DF-3541 / verdict.json
{ "finding_id": "DF-3541", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "Reproduced on the stock guest (v1 netgraph/ng_socket from /boot/kernel, ng_eiface.ko rebuilt with DF-3486s unblock fix so the node can be created at all): 500 x 2048-byte packets delivered to the ether hook of a DOWN ngethX return ENETDOWN (errno 50) from ng_eiface.c:514-515 and leak exactly +500 mbuf clusters (256 -> 756 in use; 268 -> 768 allocated-to-data); the control run with the interface UP shows zero growth, isolating the ENETDOWN path. Root cause: ng_eiface_rcvdata returns ENETDOWN without m_freem(m) although v1 rcvdata owns the mbuf (ng_send_data hands over ownership, callers NULL their pointers) \u2014 the ng7 twin frees explicitly at the same spot, proving the deviation. Unbounded kernel heap exhaustion at traffic rate = DoS (Medium: root must build the netgraph path; traffic can be unprivileged). Fix validated: m_freem(m) before the return gives zero growth with ENETDOWN semantics preserved.", "exploit_chain": "", "evidence": "run.log (before/after netstat -m with +500 clusters and the per-send ENETDOWN); leak_before.txt / leak_after.txt; fix_run.log (fixed module: 256 -> 256, zero growth); unpriv_check.txt (EPERM uid 1001); env.txt", "kernel_refs": [ "sys/netgraph/eiface/ng_eiface.c:514", "sys/netgraph/eiface/ng_eiface.c:515", "sys/netgraph/netgraph/ng_base.c:1684", "sys/netgraph/netgraph.h:224", "sys/netgraph7/eiface/ng_eiface.c" ], "poc_changes": "v1 ABI corrections: NG_VERSION 2, u_int16_t arglen, header field order flags/token/typecookie/cmd; DFly sockaddr_ng data at offset 2 (sa_family_t is __uint8_t); node naming via synchronous bind() (v1 control messages are async through netisr); data socket connect needs the trailing colon (bare name parses as a hook path with here==NULL); added a pre-send wait window for the UP-interface control test.", "attempts": 4, "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": 900, "guest_dirty": 0, "build_cmd": "cd /usr/src && patch -p1 < unblock3486.diff && (cd sys/netgraph/eiface && make) && cc -O2 -o eiface_leak eiface_leak.c", "run_cmd": "kldload /boot/kernel/netgraph.ko; kldload /boot/kernel/ng_socket.ko; kldload /usr/src/sys/netgraph/eiface/ng_eiface.ko; ./eiface_leak 500 2048 (root)", "code_hash": "63fd916cafb234ab48676c7fc4a810d1843489a66a3821efea71fd7e4f8a23a1", "notes": "DF-3486s validated fix is required scaffolding (stock node creation panics first); fix.diff for THIS finding is the single m_freem(m) line. Only the mbuf leaks (meta already freed at :507).", "recommended_fix": "m_freem(m) before the ENETDOWN return in ng_eiface_rcvdata (mirror the ng7 twins NG_FREE_M) \u2014 see fix.diff.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 (stock kernel; fix applied as a module rebuild only)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Identical DOWN-interface test on the fixed module: mbuf clusters 256 -> 256 (zero growth vs +500 baseline), ENETDOWN still returned for every send; interface-UP control unchanged. Leak closed.", "fix_evidence": "fix_run.log (fix_before/fix_after netstat embedded); leak_after.txt vs fix_run.log" } |