DF-3577 / verdict.json
{ "finding_id": "DF-3577", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "4-byte heap OOB read in the iwn firmware TLV parser: the IWN_FW_TLV_PHY_CALIB case (if_iwn.c:8315-8320) executes tmp = le32toh(*ptr) with no len >= sizeof(uint32_t) check, although the generic bound check (if_iwn.c:8280) accepts TLV payloads of 0..3 bytes; a zero-length PHY_CALIB TLV terminating the image makes the load run past the end of the kernel heap buffer holding the firmware (firmware_get, if_iwn.c:8375). Reproduced with a line-for-line copy of the parser loop on the DragonFly guest: image placed flush against a PROT_NONE page, process dies SIGSEGV exit 139, deterministic 4/4 (guest gcc 8.3 lacks libasan, so guard-page mode is the recorded evidence; ASAN variant provided). The one-line fix (mirror the IWN_FW_TLV_FLAGS length guard, if_iwn.c:8328) was validated in the same harness: fixed variant parses the identical image and returns cleanly. No userspace-visible disclosure path exists (the value only feeds calibration command codes), so impact is rated none/Low despite the memory-safety violation.", "exploit_chain": "root-controlled or corrupted iwn firmware file with trailing PHY_CALIB TLV len<4 -> firmware_get loads image into kernel heap -> iwn_read_firmware_tlv reads 4 bytes past allocation end at if_iwn.c:8316 -> OOB heap read (value conditions sc->reset_noise_gain/sc->noise_gain; no leak path to userspace).", "evidence": "run.log (baseline: guard mode ... TLV payload len=0 then exit=139 SIGSEGV; fixed variant: UNEXPECTED: parser returned without OOB = clean return, no fault), run.2.log (stress 3/3 baseline faults), build.log (clean build; ASAN unavailable: cannot find -lasan), iwn_tlv_oob.c (verbatim parser copy), iwn_tlv_oob_fixed.c (fix applied), fix.diff.", "kernel_refs": [ "sys/dev/netif/iwn/if_iwn.c:8280", "sys/dev/netif/iwn/if_iwn.c:8315", "sys/dev/netif/iwn/if_iwn.c:8316", "sys/dev/netif/iwn/if_iwn.c:8327", "sys/dev/netif/iwn/if_iwn.c:8375", "sys/dev/netif/iwn/if_iwn.c:8933" ], "poc_changes": "No seed existed; harness authored in this run: verbatim copy of iwn_read_firmware_tlv parsing loop with struct defs from if_iwnreg.h:1721-1754, guard-page detection mode (ASAN unavailable on guest), plus a fixed variant carrying the proposed one-line guard.", "attempts": 4, "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": 15, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o iwn_tlv_oob iwn_tlv_oob.c && cc -O2 -Wall -o iwn_tlv_oob_fixed iwn_tlv_oob_fixed.c", "run_cmd": "./iwn_tlv_oob guard # expect exit 139; ./iwn_tlv_oob_fixed guard # expect clean return", "code_hash": "86ef2e5de77effdfa0e857e9e6d305e3cba37f21b58943922cda9e3b923ecd1e", "notes": "Parser is pure code over a kernel heap buffer; the harness executes the identical statements on identical input, so this is a faithful reproduction of the defect (allocator differs only in whether the OOB faults). Attacker = firmware-file control (root-installed /boot/firmware), hence Low severity despite CWE-125.", "recommended_fix": "Add if (len < sizeof(uint32_t)) break; to the IWN_FW_TLV_PHY_CALIB case, mirroring IWN_FW_TLV_FLAGS (if_iwn.c:8328).", "fix_status": "not_testable", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree and validated at harness level: baseline harness faults (SIGSEGV 139) on the crafted TLV, fixed harness (identical code + the one-line guard) parses the same image cleanly. Kernel-build validation impossible on this guest (no iwn hardware to load a patched kernel against; the PoC is a userland model of pure parsing code), so fix_status is not_testable rather than fixed.", "fix_evidence": "run.log decisive run C (fixed variant, no fault) vs run B (baseline, SIGSEGV); findings/poc/DF-3577/fix.diff" } |