DF-0243 / trigger3.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 | /* * DF-0243 trigger3 -- EXTREME-EDGE + CONCURRENCY stress (verify-mode addition). * * Goes beyond pass-1's sweep: * (a) maximal underflow delta: fname "/tmp/z" (6 chars) + interp "/bin/sh" * -> offset = 8 + 7 = 15, with argv[0] up to the copyinstr bound * (ARG_MAX-1 chars + NUL = 262144 = kern.argmax). d = length-offset ~ 262129. * (b) nonexistent-interpreter variant ("#!/a"): exec_shell_imgact's full * arithmetic + bcopy + copystr(:169) run before the ENOENT of the * interpreter is even looked up -- proves the imgact-internal path alone * cannot crash, independent of interpreter resolution. * (c) empty-env AND large-env variants (endp == begin_envv and endp >> begin_envv). * (d) loops * parallel workers: hundreds of underflow execs in flight. * * Success criterion for falsifying the finding: every child either runs the * script (exit 0) or fails execve cleanly (127); kernel never panics; dmesg * stays clean. */ #include <sys/wait.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #define SCRIPT_OK "/tmp/z" /* #!/bin/sh ; exists, prints marker */ #define SCRIPT_BAD "/tmp/zb" /* #!/a ; nonexistent interpreter */ static int one_exec(const char *path, size_t alen, char **envp, int want_code) { char *ao = malloc(alen); if (!ao) { perror("malloc"); exit(2); } memset(ao, 'A', alen - 1); ao[alen - 1] = '\0'; char *cargv[] = { ao, NULL }; pid_t pid = fork(); if (pid < 0) { perror("fork"); exit(2); } if (pid == 0) { execve(path, cargv, envp ? envp : (char **){NULL}); _exit(127); } int st = 0; if (waitpid(pid, &st, 0) < 0) { perror("waitpid"); exit(2); } free(ao); if (WIFSIGNALED(st)) { printf("!! CHILD_KILLED sig=%d\n", WTERMSIG(st)); return 1; } return WEXITSTATUS(st) == want_code ? 0 : 1; } int main(void) { const size_t big = 262144; /* argv0 string bytes incl NUL == ARG_MAX */ int rc = 0, bad = 0; size_t i; setvbuf(stdout, NULL, _IONBF, 0); printf("=== (a) max-delta single-shot: /bin/sh + /tmp/z, argv0=262144 ===\n"); for (i = 0; i < 50; i++) if (one_exec(SCRIPT_OK, big, NULL, 0)) bad++; printf("%s: 50x exec, argv0=262144 empty-env (d~262129), bad=%d\n", bad ? "FAIL" : "OK", bad); rc |= (bad != 0); bad = 0; printf("=== (b) nonexistent interp #!/a: imgact arithmetic alone ===\n"); for (i = 0; i < 50; i++) if (one_exec(SCRIPT_BAD, big, NULL, 127)) bad++; printf("%s: 50x exec, interp #!/a argv0=262144, bad=%d\n", bad ? "FAIL" : "OK", bad); rc |= (bad != 0); bad = 0; printf("=== (c) large env + max delta (argv0 sized to leave env room) ===\n"); { enum { NENV = 80 }; /* total strings must fit ARG_MAX=262144: 80 vars x ~510B + slack */ const size_t alen = 262144 - NENV * 520 - 4096; /* 215 024 */ char *envp[NENV + 1]; char v[512]; for (i = 0; i < NENV; i++) { snprintf(v, sizeof(v), "V%03zu=%0500zu", i, i); envp[i] = strdup(v); } envp[NENV] = NULL; for (i = 0; i < 50; i++) if (one_exec(SCRIPT_OK, alen, envp, 0)) bad++; for (i = 0; i < NENV; i++) free(envp[i]); } printf("%s: 50x exec, argv0=215024 + 80 env x ~510B, bad=%d\n", bad ? "FAIL" : "OK", bad); rc |= (bad != 0); bad = 0; printf("=== (d) parallel hammer: 8 workers x 75 execs, mixed lengths ===\n"); { size_t lens[5] = { 15, 256, 5000, 65536, 262144 }; int w; for (w = 0; w < 8; w++) { pid_t pid = fork(); if (pid == 0) { int devnull = open("/dev/null", O_WRONLY); if (devnull >= 0) { dup2(devnull, 1); close(devnull); } for (i = 0; i < 75; i++) one_exec(SCRIPT_OK, lens[i % 5], NULL, 0); _exit(0); } } int wst, failed = 0; while (wait(&wst) > 0) if (!WIFEXITED(wst) || WEXITSTATUS(wst) != 0) failed++; printf("%s: 8x75 parallel execs, failed_workers=%d\n", failed ? "FAIL" : "OK", failed); rc |= (failed != 0); } printf("%s\n", rc ? "TRIGGER3_FAIL" : "TRIGGER3_OK: 700 underflow execs, max delta, no crash no signal"); return rc; } |