我知道操作系统限制了对内核代码的访问;通过使用分割和特权级别来处理数据。然而,如果以下代码成功执行,用户可以更改段寄存器值,并且我们似乎可以访问内核数据:
mov eax, 0x10
mov es, ax #point selector to the item 2 in GDT with RPL 0, which is the data segment
les bx, [0]
所以我想知道是什么机制阻止了这个代码的成功执行?
mov es, ax
指令将由于当前特权级别(CPL(大于描述符的特权级别(DPL(而导致常规保护(#GP(故障,或者由于请求的特权级别在数字上不高于DPL而被忽略。在您的示例中,由于它是在用户模式下运行的,因此CPL为3。这意味着描述符的DPL也必须是3,否则指令将出错。如果DPL是3,那么就不会有故障,但RPL实际上被忽略了,因为它不能高于DPL。
(请注意,只有在加载段寄存器时才会执行段特权级别检查,因此只有mov es, ax
指令才会因此而崩溃。(
"英特尔软件开发人员手册"中MOV指令的文档说明了加载段寄存器时,MOV指令何时会导致#GP故障:
IF DS, ES, FS, or GS is loaded with non-NULL selector THEN IF segment selector index is outside descriptor table limits or segment is not a data or readable code segment or ((segment is a data or nonconforming code segment) or ((RPL > DPL) and (CPL > DPL)) THEN #GP(selector); FI; IF segment not marked present THEN #NP(selector); ELSE SegmentRegister ← segment selector; SegmentRegister ← segment descriptor; FI; FI;
正在使用的DPL和RPL中最高的行为记录在Intel SDM第3卷"5.5特权级别":中
- 请求的权限级别(RPL(--[…]即使请求访问段的程序或任务如果RPL没有足够的特权级别,则拒绝访问。也就是说,如果段选择器的RPL在数值上大于CPL,则RPL将覆盖CPL,反之亦然。[…]
选择器的RPL字段只允许将有效特权级别增加到比DPL更高或更低的数字特权级别。如果将其设置为数值较低的级别,则不会产生任何效果。
换句话说,如果选择器0x10引用内核模式数据段(DPL=0(,则代码将崩溃。如果选择器0x10是用户模式数据段(DPL=3(,则其处理方式与使用0x13(RPL=3(时相同。
请注意,在实践中,这并不重要,因为所有现代操作系统都使用平面段模型,因为每个段的基数都为0,并且可以访问整个线性地址空间。用户模式代码实际上并没有通过段检查来访问内核代码和数据,而是通过页面保护来访问。这些仅使用CPL来确定是否应授予对管理模式(内核(页面的访问权限。
在受保护和64位模式下,mov Sreg, reg
与#GP(selector)
故障,如果:
- 如果段选择器索引超出描述符表限制
- 如果正在加载DS、ES、FS或GS寄存器,并且指向的段是数据段或非一致代码段,则并且RPL或CPL大于DPL
但是操作系统控制GDT的内容,GDT条目有一个描述符特权级别字段,甚至需要该字段才能将其加载到段reg中(https://wiki.osdev.org/Global_Descriptor_Table)操作系统可能会使某些GDT条目无法用于用户空间
(此外,由于类似的检查,环3用户空间不能直接跳转到环0代码段。(
如果GDT位于用户空间没有写入权限的内存中,则操作系统可以保持控制。(当然,LDT也是如此(。一些操作系统,例如Linux,具有modify_ldt
系统调用,特权用户空间可以使用该调用来要求操作系统设置LDT条目。
由于大多数操作系统使用平面内存模型(base=0 limit=-1(并通过分页进行内存保护,因此没有必要阻止用户空间按照自己的意愿配置数据段。(seg:off to linear发生在virt->phys之前。即,如果启用了分页,则线性地址是虚拟的。(
但单独的分段确实为操作系统提供了一种机制,可以阻止无特权的ring3用户空间使用任意条目。
请注意,您的序列不使用新修改的ES寄存器,而是覆盖它https://www.felixcloutier.com/x86/lds:les:lfs:lgs:lss
les bx, [0] # Load a seg:off from memory at DS:0 into ES:BX
也许您想要mov bx, [es:0]