1 CPL/DPL/RPL
- DPL(Descriptor Privilege Level)
指GDT或LDT描述符中的DPL字段,根据段的类型不同其处理规则而异:- 数据段:指定了访问该数据段的最低特权级(如DPL为1的数据段,只有特权级 0 和 1 下才能访问。
- 非一致代码段:规定了只有在特权级等于 DPL 时才能访问。
- 一致代码段和通过调用门访问非一致代码段:规定只有在特权级等于或高于 DPL的情况下才能访问
- TSS 段:规定了访问此段的最低特权级,与数据段一致。
- CPL(current privilege level)
指当前执行任务或程序代码段寄存器(CS)或堆栈寄存器(SS)中第 0 位和第 1 位的值。此一般等于程序和任务的代码所在段的 DPL。注意:当跨特权级访问一致代码段时,此时CPL与访问者一致,不会与此一直代码段DPL相等。
- RPL(Requested privilege Level)
指程序或任务所在段所对应的选择子的第0位和第 1 位所代表的值。处理器比较 RPL 和 CPL 来判断是否为一个合法访问,即选择 CPL 与 RPL 较大的值来判定是否有权执行某一访问动作。RPL可以很好的限制用户态程序对于内核态内存的访问。用户态程序执行系统调用或中断等转移到内核态执行时,在内核态执行时的RPL由调用者使用的选择子来决定,从而保证了用户态执行时的 RPL 仍然是用户态权限,所能访问的内存仍仅限于用户态内存。
2 不同特权级代码段之间的转移
特权级是以段为单元来划分的,故特权级的转移必然伴随着代码段之间的跳转。程序从一个代码段跳转到另外一个代码段之前,目标代码段的选择子会加载到 cs 中。但是在加载的过程中,系统会根据当前现状进行特权级、类型、代码段界限等进行检查,若检查通过,则进行跳转。
程序控制权的转移可通过指令 jmp、call、int, ret, sysenter、sysexit、iret等,也可由硬中断和异常引起。
使用jmp 和call 实现以下 4 种转移:
- 目标操作数包含目标代码段的选择子
- 目标操作数指向一个包含目标代码段选择子的调用门描述符
- 目标操作数指向一个包含目标代码段选择子的TSS
- 目标操作数指向一个任务门,这个任务门指向一个包含目标代码段选择子的TSS
2.1 通过jmp 或 call 进行直接转移
- 如果目标是非一致代码段,要求CPL必须等于目标段的DPL,同时要求RPL小于等于DPL。
- 如果目标是一致代码段,则要求CPL大于或等于目标段的DPL,RPL此时不做检查。当转移到一致代码段后,CPL会被延续下来,而不会变成目标代码段的DPL。
2.2 call调用时的堆栈变化
- 短调用时的堆栈变化
call时:
ret时:
- 同特权级段间跳转
call:
ret:
- 不同特权级段间跳转
call:
ret: