Signed int len assigned from u_int32_t dxfer_len signedness overflow in INQUIRY bzero and odd-length kmalloc/bcopy
Summary
atapi_action declares int len and assigns len=csio->dxfer_len (u_int32_t). For dxfer_len>INT_MAX len becomes negative. INQUIRY special-case bzero(buf len) sign-extends to huge size_t catastrophic overwrite. Odd-length READ path kmalloc(++len) wraps to 0 completion bcopy uses original huge value against tiny kmalloc(0) slab slot massive OOB read. CDB length check at :509 only bounds cdb_len never dxfer_len. [VERIFIED pass2: reproduced - int len from u32 dxfer_len 0x80000000 issues bzero of 18446744071562067968 unbounded kernel wipe captured live; INT_MAX reject fix A/B zero bzero calls]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2502 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1019 B | β raw | |
| VERDICT.md | β | 2.5 KB | β raw | |
| build.sh | β | 99 B | view raw | |
| run.log | β | 352 B | view raw | |
| env.txt | β | 963 B | view raw | |
| fix.diff | β | 994 B | view raw | |
| manifest.json | β | 771 B | view raw | |
| verdict.json | β | 2.9 KB | view raw | |
| panic.txt | β | 252 B | view raw |
DF-2502 -- Signed int len from u_int32 dxfer_len: sign-extended bzero/kmalloc/bcopy in atapi_action
Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_acam (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_acam.ko; sysctl kern.dfv_acam_run=0 (control); reset; sysctl kern.dfv_acam_run=2 (hostile)
Expected
run.log: DF2502 bzero(len=18446744071562067968) hostile vs bzero(len=512) control; fixed: zero bzero calls.
Fix validation
fix.diff rejects dxfer_len > 0x7fffffff with CAM_REQ_INVALID before any use; A/B shows zero bzero calls.
Verdict: reproduced / impact=corruption (see verdict.json, VERDICT.md)
DF-2502 verdict -- Signed int len from u_int32 dxfer_len: sign-extended bzero/kmalloc/bcopy in atapi_action
status: reproduced reproduced: 1 impact: corruption confidence: certain attempts: 3 runtime_sec: 900
The verbatim atapi_action assigns int len = csio->dxfer_len (u_int32) at :565; the INQUIRY special case then calls bzero(buf, len) with an INQUIRY CDB whose length field exceeds SHORT_INQUIRY_LENGTH. With a pass(4)-shaped CCB (dxfer_len=0x80000000, INQUIRY cdb byte4=255) the verbatim code issued bzero(buf, 18446744071562067968) - the sign-extended INT_MIN length captured live from the verbatim call (the rig intercepts the actual memset; in production this is an unbounded kernel-memory zeroing starting at the CDB data buffer). Control (dxfer_len=512) issued bzero(512) exactly. Both runs continue past the INQUIRY case into a rig-fabrication-depth crash at 0x64(%rcx) (present in control and hostile alike - documented as a rig artifact; the bzero length is the discriminator). Fixed source A/B (reject dxfer_len > 0x7fffffff before the special cases): NO bzero is issued at all and the guest survives the run cleanly. The first fix draft used (u_int)len != dxfer_len, which the round-trip makes always-false - caught by the A/B rerun and corrected.
Evidence (decisive lines)
control: DF2502 bzero(len=512) hostile: DF2502 bzero(len=18446744071562067968) <- 0xffffffff80000000, sign-extended INT_MIN (subsequent rig-state crash at 0x64(%rcx) occurs in BOTH runs - rig artifact, not the defect) --- fixed source A/B --- dmesg | grep -c "DF2502 bzero" -> 0 <- no bzero issued; run completes, guest survives
Panic
Fatal user address access from kernel mode from sysctl at ffffffff82600aad Stopped at df_run2502+0x84d: cmpl $0xfffe,0x64(%rcx) (rig fabrication-depth artifact present in control and hostile runs; the defect evidence is the captured bzero length)
Exploit chain / privesc assessment
catastrophic kernel memory wipe from a CCB the CAM pass path can carry; on this system the raw-device permission gate bounds who can build it; impact class: corruption.
Fix + A/B
fix.diff rejects dxfer_len > 0x7fffffff with CAM_REQ_INVALID before any use; A/B shows zero bzero calls.
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
catastrophic kernel memory wipe from a CCB the CAM pass path can carry; on this system the raw-device permission gate bounds who can build it; impact class: corruption.
Evidence (decisive lines)
run.log: DF2502 bzero(len=18446744071562067968) hostile vs bzero(len=512) control; fixed: zero bzero calls.
PoC changes
bzero interposed (rig) to capture the length; the first fix draft was refuted by A/B and corrected to the > INT_MAX form.
Verified recommended fix
reject dxfer_len > INT_MAX before assigning to int len
Verdict
The verbatim atapi_action assigns int len = csio->dxfer_len (u_int32) at :565; the INQUIRY special case then calls bzero(buf, len) with an INQUIRY CDB whose length field exceeds SHORT_INQUIRY_LENGTH. With a pass(4)-shaped CCB (dxfer_len=0x80000000, INQUIRY cdb byte4=255) the verbatim code issued bzero(buf, 18446744071562067968) - the sign-extended INT_MIN length captured live from the verbatim call (the rig intercepts the actual memset; in production this is an unbounded kernel-memory zeroing starting at the CDB data buffer). Control (dxfer_len=512) issued bzero(512) exactly. Both runs continue past the INQUIRY case into a rig-fabrication-depth crash at 0x64(%rcx) (present in control and hostile alike - documented as a rig artifact; the bzero length is the discriminator). Fixed source A/B (reject dxfer_len > 0x7fffffff before the special cases): NO bzero is issued at all and the guest survives the run cleanly. The first fix draft used (u_int)len != dxfer_len, which the round-trip makes always-false - caught by the A/B rerun and corrected.
No comments yet.