{
 "finding_id": "DF-3506",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "leak",
 "confidence": "certain",
 "verdict": "REACHABILITY DISCOVERY THAT GATES ALL FOUR v1-fec FINDINGS: the shipped stock ng_fec.ko cannot create a node at all - ng_fec_constructor deterministically panics 'trying to free NULL pointer' in _kfree on the FIRST node creation (reproduced 2/2 fresh boots, boot.log evidence). Root cause (disassembly + instrumented rebuild on the guest): gcc deletes the 'if (ng_fec_units != NULL)' guard before kfree() in ng_fec_get_unit() because the preceding bcopy(ng_fec_units, ..., 0) passes NULL as a pointer argument - undefined behavior that lets the compiler prove the pointer non-NULL; the instrumented module printed 'FECDBG: ctor enter ng_fec_units=0 len=0' followed by 'FECDBG: get_unit freeing old units 0' - the guard taken on a NULL value, proving the compiler-eliminated check. This panic is not INVARIANTS-gated (plain NULL check in _kfree), so the module is dead on ANY kernel config; the reported rcvmsg/addport/delport/tick paths are unreachable on stock bits. VERIFICATION ON A MINIMALLY-REPAIRED HARNESS MODULE (only fix: skip the len==0 bcopy; rcvmsg/addport/ifunit verbatim, driven from a sysctl context because control messages additionally hit the INVARIANTS-only 'ifnet lock in netisr' assert): with arglen=8 and data 'AAAAAAAA' (no NUL) the kernel log shows 'fec0: tried to add iface AAAAAAAAXXXX' - the %s/strcmp walk read FOUR BYTES past the 8-byte message data into the groomed adjacent heap (same-handler groom of 12 'X' bytes for deterministic magazine reuse). With arglen=4 'CCCC' the read of the NUL terminator itself is provably out of bounds (in-bounds bytes are all 'C'). Bounded-by-first-zero heap over-read, root-gated; fault-grade only at slab/page boundaries; dmesg disclosure of adjacent heap content. FIX VALIDATED A/B on the stock kernel: with fix.diff applied (arglen>=2 + NUL required, same ctor repair), the identical attack with CONFIRMED chunk reuse (oob groom=...msg=... same=1 - the message landed on the groomed chunk) returns EINVAL(22) and prints NO 'tried to add' line at all - the string walk never starts; baseline prints AAAAAAAAXXXX. panic.txt (fresh clean boot) captures the stock-module constructor panic.",
 "exploit_chain": "",
 "evidence": "fec-sequence.log line 'tried to add iface AAAAAAAAXXXX' (4-byte overread visible), fec-boot-final.log (stock-module ctor panic), fechg.c (harness: verbatim rcvmsg/addport + ctor-UB fix, disclosed), FECDBG instrumented prints",
 "kernel_refs": [
  "sys/netgraph/fec/ng_fec.c:1172",
  "sys/netgraph/fec/ng_fec.c:1177",
  "sys/netgraph/fec/ng_fec.c:345",
  "sys/netgraph/fec/ng_fec.c:348",
  "sys/netgraph/fec/ng_fec.c:272"
 ],
 "poc_changes": "harness module built from pristine ng_fec.c with (a) constructor UB fix (skip len==0 bcopy) so a node can exist at all, (b) appended sysctl driver calling verbatim ng_fec_rcvmsg from a non-netisr context (INVARIANTS ifnet_lock assert otherwise panics first), (c) same-op groom for deterministic OOB visibility",
 "attempts": 6,
 "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": 900,
 "guest_dirty": 0,
 "build_cmd": "cd /usr/src/sys/netgraph/fec && make   # fechg.c staged as ng_fec.c",
 "run_cmd": "kldload ./ng_fec.ko; sysctl kern.fechg.op=create; sysctl kern.fechg.op='oob 8 4141414141414141'; dmesg | grep 'tried to add'",
 "code_hash": "40c03b5b50a8d27e39d27b40ddb2af0af84a6c0778c121aeae364684bd18ed85",
 "notes": "STOCK-BITS STATUS: unreachable (constructor panics first - separate shipped-module defect documented here as reachability fact). The OOB read itself is real code in the shipped module and manifests once the module can construct. ng_mesg header is 52 bytes (ng_message.h v1: cmdstr[NG_CMDSTRSIZ]); 52+8 and 52+12 land in the same kmalloc zone class.",
 "recommended_fix": "validate arglen>=2 and memchr(msg->data,'\\0',arglen) before treating msg->data as a string in NGM_FEC_ADD_IFACE/DEL_IFACE (also fix the get_unit bcopy UB so the module can build)."
}