β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2505

Drive-controlled / TOCTOU OOB kernel heap read in DVD_STRUCT_BCA and DVD_STRUCT_MANUFACT

Summary

In acd_read_structure DVD_STRUCT_BCA and DVD_STRUCT_MANUFACT cases use s->length=ntohs(d->length) as bcopy length where d->length is drive-controlled u_int16_t then re-read s->length from user pointer in bcopy. Neither value bounded against actual size of kernel buffer d (188 bytes BCA 2048 bytes MANUFACT). Malicious ATAPI device or user racing s->length causes bcopy to read up to 65535 bytes past d allocation into adjacent kernel heap written to user memory. [VERIFIED with corrections: drive-controlled OOB read AND kernel heap corruption via kern_ioctl buffer overrun (up to 1860 bytes/call leaked to caller); TOCTOU arm refuted (kernel buffer); hostile-drive hardening class - RESTRICTEDROOT + capability gated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2505 Β· 13 files
FileTypeDescriptionSize
dfrig4_acd.c β€” 15.0 KB view raw
Makefile β€” 445 B ↓ download
build.sh β€” 298 B view raw
build.log β€” 6.4 KB view raw
run.sh β€” 287 B view raw
run.log β€” 3.3 KB view raw
fix_validation.log β€” 1.4 KB view raw
fix_run.log β€” 1.6 KB view raw
fix_build.log β€” 333.7 KB ↓ download
fix.diff β€” 882 B view raw
fix_combined.diff β€” 1.2 KB view raw
env.txt β€” 1.2 KB view raw
verdict.json β€” 5.8 KB view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

fixed

fix_validation.log / fix_run.log: patched kernel #1 (Thu Oct 15 23:37:29 UTC 2026), rig rebuilt against patched /usr/src: test30 s->length clamped 4096->188 with zero markers and zero destination smashes; test31 clamped 3000->2048 clean; test32 clamped 65535->188 clean, survives; test33 control unchanged. Baseline: 3/3 hostile tests proved OOB read (+2/3 dest overflow). fix.diff applied to guest /usr/src only; audit sys/ tree untouched.
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #1: Thu Oct 15 23:37:29 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Confirmed kernel references

Detail

Exploit chain

malicious ATAPI drive (compromised firmware / USB-IDE bridge): respond to READ DVD STRUCTURE (format 3 or 4) with data_length=0xFFFF (DMA stays within the 192/2052-byte allocation length) -> acd_read_structure atapi-cd.c:1583/1588 stores ntohs() verbatim -> bcopy(d+4, s->data, 65535) reads 65531 bytes past the 192-byte heap chunk into the kernel ioctl buffer and writes 65523 bytes past it (kernel heap corruption; content = adjacent heap) -> driver returns 0 -> kern_ioctl copyouts 2060 bytes -> caller receives up to 1860 bytes/call of kernel heap beyond the 188-byte legit payload. Repeatable at will. No control over leaked offset selection beyond the claimed length.

Evidence (decisive lines)

run.log (baseline kernel, tests 33/30/31/32 with full production-call readbacks: s->length values, 0xAA marker spans [188..4095]/[2300..2999]/[188..16123], destination guard smash 1/10, control clean); fix_validation.log + fix_run.log (patched kernel: clamped 188/2048, zero markers/smashes); dfrig4_acd.c header documents the seam; build.log full compile of the verbatim production file.

PoC changes

No seeded sources existed; the rig was authored fresh following findings/poc/DF-2496/dfrig3_ata.c: (a) interposition moved to ata_atapicmd (the ATAPI response boundary this driver trusts) instead of ata_queue_request; (b) s allocated as a faithful kern_ioctl M_IOCTLOPS 2060-byte buffer (kernel malloc type bound via extern); (c) >2048 allocations use the kmem carve path on this guest, so freed-hole sandwiches never place the production MANUFACT chunk -- marker chunks are carved from inside the seam (while d exists, before the production bcopy) as pure instrumentation; the hostile attack input remains the 2-byte claimed length; (d) retry loop for <2048 magazine placement nondeterminism.

Verified recommended fix

Clamp both BCA and MANUFACT copies: copylen = min(ntohs(d->length), length-4) and min(copylen, sizeof(s->data)) before storing s->length and bcopy (fix.diff does exactly this).

Verdict

Drive-controlled OOB kernel heap read CONFIRMED at both DVD_STRUCT_BCA and DVD_STRUCT_MANUFACT sites through 100% production code (unmodified atapi-cd.c compiled into the dfrig4_acd KLD; only ata_atapicmd() interposed at the hardware boundary to serve a hostile 2-byte response length -- the DF-2496-proven verbatim-module pattern). BCA: claimed 4096 vs 192-byte allocation -> 3907 OOB-sourced marker bytes land in s->data[188..], and the same bcopy WRITES ~2048 bytes past the 2060-byte M_IOCTLOPS kern_ioctl buffer (guard smashed). MANUFACT: claimed 3000 vs 2052 -> 700 marker bytes past the allocation. Max arm 0xFFFF: s->length=65535 accepted, 65531 bytes read from a 192-byte chunk (0xAA x15936), non-fatal on the contained run. Compliant-length control (188) shows zero false positives. kern_ioctl then copyouts the full 2060-byte buffer to the caller on rc=0 -> up to 1860 bytes/call of kernel heap disclosed to the ioctl caller. CORRECTIONS to the finding: (1) the user-race/TOCTOU arm is refuted on DragonFly -- ap->a_data is a kernel M_IOCTLOPS buffer (sys/kern/sys_generic.c:675), not user memory; (2) reachability requires a malicious/compromised ATAPI device AND the RESTRICTEDROOT open gate (sys/kern/subr_disk.c:1071) plus the MST_READ_DVDROM capability gate, so this is a hostile-drive hardening bug, not an unprivileged-user primitive. Single-fix kernel validated: clamp to length-4/sizeof(s->data) -> all hostile tests clamp cleanly, zero markers, zero smashes.