DF-3578 / verdict.json
{ "finding_id": "DF-3578", "status": "inconclusive", "reproduced": 0, "impact": "panic", "confidence": "certain", "verdict": "Division by zero in iwn4965_set_txpower(): interpolate() (if_iwn.c:5636-5637) divides by chans[1].num - chans[0].num, two raw EEPROM bytes bulk-loaded without validation at if_iwn.c:2314; a malicious/corrupt 4965 EEPROM carrying equal sample channel numbers makes the divisor zero and the kernel takes a #DE at device bring-up (iwn_config -> ops->set_txpower, if_iwn.c:6798). The verbatim macros were executed on the DragonFly guest with EEPROM values routed through volatile stores: control (36/64) survives, malicious (36/36) dies SIGFPE exit 136, deterministic 4/4. First harness iteration was silently constant-folded by gcc -O2 (documented in VERDICT.md) and had to be hardened - a real hardware idiv, not a compiler fold. In-kernel execution impossible on the virtio-only guest (no 4965 card), hence inconclusive-at-runtime / certain-at-source.", "exploit_chain": "malicious/tampered 4965 EEPROM with chans[0].num == chans[1].num in any power group -> machine boots / ifconfig wlan0 up -> iwn4965_read_eeprom loads sc->bands unvalidated -> iwn_config -> iwn4965_set_txpower -> interpolate() divides by 0 -> #DE -> kernel panic (persistent DoS: faults again on every bring-up).", "evidence": "run.log (control OK; malicious EEPROM (nums 36/36) then exit=136 SIGFPE), run.2.log (3/3 stress), iwn_eeprom_div0.c (verbatim macros, volatile-fed operands), VERDICT.md (source trace + constant-folding pitfall), fix.diff.", "kernel_refs": [ "sys/dev/netif/iwn/if_iwn.c:2314", "sys/dev/netif/iwn/if_iwn.c:5633", "sys/dev/netif/iwn/if_iwn.c:5636", "sys/dev/netif/iwn/if_iwn.c:5707", "sys/dev/netif/iwn/if_iwn.c:6798", "sys/dev/netif/iwn/if_iwn.c:7199" ], "poc_changes": "No seed existed; harness authored in this run. Values fed through volatile after the plain-struct version was constant-folded by gcc -O2 (folded 0/0 does not fault; the hardened version faults 4/4).", "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": 10, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o iwn_eeprom_div0 iwn_eeprom_div0.c", "run_cmd": "./iwn_eeprom_div0 # expect exit=136 (SIGFPE) after control succeeds", "code_hash": "8335b52c5ed94d90e64b02f4dd4c3f793fb21da3b6f8f72208e0f9d421ddd3b5", "notes": "Threat model: malicious/corrupt EEPROM = physical tamper or root-controlled flashing (audit-strategy surface EEPROM parse). Sibling pattern: maxpwr values ARE range-checked at if_iwn.c:2305-2309, the band sample channels are not.", "recommended_fix": "Validate chans[1].num > chans[0].num (return EINVAL otherwise) before interpolate() in iwn4965_set_txpower, or validate the whole sc->bands table after the EEPROM bulk read.", "fix_status": "not_testable", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree; kernel-build validation impossible on the virtio-only guest (no 4965 hardware, and the trigger is EEPROM contents). Baseline fault primitive reproduced (SIGFPE exit 136); the guard returns EINVAL before the division.", "fix_evidence": "findings/poc/DF-3578/fix.diff" } |