利用LDT(本地描述符表)
我试图使用除默认代码和数据用户和内核段之外的不同段进行一些实验。 我希望通过使用本地描述符表和modify_ldt系统调用来实现这一点。 通过系统调用,我在LDT中创建了一个新条目,它是一个段描述符,其基地址是我要“隔离”的全局变量,限制为4个字节。
我尝试通过C程序中的内联汇编将数据段寄存器与我的自定义LDT条目的段选择器一起加载,但是当我尝试访问变量时,我收到了分段错误。
我的怀疑是我的全局变量的偏移存在问题,并且在计算地址时,它超出了我的自定义段的限制,因此导致seg错误。
有谁知道这种情况的工作?
哦,顺便说一句,这是在Linux上的x86架构上。 这是我第一次在论坛上提出这样的问题,所以如果有任何其他信息可以certificate是有用的,请告诉我。
先感谢您。
编辑:我意识到我可能应该包含源代码:)
struct user_desc* table_entry_ptr = NULL; /* Allocates memory for a user_desc struct */ table_entry_ptr = (struct user_desc*)malloc(sizeof(struct user_desc)); /* Fills the user_desc struct which represents the segment for mx */ table_entry_ptr->entry_number = 0; table_entry_ptr->base_addr = ((unsigned long)&mx); table_entry_ptr->limit = 0x4; table_entry_ptr->seg_32bit = 0x1; table_entry_ptr->contents = 0x0; table_entry_ptr->read_exec_only = 0x0; table_entry_ptr->limit_in_pages = 0x0; table_entry_ptr->seg_not_present = 0x0; table_entry_ptr->useable = 0x1; /* Writes a user_desc struct to the ldt */ num_bytes = syscall( __NR_modify_ldt, LDT_WRITE, // 1 table_entry_ptr, sizeof(struct user_desc) ); asm("pushl %eax"); asm("movl $0x7, %eax"); /* 0111: 0-Index 1-Using the LDT table 11-RPL of 3 */ asm("movl %eax, %ds"); asm("popl %eax"); mx = 0x407CAFE;
seg故障发生在最后一条指令处。
我只能猜测,因为我没有可用的assembly。
我猜你得到段错误的行编译成如下:
mov ds:[offset mx], 0x407cafe
其中offset mx
是程序数据段中offset mx
的偏移量(如果它是静态变量)或堆栈中的偏移量(如果它是自动变量)。 无论哪种方式,这个偏移量都是在编译时计算的,无论DS
指向什么,都将使用该偏移量。
现在你在这里做的是创建一个新的段,其基址是mx
的地址,其限制是0x4
或0x4fff
(取决于你没有指定的G-bit
)。
如果G-bit
为0,则限制为0x4
,并且由于mx
位于原始DS
地址0x0
和0x4
之间的可能性非常小,因此当您访问新段内的mx
偏移时,您将超过限制。
如果G-bit
为1,则限制为0x4fff
。 现在只有当原始mx
位于0x4fff
之上时0x4fff
段0x4fff
。
考虑到新段的基数是mx
,您可以通过执行以下操作来访问mx
:
mov ds:[0], 0x407cafe
不过,我不知道如何在C中写这个。