DF-5463 / to5463.c
/* * to5463 -- DF-5463: PTIOCSETTIMEOUT signed multiply overflow. * * ptioctl() stores softc->io_timeout = *(int *)addr * 1000 * (sys/bus/cam/scsi/scsi_pt.c:654). For values > 2147483 the int * multiply overflows and io_timeout goes NEGATIVE (UB); the negative * value is then consumed as a u_int32_t CDB timeout in ptstart(). * PTIOCGETTIMEOUT maps any io_timeout < 1000 to 0, so the wrap is * directly observable from userland. */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/ptio.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/pt0"; int fd, t, r = 0; fd = open(dev, O_RDWR); if (fd < 0) { perror(dev); return (2); } t = 100000; /* sanity: in-range */ if (ioctl(fd, PTIOCSETTIMEOUT, &t) != 0) { perror("SETTIMEOUT(100000)"); r = 2; } t = -1; ioctl(fd, PTIOCGETTIMEOUT, &t); printf("set=100000 -> get=%d (expect 100000)\n", t); if (t != 100000) r |= 1; t = 2147483; /* INT_MAX/1000: still fine */ ioctl(fd, PTIOCSETTIMEOUT, &t); t = -1; ioctl(fd, PTIOCGETTIMEOUT, &t); printf("set=2147483 -> get=%d (expect 2147483)\n", t); if (t != 2147483) r |= 1; t = 2147484; /* 2147484*1000 > INT_MAX: wraps */ ioctl(fd, PTIOCSETTIMEOUT, &t); t = -1; ioctl(fd, PTIOCGETTIMEOUT, &t); printf("set=2147484 -> get=%d (expect 2147484; 0 == OVERFLOWED " "to negative)\n", t); if (t == 0) printf("OVERFLOW-MANIFEST: io_timeout wrapped negative\n"); close(fd); return (r); } |