OS&Assembly:是什么阻止用户模式将选择器设置为任意值?

我知道操作系统通过使用分段和特权级别来限制对内核代码和数据的访问。但是,用户可以更改段寄存器的值,并且如果以下代码成功执行,我们似乎可以访问内核数据:

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]

所以我想知道阻止该代码成功执行的机制是什么?

whqjj19860309 回答:OS&Assembly:是什么阻止用户模式将选择器设置为任意值?

mov es,ax指令将由于当前特权级别(CPL)大于描述符的特权级别(DPL)而导致一般保护(#GP)错误,或者将忽略请求的特权级别(RPL)因为它在数值上不高于DPL。在您的示例中,由于它在用户模式下运行,因此CPL为3。这意味着描述符的DPL也必须为3,否则指令将出错。如果DPL为3,那么就不会有错误,但是RPL实际上不会被忽略,因为它不能高于DPL。

(请注意,只有在加载段寄存器时才执行段特权级别检查,因此只有mov es,ax指令会因为它们而崩溃。)

《英特尔软件开发人员手册》中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行为记录在英特尔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条目无法用于用户空间。

(此外,由于类似的检查,ring 3用户空间不能仅跳到ring-0代码段。)

如果GDT在用户空间没有写权限的内存中,则OS可以保持控制权。 (当然,与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]

本文链接:https://www.f2er.com/3161872.html

大家都在问