Nevertheless, I'm wondering which address space is considered. Ring 3 (user-land) programs are perfectly allowed to modify some segment selectors (ES for example). This modification should trigger the processor to load segment descriptor from corresponding entry in the GDT which base address is computed using the linear address given by the GDTR register.
Because linear address are subject to paging, I understand from Intel manuals, that segment descriptor loads go through the memory paging of current process. Because Linux certainly doesn't want to expose the GDT structure to user-land programs, I thought that it somehow managed to introduce a hole in the address space of user-land processes; preventing these processes to read the GDT, while allowing the processor to read it for segment reloads.
I checked by using the following code which showed I'm completely wrong about the GDTR's base linear address.
Code: Select all
int
main()
{
struct
{
uint16_t pad;
uint16_t size;
uintptr_t base;
} gdt_info;
__asm__ volatile ("sgdt %0" : "=m" (gdt_info.size) );
void* try_mmgdt = (void*)( gdt_info.base & ~0xfff );
void* chk_mmgdt = mmap(try_mmgdt, 0x4000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
std::cout << "gdt size: \t" << std::dec << gdt_info.size << std::endl;
std::cout << "gdt base: \t" << std::hex << gdt_info.base << std::endl;
std::cout << "mmgdt try:\t" << std::hex << uintptr_t(try_mmgdt) << std::endl;
std::cout << "mmgdt chk:\t" << std::hex << uintptr_t(chk_mmgdt) << std::endl;
return 0;
}
Code: Select all
gdt size: 127
gdt base: 1dd89000
mmgdt try: 1dd89000
mmgdt chk: 1dd89000
So my question finally is: which Intel/linux mechanism makes the linear address of the GDTR and the linear address of the current process point to different memory region ?