Unbounded queue-number index into sense_buffers[] heap OOB read / kernel heap info leak
Summary
adv_done indexes adv->sense_buffers[q_no-1] using queue number read directly from firmware LRAM via adv_copy_lram_doneq with no validation q_no in [1 max_openings]. sense_buffers allocated for exactly max_openings entries. q_no of 0 (underflows to 0xFFFFFFFF since u_int) or q_no > max_openings (firmware queue space extends ADV_MAX_QNO=0xF8=248 while max_openings may be 16) causes OOB heap read structure-copied into CCB auto-sense buffer returned to userland via CAM_AUTOSNS_VALID. Impact: kernel heap memory disclosure up to few KB per request when q_no > max_openings or immediate panic when q_no==0. Requires control of AdvanSys HBA LRAM. [VERIFIED pass2: reproduced - q_no 25 struct-copies sense_buffers 24 OOB into autosense, q_no 0 wraps to 128GB span index; zeros in-capture so no contentful leak captured; bound fix authored]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2412 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 345 B | β raw | |
| VERDICT.md | β | 1.4 KB | β raw | |
| build.sh | β | 93 B | view raw | |
| dfadv24.c | β | 46.2 KB | view raw | |
| env.txt | β | 254 B | view raw | |
| fix.diff | β | 517 B | view raw | |
| manifest.json | β | 734 B | view raw | |
| primeadv.sh | β | 663 B | view raw | |
| run.log | β | 1.0 KB | view raw | |
| run.sh | β | 147 B | view raw | |
| verdict.json | β | 2.0 KB | view raw |
DF-2412 -- evidence pack
Verdict: reproduced (reproduced=1, impact=none, confidence=likely)
Build: see build.sh (df43xx_rig.ko extension)
Run: sh primeadv.sh; sysctl kern.df43xx.go=12; sysctl kern.df43xx.go=13
See VERDICT.md for the full narrative, run.log/panic.txt for the decisive output, fix.diff for the post-verification fix.
DF-2412 VERDICT
Status: reproduced Impact: none Confidence: likely
Firmware-controlled q_no indexes adv->sense_buffers[q_no-1] with no bound: production adv_intr completed a CHECK_COND entry naming q_no=25 over a 16-entry array, copying the struct at sense_buffers+768 (OOB by construction) into ccb->csio.sense_data with CAM_AUTOSNS_VALID set (kernel heap disclosure window into pass(4)-readable sense data); the q_no=0 variant reads at sense_buffers + 0x1FFFFFFE0 (u_int wrap), also survived and copied 32 zero bytes from that distant KVA. Captured contents were zeros on this heap state both times, so no secret bytes were disclosed in the capture, but the OOB read is mechanically proven (index 24 of a 16-element array; AUTOSNS=1).
Kernel references
Guest
DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
Notes
requires control of the AdvanSys HBA LRAM (hostile/compromised card or VM passthrough), hence Low
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
not_testableConfirmed kernel references
Detail
Exploit chain
HBA LRAM/firmware controls q_no -> sense_buffers[q_no-1] struct-copied into user-visible sense data: kernel heap read window up to a 128GB span at 32-byte granularity
Evidence (decisive lines)
run.log (AUTOSNS=1 dumps for q_no=25 and q_no=0)
PoC changes
df43xx rig (DF-4349 harness) extended with a status-parameterized done-queue entry and the two q_no scenarios; production adv_intr dispatched over fabricated post-attach state
Verified recommended fix
validate q_no in adv_done/adv_run_doneq: if (q_no == 0 || q_no > adv->max_openings) drop the completion
Verdict
Firmware-controlled q_no indexes adv->sense_buffers[q_no-1] with no bound: production adv_intr completed a CHECK_COND entry naming q_no=25 over a 16-entry array, copying the struct at sense_buffers+768 (OOB by construction) into ccb->csio.sense_data with CAM_AUTOSNS_VALID set (kernel heap disclosure window into pass(4)-readable sense data); the q_no=0 variant reads at sense_buffers + 0x1FFFFFFE0 (u_int wrap), also survived and copied 32 zero bytes from that distant KVA. Captured contents were zeros on this heap state both times, so no secret bytes were disclosed in the capture, but the OOB read is mechanically proven (index 24 of a 16-element array; AUTOSNS=1).
No comments yet.