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;
2条答案
按热度按时间0lvr5msh1#
mov es, ax
指令将导致一般保护(#GP)错误,因为当前特权级别(CPL)大于描述符的特权级别(DPL),或者请求的特权级别(RPL)将被忽略,因为它的数值不高于DPL。在您的示例中,由于它在用户模式下运行,CPL是3。这意味着描述符的DPL也必须是3,否则指令将出错。如果DPL是3,那么将不会有错误,但是RPL被有效地忽略,因为它不能高于DPL。(Note段特权级别检查仅在加载段寄存器时执行,因此只有
mov es, ax
指令会因此而崩溃。)英特尔软件开发人员手册中MOV指令的文档说明了在加载段寄存器时,MOV指令何时会导致#GP故障:
字符串
所使用的最高DPL和RPL的行为记录在英特尔SDM第3卷“5.5特权级别”中:
选择器的RPL字段只允许将有效权限级别增加到比DPL更高或更低的数字级别。如果您将其设置为较低的数字级别,则无效。
换句话说,如果选择器0x 10引用内核模式数据段(DPL = 0),那么代码将崩溃。如果选择器0x 10是用户模式数据段(DPL = 3),则处理方式与使用0x 13(RPL = 3)相同。
请注意,实际上这并不重要,因为所有现代操作系统都使用扁平段模型,每个段都以0为基数,可以访问整个线性地址空间。用户模式代码实际上并没有通过段检查来限制访问内核代码和数据,而是通过页面保护来限制访问。这些只使用CPL来确定是否应该授予管理员模式(内核)页面的访问权。
kognpnkq2#
在保护模式和64位模式下,如果出现以下情况,
mov Sreg, reg
将与#GP(selector)
一起出错:但是操作系统控制着GDT的内容,GDT条目有一个复制者权限级别字段,甚至需要将其加载到段寄存器中(https://wiki.osdev.org/Global_Descriptor_Table)。操作系统可以使一些GDT条目无法用于用户空间。
(Also由于类似的检查,环3用户空间不能仅仅远跳到环0代码段。
如果GDT在用户空间没有写权限的内存中,操作系统可以保持控制。(当然LDT也是如此)。一些操作系统,例如Linux,有一个
modify_ldt
系统调用,特权用户空间可以使用它来要求操作系统设置LDT条目。由于大多数操作系统使用平面内存模型(base=0 limit=-1)并通过分页进行内存保护,因此无需阻止用户空间配置数据段(seg:off to linear发生在virt->phys.之前,即如果启用分页,则线性地址是虚拟的)。
但是分段本身确实为操作系统提供了一种给予机制来阻止非特权的ring 3用户空间使用任意条目。
还要注意,你的序列并没有使用新修改的ES寄存器,而是覆盖了它。
字符串
也许你想要
mov bx, [es:0]