DF-4231 / verdict.json
{ "finding_id": "DF-4231", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-level certain: txp_rx_reclaim() (sys/dev/netif/txp/if_txp.c:676) stamps the firmware-fed 16-bit rxd->rx_len (volatile, inside the DMA-shared rx ring, if_txpreg.h:263) into the receive cluster mbuf with no bound, then m_copydata(m, 0, rx_len, mtod(mnew)) at :704 (__STRICT_ALIGNMENT is always defined, if_txp.c:85) copies rx_len bytes between two 2048-byte clusters in one bcopy (m_copydata trusts m->m_len, uipc_mbuf.c:1671/1690) -- for rx_len>2048 both an OOB heap read of the source cluster and an equal OOB heap write past the destination cluster, up to 63531 bytes, contents = adjacent cluster-zone heap. No KASSERT fires (driver itself stamped m_len). Runtime honestly inconclusive: driver verified present in the running kernel (kldstat -v: 161 pci/if_txp) but the guest has no 3Com 3c990 (pciconf: NO_3COM_PCI_DEVICE) and QEMU has no Typhoon model, so the DMA-fed precondition cannot be staged.", "exploit_chain": "On real/passthrough hardware: firmware writes rx_desc{flags=DATA, rx_len=65535} -> intr -> txp_rx_reclaim -> 63KB bcopy past mnews cluster -> adjacent mbuf-cluster-zone objects overwritten with heap-sourced content -> groom a victim cluster-adjacent object (e.g. in-flight mbuf m_data/m_ext) -> kernel R/W -> uid=0 for the device owner; faulty-firmware case = crash generator. Same class as audit-accepted DF-3604 (bce) family.", "evidence": "run.log (driver-in-kernel + NO_3COM_PCI_DEVICE + md5 parity), VERDICT.md (path:line trace + m_copydata mechanics), trigger.c (annotated precondition probe), fix.diff", "kernel_refs": [ "sys/dev/netif/txp/if_txp.c:676", "sys/dev/netif/txp/if_txp.c:688", "sys/dev/netif/txp/if_txp.c:693", "sys/dev/netif/txp/if_txp.c:704", "sys/dev/netif/txp/if_txp.c:85", "sys/dev/netif/txp/if_txpreg.h:263", "sys/dev/netif/txp/if_txpreg.h:631", "sys/kern/uipc_mbuf.c:1671", "sys/kern/uipc_mbuf.c:1690" ], "poc_changes": "No seed existed (pass-2 new finding); trigger authored as an annotated hardware-precondition probe per the DF-3604 convention since no syscall path can forge DMA state.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 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": 140, "guest_dirty": 0, "build_cmd": "cc -o trig_4231 t4231.c (guest)", "run_cmd": "./trig_4231 && kldstat -v | grep if_txp && (pciconf -l | grep -i 10b7 || echo NO_3COM_PCI_DEVICE)", "code_hash": "f30b1c6ed94a205c31d1b5ac6fbe4e9e3936fb694994cfc3fad281295aec9cd5", "notes": "Pass-2 depth: DF-1461 (known) covers only txp_rxbuf_reclaims kfree error path -- different function, no overlap (DB queried). fw download bounds (if_txp.c:553-567) verified sound vs the compiled-in tc990image; tx walks are cnt-bounded; rsp_numdesc is u_int8 so the kmalloc cannot overflow.", "recommended_fix": "In txp_rx_reclaim, drop frames with rx_len outside [ETHER_MIN_LEN, MCLBYTES] before stamping m_len (see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff uses the files own error idiom (ierrors + goto next, cf. if_txp.c:664-668) so the buffer slot keeps its cluster for the next refill. Not runtime-validable: no 3c990 on the guest, same reason the PoC is inconclusive.", "fix_evidence": "fix.diff; run.log absence proof" } |