DF-2898 / sysent_stage.c
/* * Stage-driven bisect of the sysent[] edge-case crash. * usage: sysent_stage <stage> * 1 = OOR syscall 556 (in child) * 2 = OOR 0x7fffffff (in child) * 3 = lkm slot 210 (in child) * 4 = direct 7-arg mmap * 5 = indirect mmap syscall(0, 197, ...) 8 total args * 6 = indirect mmap __syscall(198, 197, ...) * 7 = lseek 4GiB (rsize=8) * 8 = getrandom (rsize=8) */ #include <sys/syscall.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> static long sc(long n, long a, long b, long c, long d, long e, long f, long g) { return syscall(n, a, b, c, d, e, f, g); } int main(int argc, char **argv) { int stage = argc > 1 ? atoi(argv[1]) : 0; pid_t p; int st; switch (stage) { case 1: p = fork(); if (p == 0) { sc(556,0,0,0,0,0,0,0); _exit(1); } waitpid(p, &st, 0); printf("[1] 556 -> %s\n", WIFSIGNALED(st) ? "signaled" : "exit"); break; case 2: p = fork(); if (p == 0) { sc(0x7fffffff,0,0,0,0,0,0,0); _exit(1); } waitpid(p, &st, 0); printf("[2] INT_MAX -> %s\n", WIFSIGNALED(st) ? "signaled" : "exit"); break; case 3: p = fork(); if (p == 0) { sc(210,0,0,0,0,0,0,0); _exit(1); } waitpid(p, &st, 0); printf("[3] lkm 210 -> %s\n", WIFSIGNALED(st) ? "signaled" : "exit"); break; case 4: { void *m = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("[4] direct mmap = %p\n", m); break; } case 5: { long im = sc(SYS_syscall, 197, 0, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("[5] indirect mmap(syscall) = 0x%lx\n", (unsigned long)im); break; } case 6: { long im = sc(SYS___syscall, 197, 0, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("[6] indirect mmap(__syscall) = 0x%lx\n", (unsigned long)im); break; } case 7: { int fd = open("/tmp/stage.tmp", O_RDWR|O_CREAT, 0600); off_t r = lseek(fd, 0x100000000LL, SEEK_SET); printf("[7] lseek = %lld\n", (long long)r); close(fd); unlink("/tmp/stage.tmp"); break; } case 8: { unsigned char rb[8]; long gr = syscall(SYS_getrandom, rb, 8, 0); printf("[8] getrandom = %ld\n", gr); break; } default: printf("unknown stage\n"); return 2; } return 0; } |