DF-2898 / leaktest.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /* * Kernel-stack leak detector: N raw indirect syscalls in a loop. * usage: leaktest <mode> [count] * mode i = indirect getpid (rax=0, rdi=20) narg=0 * mode w = indirect write (rax=0, rdi=4,rsi,rdx) narg=3 * mode m = indirect mmap (rax=0, rdi=197, 7 args) narg=7 (copyin path) * mode d = DIRECT mmap (rax=197, 7 args) control * mode s = direct getpid (rax=20) control * Prints progress markers via raw write so libc never touches the path. * Exit code: 0 = survived all iterations. */ #include <stdio.h> #include <stdlib.h> #define PROD 0 static long raw_ind0(long code) { long ret; __asm__ volatile( "movl $0, %%eax\n\t" "movq %[c], %%rdi\n\t" "syscall" : "=a"(ret) : [c]"r"(code) : "rcx", "r11", "memory"); return ret; } static long raw_ind3(long code, long a1, long a2, long a3) { long ret; __asm__ volatile( "movl $0, %%eax\n\t" "movq %[c], %%rdi\n\t" "movq %[a1], %%rsi\n\t" "movq %[a2], %%rdx\n\t" "movq %[a3], %%rcx\n\t" "syscall" : "=a"(ret) : [c]"r"(code), [a1]"r"(a1), [a2]"r"(a2), [a3]"r"(a3) : "rcx", "r11", "memory"); return ret; } static long raw_ind7(long code, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { long ret; __asm__ volatile( "subq $32, %%rsp\n\t" "movq %[a6], 8(%%rsp)\n\t" "movq %[a7], 16(%%rsp)\n\t" "movq $0, (%%rsp)\n\t" "movl $0, %%eax\n\t" "movq %[c], %%rdi\n\t" "movq %[a1], %%rsi\n\t" "movq %[a2], %%rdx\n\t" "movq %[a3], %%rcx\n\t" "movq %[a4], %%r8\n\t" "movq %[a5], %%r9\n\t" "syscall\n\t" "addq $32, %%rsp" : "=a"(ret) : [c]"r"(code), [a1]"r"(a1), [a2]"r"(a2), [a3]"r"(a3), [a4]"r"(a4), [a5]"r"(a5), [a6]"r"(a6), [a7]"r"(a7) : "rcx", "r11", "memory"); return ret; } static long raw_dir7(long n, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { long ret; __asm__ volatile( "subq $32, %%rsp\n\t" "movq %[a6], 8(%%rsp)\n\t" "movq %[a7], 16(%%rsp)\n\t" "movq $0, (%%rsp)\n\t" "movq %[n], %%rax\n\t" "movq %[a1], %%rdi\n\t" "movq %[a2], %%rsi\n\t" "movq %[a3], %%rdx\n\t" "movq %[a4], %%rcx\n\t" "movq %[a5], %%r8\n\t" "movq %[a6], %%r9\n\t" "syscall\n\t" "addq $32, %%rsp" : "=a"(ret) : [n]"r"(n), [a1]"r"(a1), [a2]"r"(a2), [a3]"r"(a3), [a4]"r"(a4), [a5]"r"(a5), [a6]"r"(a6), [a7]"r"(a7) : "rcx", "r11", "memory"); return ret; } static long raw_getpid(void) { long ret; __asm__ volatile("movl $20, %%eax\n\tsyscall" : "=a"(ret) :: "rcx","r11","memory"); return ret; } static void raw_write(const char *s, int len) { __asm__ volatile( "movl $4, %%eax\n\t" "movl $1, %%edi\n\t" "syscall" :: "D"(1), "S"(s), "d"(len) : "rax","rcx","r11","memory"); } int main(int argc, char **argv) { char mode = argc > 1 ? argv[1][0] : 'i'; long n = argc > 2 ? atol(argv[2]) : 5000; char buf[64]; long i, r = 0; for (i = 0; i < n; i++) { switch (mode) { case 'i': r = raw_ind0(20); break; /* getpid */ case 'w': r = raw_ind3(4, 1, "", 0); break; /* write fd1, 0 bytes */ case 'm': r = raw_ind7(197, 0, 4096, 3, 0x1002, -1, 0, 0); break; case 'd': r = raw_dir7(197, 0, 4096, 3, 0x1002, -1, 0, 0); break; case 's': r = raw_getpid(); break; } if ((i % 64) == 0) { int l = snprintf(buf, sizeof(buf), "%c %ld\n", mode, i); raw_write(buf, l); } if (mode == 'm' || mode == 'd') { /* munmap the result to avoid exhausting the map space */ __asm__ volatile( "movl $73, %%eax\n\t" /* SYS_munmap */ "syscall" :: "D"(r), "S"(4096L) : "rax","rcx","r11","memory"); } } printf("%c survived %ld iterations (last=%ld)\n", mode, n, r); return 0; } |