# DF-3469 — VERDICT

**Status: reproduced (impact: leak, confidence: certain)**

## Root cause (path:line)

1. `sys/net/if_mib.c:178-189` — `sysctl_ifdata()` case `IFDATA_LINKSPECIFIC`
   does `SYSCTL_OUT(req, ifp->if_linkmib, ifp->if_linkmiblen)`: an
   unconditional copyout of whatever buffer/length the driver registered.
   Sysctl **reads** are unprivileged in DragonFly; only writes are gated
   (`sys/kern/kern_sysctl.c:1446-1450`, `SYSCAP_NOSYSCTL_WR`). The handler
   holds the global ifnet lock across the copyout (that lock issue is the
   known DF-0757, not re-reported here); the *content* export is the
   defect reported here.
2. `sys/net/sl/if_sl.c:218-219` — sl(4) sets `if_linkmib = sc;
   if_linkmiblen = sizeof *sc`, i.e. the raw `struct sl_softc` — an SNMP-MIB
   habit from the 1990s. The struct (sys/net/sl/if_slvar.h:48-66) embeds
   `struct ifnet sc_if` (function pointers `if_output`, `if_ioctl`,
   serializer/TAILQ pointers), `struct tty *sc_ttyp`, `u_char *sc_mp /
   *sc_ep / *sc_buf`, two `struct callout` (function pointers), and
   `struct slcompress sc_comp`. Registration happens for all `NSL` units in
   the `slattach()` SYSINIT at module load — **no tty is required**.

Reachability for an unprivileged user requires only that the sl interface
exists (`kldload if_sl` or `device sl` kernels); the read itself is a plain
unprivileged sysctl.

## How it was reproduced

Stock INVARIANTS kernel (DragonFly 6.5-DEVELOPMENT #0, x86_64, guest up via
dfbsd-qemu/vm.sh):

1. Root: `kldload if_sl` → sl0..sl3 attach (ifcount 6).
2. Root ground truth: `kldstat` → if_sl.ko @ 0xffffffff82600000;
   `nm /boot/kernel/if_sl.ko` → sloutput +0x11f0, slioctl +0x1520.
3. Built `read_leak.c` (raw `sysctl(3)` on OID {4,18,0,2,idx,2}).
4. **Unprivileged user (uid 1001)** ran it: each sl unit returns
   **5736 bytes** with **91 kernel-pointer qwords**, including exact
   matches `+0x150 = 0xffffffff826011f0 (= &sloutput)` and
   `+0x168 = 0xffffffff82601520 (= &slioctl)` (run.log/run.2.log/run.3.log,
   byte-identical MD5 across 3 runs).

That satisfies the leak criterion: leaked bytes match known kernel-memory
values (symbol addresses verified against the loaded module's base +
symbol offsets) across >= 3 runs, by an unprivileged local user.

## Exploit chain ceiling

Pure information disclosure: defeats KASLR/module randomization (text
addresses), leaks module-bss addresses (the softc's own address via
self-referential list heads), and after a SLIP session would additionally
leak a `struct tty *` and heap buffer addresses (`sc_ep` is kmalloc'd in
`slinit`). This is the standard companion primitive for making an
independent heap-corruption bug reliably exploitable; no direct
privilege escalation from this bug alone.

## Fix validation

`fix.diff` (authored against the read-only `sys/` tree, applied to the
guest's /usr/src copy only): sl.c registers `if_linkmib = NULL /
if_linkmiblen = 0` (nothing sensible was ever consumed from this MIB).

* Rebuilt only the `if_sl.ko` module in-guest
  (`cd /usr/src/sys/net/sl && make obj && make`), loaded the patched
  module on a fresh `vm.sh reset with-src` guest **before** the stock
  module.
* Baseline (stock module): unprivileged dump = 5736 bytes / 91 pointer
  qwords (run.log).
* Patched: unprivileged dump = `linkspecific len=0`, 0 pointer qwords for
  sl0..sl3 (patched_run.log). Bad behavior gone → fix_status=fixed.

(The stock if_sl cannot be `kldunload`ed once loaded — SYSINIT attach with
no SYSUNINIT — hence the fresh-reset A/B rather than in-place swap.)

## Negative results / notes

* Other in-tree `if_linkmib` users are scalar-only:
  vlan (sys/net/vlan/if_vlan.c:151-154: int+uint16+uint16),
  xe (if_xe.c:268-269: dot3Stats counter array). sl is the only
  pointer-bearing export found.
* The `IFDATA_GENERAL` write-back path is root-only and restores
  type/mtu/etc. from ifp before writing if_data (if_mib.c:145-156), so no
  unprivileged stats/mtu tampering.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
