DF-3469 / verdict.json
{ "finding_id": "DF-3469", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "Unprivileged local kernel-pointer disclosure reproduced on the stock guest: with if_sl loaded (kldload if_sl; all 4 sl units register their whole softc as linkmib at SYSINIT time, no tty needed), any local user reads net.link.generic.ifdata.<idx>.2 (IFDATA_LINKSPECIFIC) and receives sizeof(struct sl_softc)=5736 bytes containing 91 kernel-pointer qwords, including exact &sloutput (0xffffffff826011f0) and &slioctl (0xffffffff82601520) verified against kldstat module base + nm offsets, plus module-bss/softc self-addresses. 3/3 byte-identical unprivileged runs. Fix (linkmib=NULL/len=0 in sl.c) rebuilt as a module and validated: patched dump len=0, zero pointers.", "exploit_chain": "uid 1001 -> raw sysctl(3) on OID {4,18,0,2,ifindex,2} -> 5736-byte struct sl_softc copyout -> extract &sloutput/&slioctl (text/KASLR defeat), softc kernel address, (post-SLIP) tty* + heap buffer addresses; disclosure-only ceiling - companion primitive for exploiting an independent memory-corruption bug, no direct escalation from this bug alone.", "evidence": [ "run.log/run.2.log/run.3.log (uid=1001, 91 pointer qwords, MD5-identical; +0x150=0xffffffff826011f0=&sloutput, +0x168=0xffffffff82601520=&slioctl)", "run.root.log (root reference)", "patched_run.log (fix validated: len=0)", "env.txt (kldstat base 0xffffffff82600000; nm offsets sloutput +0x11f0, slioctl +0x1520)", "VERDICT.md" ], "kernel_refs": [ "sys/net/if_mib.c:178", "sys/net/if_mib.c:185", "sys/net/sl/if_sl.c:218", "sys/net/sl/if_sl.c:219", "sys/net/sl/if_slvar.h:48", "sys/kern/kern_sysctl.c:1446" ], "poc_changes": "Seed sketch had wrong sysctl path semantics: DF sysctl(8) CLI cannot address numeric children of handler nodes (sysctl net.link.generic.ifdata.3.2 -> unknown oid), so the PoC uses the raw sysctl(3) syscall with explicit OID {CTL_NET=4, PF_LINK=18, generic=0, ifdata=2, ifindex, IFDATA_LINKSPECIFIC=2}; initial draft also used PF_LINK=16 (AF_LINK is 18) and missed inttypes.h/unistd.h includes.", "attempts": 3, "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": "cc -O -o /tmp/read_leak read_leak.c", "run_cmd": "kldload if_sl (root, once); /tmp/read_leak (any user)", "code_hash": "e6a10928ccff9bd34f84819b8a3a5f3336a9d7d358055f1d0f1dd322fc647fce", "notes": "sl is module-only in GENERIC (kldload if_sl); exposure starts at module load because slattach() SYSINIT registers linkmib for all NSL units - no SLIP session needed. Stock if_sl cannot be unloaded once loaded (SYSINIT, no SYSUNINIT), so fix validation used a fresh vm.sh reset and loaded the patched module first. Guest was reset clean after the run. Other in-tree linkmib users (vlan, xe) export scalars only.", "recommended_fix": "sl.c: stop registering the raw softc as the link MIB (if_linkmib=NULL, if_linkmiblen=0); if an SNMP-style MIB is ever needed, export a dedicated scalar struct.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 (same kernel; patched if_sl.ko module loaded in place of stock)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Applied fix.diff to the guest /usr/src copy (if_linkmib=NULL/if_linkmiblen=0), rebuilt only if_sl.ko (cd /usr/src/sys/net/sl && make obj && make), loaded it on a fresh reset before the stock module. Baseline: unprivileged dump 5736 bytes/91 pointer qwords. Patched: linkspecific len=0, 0 pointer qwords for sl0..sl3 (patched_run.log). Leak eliminated.", "fix_evidence": "fix.diff; patched_run.log (len=0 for all sl units, uid 1001); module link line in build.log header note" } |