DF-3487 / verdict.json
{ "finding_id": "DF-3487", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "Heap OOB read in ng_pppoe_rcvdata() PPPOE_PRIMED branch reproduced deterministically on the stock INVARIANTS kernel: a 32-byte PADI with ph->length=1024 and a Service-Name tag claiming 900 data bytes makes get_tag()/scan_tags() walk past the packet and make_packet() copy 896 bytes of out-of-bounds mbuf-zone memory into the emitted PADO, where the harness captures it. Leaked content includes kernel heap pointers (0xfffff80117632908 etc.), mbuf header fields, ifnet names and, on an active-traffic boot, a complete in-flight TCP segment. Identical 3/3 runs per boot, two boots. Same root cause class as DF-0414 but a distinct sink (PRIMED/daemon-echo path, not the ether-side discovery branch). Root cause is the missing ph->length-vs-packet-length check that the session branch (ng_pppoe.c:1632) already performs.", "exploit_chain": "", "evidence": [ "findings/poc/DF-3487/run.log: PPSBX: PADI pre-send dump (m_len=32): ... 01 01 03 84 SERVNAME followed by captured 944-byte PADO", "findings/poc/DF-3487/leak1.txt: 944-byte capture; OOB window mbuf+32..mbuf+924 with sess_con pointer and .vn1 ifnet name", "findings/poc/DF-3487/leak_sample.txt: boot-A sample with kernel pointers 0xfffff80117632908/0xfffff80117632b08 and a full leaked TCP segment at PADO offset 0x210", "findings/poc/DF-3487/fixrun.log + fixleak1/2.txt: with fix.diff applied, ppsbx_len: 0 and empty capture on 2/2 runs, no crash" ], "poc_changes": "Harness authored fresh (no seed). Two iterations needed: (1) netgraph type must be registered before node creation (setup moved to first sysctl command); (2) tag type/length bytes must be written in big-endian wire order - an initial little-endian write made tag_len read as 0x8403 so get_tag correctly rejected it; after the byte-order fix the leak reproduced immediately.", "attempts": 5, "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": 1500, "guest_dirty": 0, "build_cmd": "cd /usr/src/sys/netgraph7/{netgraph,pppoe}: make obj depend && make; cd /root/ppsbx && make; kldload netgraph.ko ng_pppoe.ko ppsbx.ko", "run_cmd": "sysctl debug.ppsbx_cmd=1; sleep 1; sysctl debug.ppsbx_cmd=2; sysctl debug.ppsbx_len; sysctl -b debug.ppsbx_capture | od -A x -t x1", "code_hash": "f410d3f47b734a85393091e609820f7d344c1b2d44f7d8082bd58d922aa86272", "notes": "Verification side-quest: an initially-hypothesized integer overflow in ng_parse.c:1221 (foff = kmalloc(num*4)) was REFUTED live on this guest - on x86-64 sizeof() promotes the product to 64-bit so no wrap occurs; num=0x40000001 instead produced a ~4GB M_WAITOK kmalloc that wedged the guest into a pagedaemon death spiral (root-gated memory-exhaustion only, not filed). DF-0413 reachability evidence: NGM_ASCII2BINARY parses into a fixed 2000-byte buffer (ng_base.c:2458,2515) while sizedstring/string elements accept up to 64KB - the Info-rated latent finding is concretely reachable by the root ngctl user.", "recommended_fix": "In ng_pppoe_rcvdata() PRIMED branch, reject the PADI when m->m_pkthdr.len < sizeof(*wh) + ntohs(wh->ph.length), mirroring the session-branch check at ng_pppoe.c:1632 (see validated fix.diff).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 (stock kernel; ng_pppoe.ko rebuilt from patched /usr/src - ng_pppoe is a KLD on this guest so the module is the executing code for this path)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to guest /usr/src, ng_pppoe.ko rebuilt and reloaded on a fresh boot; identical PADI input produced no PADO (ppsbx_len 0 vs 944 baseline), empty capture, no panic, 2/2 runs. Full-kernel nativekernel rebuild unnecessary because the vulnerable code executes solely from the KLD.", "fix_evidence": [ "findings/poc/DF-3487/fixrun.log", "findings/poc/DF-3487/fixleak1.txt", "findings/poc/DF-3487/fixleak2.txt", "findings/poc/DF-3487/fix.diff" ] } |