保护模式中段选择子权限校验逻辑详解
- CPL
- RPL
- DPL
- 权限校验逻辑测试
CPL
CPL是当前进程的权限级别(Current Privilege Level),是当前正在执行的代码所在的段的特权级,存在于cs段选择子的后两位的低两位。
段选择子可见部分的数据结构如下:
举例0x001b 拆分之后就是0b0000_0000_0001_1011
就是特权级为11(3环),TI为0(GDT中),index为3(gdtr.base +0b (3 * 8))
也就是说,CPL标识了代码在不通过门调用等方式提权以外只是通过我么自己的代码所能够达到的最高的特权级别。
RPL
RPL说明的是进程对段访问的请求权限(Request Privilege Level),是对于段选择子而言的,每个段选择子有自己的RPL,它说明的是进程对段访问的请求权限。
可使用的每一个段寄存器都存在自己的rpl,在切换段寄存器中段选择子的时候会手工赋予他一个rpl
举例:下图就是通过mov的方式主动加载段选择子到es段寄存器
rpl=00也就是0环权限
因此,RPL对每个段来说不是固定的,两次访问同一段的RPL可以不同。RPL可能会削弱CPL的作用,例如当前CPL=0的进程要访问一个数据段,它把段选择符中的RPL设为3,这样虽然它对该段仍然只有特权为3的访问权限。
DPL
DPL存储在段描述符中,规定访问该段的权限级别(Descriptor Privilege Level),每个段的DPL固定。当进程访问一个段时,需要进程特权级检查,一般要求DPL >= max {CPL, RPL},即级别至少要相同才能通过检查。
举例:下图是我从win7_x86环境下的虚拟机中copy出来的gdt表
第一个全0是cpu要求第一个gdtentry必须为null
我们看第二个00cf9b00`0000ffff
dpl存在9的位置,9拆分之后是1001
00为dpl也就是0环权限
第四个gdtEntry是00cffb00`0000ffff
dpl存在f的位置,拆分是1111
11就是dpl,3环权限
权限校验逻辑测试
现在我们来验证一下,DPL >= max {CPL, RPL}条件成立才能成功切换段选择子的这个结论
首先我们来构造四个段选择子
1:0b0000_0000_0000_1000=0x0008
2: 0b0000_0000_0000_1011=0x000b
3: 0b0000_0000_0001_1000=0x0018
4: 0b0000_0000_0001_1011=0x001b
1是index=1然后rpl=0
2是index=1然后rpl=0
3是index=1然后rpl=0
4是index=1然后rpl=0
然后我们依次执行如下代码
xor eax, eax
mov ax, [这里写我们刚刚构造的段选择子]
mov es, ax
执行1
执行2
执行3
执行4
结论:
最终根据执行结果可以看到当DPL >= max {CPL, RPL}的时候我们是可以成功切换段选择子的反之则会报错