DF-2898 / sysent_edge.c
/* * Behavioral spot-check of the native sysent[] table edge cases: * 1. syscall numbers >= SYS_MAXSYSCALL (556) and just below it -> SIGSYS path, no OOB * 2. lkmnosys slot 210 -> SIGSYS, slot 219 -> SIGSYS * 3. obsolete slot 11 -> SIGSYS * 4. mmap (7-arg syscall: exercises the narg>regcnt=6 stack-arg copyin) * 5. mmap via indirect syscall(197,...) (exercises sys_xsyscall regcnt=5 path + copyin of 2 stack args) * 6. lseek 64-bit result (rsize=8) returns full 64-bit offset * 7. getrandom (rsize=8) sanity * Build: cc -o sysent_edge sysent_edge.c */ #include <sys/syscall.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <errno.h> static int sigsys_count; static void onsig(int s __unused) { sigsys_count++; _exit(77); } 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(void) { signal(SIGSYS, onsig); int fail = 0; /* 1. out-of-range syscall numbers must not crash the kernel */ printf("[1] OOR syscalls: "); fflush(stdout); pid_t p = fork(); if (p == 0) { sc(556,0,0,0,0,0,0,0); _exit(1); } int st; waitpid(p, &st, 0); printf("556->%s ", WIFSIGNALED(st) ? "SIGSYS" : "exit"); p = fork(); if (p == 0) { sc(0x7fffffff,0,0,0,0,0,0,0); _exit(1); } waitpid(p, &st, 0); printf("INT_MAX->%s ", WIFSIGNALED(st) ? "SIGSYS" : "exit"); p = fork(); if (p == 0) { sc(555,0,0,0,0,0,0,0); } /* futimesat: EINVAL via args, NOT SIGSYS-by-table */ waitpid(p, &st, 0); printf("555->%s\n", WIFSIGNALED(st) ? "SIGSYS" : "no-signal"); /* 2./3. lkm + obsolete slots -> SIGSYS */ p = fork(); if (p == 0) { sc(210,0,0,0,0,0,0,0); _exit(1); } waitpid(p, &st, 0); printf("[2] lkmnosys 210 -> %s\n", WIFSIGNALED(st) ? "SIGSYS" : "no-signal"); p = fork(); if (p == 0) { sc(11,0,0,0,0,0,0,0); _exit(1); } waitpid(p, &st, 0); printf("[3] obsolete 11 -> %s\n", WIFSIGNALED(st) ? "SIGSYS" : "no-signal"); /* 4. direct 7-arg mmap */ void *m = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("[4] direct mmap = %p\n", m); if (m == MAP_FAILED) fail++; /* 5. indirect mmap via syscall(197,...): code in rdi, 6 args in rsi.., last from stack */ long im = sc(SYS_syscall, 197, 0, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("[5] indirect mmap = 0x%lx\n", (unsigned long)im); if (im == -1) fail++; /* 5b. indirect __syscall(198,...) variant */ long im2 = sc(SYS___syscall, 197, 0, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("[5b] indirect __syscall mmap = 0x%lx\n", (unsigned long)im2); if (im2 == -1) fail++; /* 6. lseek 64-bit result across the 2^32 boundary */ int fd = open("/tmp/sysent_edge.tmp", O_RDWR|O_CREAT, 0600); if (fd >= 0) { off_t r = lseek(fd, 0x100000000LL, SEEK_SET); printf("[6] lseek(4GiB) = %lld (errno path %d)\n", (long long)r, errno); if (r < 0) fail++; close(fd); unlink("/tmp/sysent_edge.tmp"); } /* 7. getrandom rsize=8 */ unsigned char rb[8]; long gr = syscall(SYS_getrandom, rb, 8, 0); printf("[7] getrandom = %ld\n", gr); if (gr != 8) fail++; printf(fail ? "RESULT: FAIL(%d)\n" : "RESULT: PASS\n", fail); return fail ? 1 : 0; } |