DF-3961 / trigger.c
/* * DF-3961 trigger sketch - hptiop.c SG-capacity heap overflow * ============================================================ * Sink: hptiop_post_req_itl/mv/mvfrey write nsegs scatter-gather entries * into ((struct hpt_iop_request_scsi_command *)srb)->sg_list, * i.e. into the fixed 600-byte srb->req[] buffer (hptiop.h:42,452). * Capacity: offsetof(sg_list)=48; (600-48)/16 = 34 entries. * Entry k writes bytes [48+16k, 48+16k+16): * k=34 -> [592,608) overwrites srb->hba (offset 600) * k=35 -> [608,624) overwrites srb->ccb, srb->next * k=36 -> [624,640) overwrites srb->dma_map, srb->phy_addr * k=37 -> [640,656) overwrites srb->srb_flag, srb->index * k>=39 -> walks into the NEXT srb (stride HPT_SRB_MAX_SIZE=672) * Bound: the ONLY gate is hptiop_post_scsi_command(): * if (error || nsegs > hba->max_sg_count) // hptiop.c:2660 * with hba->max_sg_count taken verbatim from the HBA firmware * get_config reply (hptiop.c:1933). No check against the 34-entry * capacity, and io_dmat is created with nsegments=max_sg_count * (hptiop.c:1952), so the DMA layer will happily produce that many. * * Precondition (both required): * 1. HBA firmware reports max_sg_count >= 35 in the get_config reply * (device-fed; a compromised/misbehaving HBA or DMA attacker controls it; * what stock RR3xxx/4xxx firmware reports is undocumented). * 2. A CAM initiator supplies a CCB yielding >= 35 segments: * - bus_dmamap_load path is capped by MAXPHYS=128K on x86_64 * (scsi_da.c:1248 pins si_iosize_max=MAXPHYS) -> max ~34 segments, * JUST under the limit, so plain disk I/O does not overflow; * - the CAM_SCATTER_VALID path (hptiop.c:2329-2342) passes * ccb->csio.sglist_cnt straight through as nsegs - no in-tree * initiator sets it on this system, but any kernel component * (or future/out-of-tree periph) that does can supply 35+. * * Values written per entry (hptiop.c:2475-2479): * psg->pci_address = (u64)segs[idx].ds_addr - physical address of the * I/O buffer pages (semi-controlled by the originator) * psg->size = segs[idx].ds_len - attacker-chosen length * psg->eot = 0 * Corrupted srb->ccb then reaches `ccb = (union ccb *)srb->ccb` and * xpt_done(ccb) in the completion callbacks -> wild kernel pointer. * * This PoC cannot run on the audit guest (no HighPoint HBA, see env.txt). * On hardware, the minimal trigger is: * - emulate/reflash an RR44xx so get_config returns max_sg_count=64, then * - issue one CCB with 35+ scatter segments to any hptiop target, e.g. * via a small kernel module calling xpt_action with a hand-built csio * (CAM_SCATTER_VALID|CAM_SG_LIST_PHYS), or * - dd if=/dev/daX of=/dev/null bs=1m on a kernel whose MAXPHYS exceeds * 136 KB (34 * 4K), which yields >= 35 segments from the load path. */ int main(void) { return 0; } /* informational sketch - see VERDICT.md */ |