Unclamped sense_len overflows 32-byte inline sense_data buffer on CHECK CONDITION
Summary
On SCSI CHECK CONDITION vpo_intr issues REQUEST_SENSE using csio->sense_len (u_int8_t 0..255) as byte-transfer bound and &csio->sense_data as destination but csio->sense_data is fixed 32-byte struct scsi_sense_data. Low-level loops write up to blen bytes into buffer. sense_len>32 overflows sense_data into adjacent csio fields (cdb_len sglist_cnt scsi_status sense_resid resid cdb_io msg_ptr). csio->sense_len reachable at arbitrary value via CAM pass-through xpt_merge_ccb copies wholesale no validation. Local privileged attacker root/operator /dev/passN. Bounded CCB corruption not arbitrary write. [PASS-2 NOTE: DF-2530/DF-2531 are the sense/cdb halves of DF-1958 - one unclamped-length root; fold on triage] [VERIFIED pass2: reproduced - sense_len 255 written into 32-byte sense_data destroys CCB markers cdb_len sglist_cnt scsi_status with 223 bytes past the field; clamp fix A/B clean]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2530 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 967 B | β raw | |
| VERDICT.md | β | 2.1 KB | β raw | |
| build.sh | β | 99 B | view raw | |
| run.log | β | 460 B | view raw | |
| env.txt | β | 963 B | view raw | |
| fix.diff | β | 548 B | view raw | |
| manifest.json | β | 687 B | view raw | |
| verdict.json | β | 2.4 KB | view raw |
DF-2530 -- Unclamped sense_len overflows the 32-byte sense_data on CHECK CONDITION
Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_vpo (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.
Build
sh build.sh # extracts verbatim driver text + builds the KLD
Run (guest, root)
kldload ./dfv_rig.ko
kldload dfv_vpo.ko; sysctl kern.dfv_vpo_run=1; sysctl -n kern.dfv_vpo_status
Expected
run.log: 255 bytes written, markers destroyed; control 32/intact; fixed-caller model intact.
Fix validation
fix.diff clamps the REQUEST_SENSE length to sizeof(csio->sense_data) in vpo_intr before the call; A/B clean.
Verdict: reproduced / impact=limited_write (see verdict.json, VERDICT.md)
DF-2530 verdict -- Unclamped sense_len overflows the 32-byte sense_data on CHECK CONDITION
status: reproduced reproduced: 1 impact: limited_write confidence: certain attempts: 2 runtime_sec: 700
vpo_intr hands csio->sense_len (user CCB byte, 0..255 via pass(4) xpt_merge_ccb) and &csio->sense_data (32 bytes) to the transfer engine; the verbatim imm_do_scsi wrote 255 bytes (count=255) into the 32-byte field - the rig dump shows sense bytes 28..39 all 0x5A and the post-CCB markers destroyed: cdb_len=0x5a sglist_cnt=0x5a5a scsi_status=0x5a sense_resid=0x5a resid=0x5a5a5a5a (pre-set markers 11/22/33/44/55) - 223 bytes past the field into the rest of union ccb, exactly the field list in the finding. Control (sense_len=32) leaves the markers intact. This is the same unclamped-length class as DF-2522 (trm), which this project already reproduced with the production handler. Fixed-caller model (vpo.c clamps to sizeof sense_data before the call) A/B: 32 bytes written, markers intact.
Evidence (decisive lines)
DF2530[sense_len=255]: sizeof(sense_data)=32; verbatim transfer wrote count=255 bytes DF2530: sense bytes 28..39: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a DF2530: post-CCB: cdb_len=0x5a sglist_cnt=0x5a5a scsi_status=0x5a sense_resid=0x5a resid=0x5a5a5a5a (markers 11/22/33/44/55) DF2530: RESULT=OVERFLOW (sense_len>32 written into the rest of the CCB) --- control (sense_len=32) --- markers intact, clean --- fixed-caller model (clamp 32) --- markers intact, clean
Exploit chain / privesc assessment
local privileged (root/operator via pass(4) on the vpo bus, plus physical parallel-port device); bounded CCB corruption, not arbitrary write.
Fix + A/B
fix.diff clamps the REQUEST_SENSE length to sizeof(csio->sense_data) in vpo_intr before the call; A/B clean.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedConfirmed kernel references
Detail
Exploit chain
local privileged (root/operator via pass(4) on the vpo bus, plus physical parallel-port device); bounded CCB corruption, not arbitrary write.
Evidence (decisive lines)
run.log: 255 bytes written, markers destroyed; control 32/intact; fixed-caller model intact.
PoC changes
same transport rig as DF-2529; fixed-caller A/B models the clamped call the patched vpo.c makes.
Verified recommended fix
clamp the REQUEST_SENSE length to sizeof sense_data
Verdict
vpo_intr hands csio->sense_len (user CCB byte, 0..255 via pass(4) xpt_merge_ccb) and &csio->sense_data (32 bytes) to the transfer engine; the verbatim imm_do_scsi wrote 255 bytes (count=255) into the 32-byte field - the rig dump shows sense bytes 28..39 all 0x5A and the post-CCB markers destroyed: cdb_len=0x5a sglist_cnt=0x5a5a scsi_status=0x5a sense_resid=0x5a resid=0x5a5a5a5a (pre-set markers 11/22/33/44/55) - 223 bytes past the field into the rest of union ccb, exactly the field list in the finding. Control (sense_len=32) leaves the markers intact. This is the same unclamped-length class as DF-2522 (trm), which this project already reproduced with the production handler. Fixed-caller model (vpo.c clamps to sizeof sense_data before the call) A/B: 32 bytes written, markers intact.
No comments yet.