DF-3690 / verdict.json
{ "finding_id": "DF-3690", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Adaptec HostRAID parser copies an untrusted 16-bit total_disks into raid->total_disks and, because raid->generation is assigned from the same metadata before it is tested, executes the disks[]-clearing loop on the FIRST parse: with total_disks=60000 the kernel wrote NULL/0 across ~2.8MB of heap during ata_raid_subdisk_attach and fatally hit a kernel stack guard page (panic captured on the guest, boot from a single crafted disk, zero interaction). Primitive = attacker-chosen-length strided zeroing write starting inside a live ar_softc; demonstrated as reliable persistent DoS / heap corruption.", "exploit_chain": "crafted disk image with Adaptec metadata (total_disks=60000, gen=1) -> attach at boot -> parse loop writes disks[n].dev=NULL/.flags=0 for n<60000 -> heap + stack guard page smashed -> fatal kernel page fault (DDB wedge). Escalation beyond DoS not pursued: the write content is fixed (NULL/0), value control is absent; realistic ceiling is adjacent-object pointer NULLing (corruption), demonstrated ceiling is boot-time panic.", "evidence": "panic.txt (fatal trap + ata_raid_subdisk_attach frame), run.log, VERDICT.md Why it happens, run.patched.log (fix rejects with Adaptec total_disks out of range, boots to login)", "kernel_refs": [ "sys/dev/disk/nata/ata-raid.c:1704", "sys/dev/disk/nata/ata-raid.c:1703", "sys/dev/disk/nata/ata-raid.c:1716", "sys/dev/disk/nata/ata-raid.c:1717", "sys/dev/disk/nata/ata-raid.c:1720", "sys/dev/disk/nata/ata-raid.h:108" ], "poc_changes": "Seed-free pass-2 finding. First image attempt used big-endian magics and two wrong struct offsets (adaptec magics are raw native compares, unlike generation); guest-compiled layout2.c against the real header fixed the offsets and the image then parsed and panicked as predicted.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 330, "guest_dirty": 0, "build_cmd": "python3 mkmeta.py (host) ; disk attached via QEMU ide.0 unit=0 at launch", "run_cmd": "ARAID_DRIVE=/tmp/opencode/araid/f1_adaptec.img dfbsd-qemu/vm.sh up 220", "code_hash": "", "notes": "ata_raid_adaptec_print_meta also loops to be16toh(total_configs) over configs[127] (bootverbose only) - noted, not fixed. Fix validated on rebuilt kernel (#1 Sep 15 17:27): no array, plain ad0, boot completes.", "recommended_fix": "reject be16toh(configs[0].total_disks) > MAX_DISKS in ata_raid_adaptec_read_meta before any use (fix.diff hunk 6)", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Patched kernel (nativekernel rebuild with fix.diff): same crafted disk prints Adaptec total_disks out of range, creates no array, ad0 attaches as a plain disk, boot reaches login. Baseline panic gone.", "fix_evidence": "findings/poc/DF-3690/run.patched.log lines: ad0: Adaptec total_disks out of range, ad0: 127MB <QEMU HARDDISK 2.5+>, normal boot; compare panic.txt" } |