# DF-3320 VERDICT

**Status: reproduced** — unprivileged kernel heap pointer disclosure after a
one-time privileged misconfiguration (DF-3318's IPv4 twin, live today through
SIOCGIFCONF and route sockets). **Fix validated** on a rebuilt kernel.

## The bug (set side, privileged)

`in_control_internal()`/`in_ifinit()` copy user sockaddrs into the live
`struct in_ifaddr` verbatim, `sin_len` included — no length check exists on
any of these paths (`sys/netinet/in.c`):

* `:998` `ia->ia_addr = *sin;` (SIOCSIFADDR/SIOCAIFADDR → `in_ifinit`),
  exported as `ifa->ifa_addr` (`:543`); for lo0 additionally
  `:1062-1063` `ia_dstaddr = ia_addr` (→ `ifa_dstaddr`);
* `:602` SIOCSIFDSTADDR → `ia_dstaddr`;
* `:625` SIOCSIFBRDADDR → `ia_broadaddr` (= `ifa_dstaddr`);
* `:668` SIOCAIFADDR `ifra_mask` → `ia_sockmask` (→ `ifa_netmask`, `:545`).

## The bug (consume side, unprivileged)

* `ifconf()` — `SIOCGIFCONF`, **no privilege check**
  (`sys/net/if.c:1996-1997`) — does
  `copyout(sa, &ifrp->ifr_addr, sa->sa_len)` (`sys/net/if.c:2590-2592`) and
  advances by `sa_len`. `sa` is `ifa->ifa_addr` = `&ia->ia_addr`
  (object offset 312 of 360): `sin_len = 200` ⇒ 152 bytes read past the end
  of the heap object, copied straight to any local user (plain `ifconfig -a`
  exercises the same path).
* `sys/net/rtsock.c:1140,1175,1202` — `RT_ROUNDUP(sa->sa_len)`-sized copies
  of `ifa_addr`/`ifa_dstaddr`/`ifa_netmask` into route-socket messages
  (RTM_NEWADDR/RTM_DELADDR broadcast right after the setup ioctl; readable
  unprivileged).
* (The in-file consumers `sys/netinet/in.c:927/:930-951` are the same
  pattern, but on the current tree they are gated behind the DF-0490 filter
  and only ever see the type-confused in6_ifaddr — that manifestation is
  DF-3319. SIOCGIFADDR/SIOCGIFNETMASK/SIOCGIFDSTADDR/SIOCGIFALIAS handlers
  use fixed-size struct assigns and are safe.)

## Reproduction (stock INVARIANTS kernel #0, dfbsd 6.5-DEVELOPMENT)

1. root: `./setup lo0` — SIOCAIFADDR with `ifra_addr.sin_len=200`
   (127.200.0.200/8) + five normal filler aliases (deterministic slab
   neighbours). The ioctl succeeds; `ifconfig lo0` shows the alias.
2. nobody: `./leak 127.200.0.200` — SIOCGIFCONF, 65536-byte buffer; the
   packed entry for the poisoned address carries 200 bytes:
   `[0..15] ia_addr (len 200)`, `[16..31] ia_dstaddr (len 200)`,
   `[32..47] ia_sockmask`, `[48..199] out-of-bounds`. At offsets 72/80/88:
   `0xfffff8004f2e79d8 / ...e8 / ...f8` — the adjacent in_ifaddr's
   `ifa_addr/ifa_dstaddr/ifa_netmask` pointers (16-byte spacing = the
   sockaddr_in layout inside in_ifaddr). **Identical across 3 runs**
   (`run.log`; `leak_sample.txt`), no-KASLR guest.
3. Baseline before setup: no `sa_len>16` entry exists (also in `run.log`).

Impact ceiling: kernel-heap address disclosure (KASLR defeat + slab layout
revelation) to unprivileged users after one privileged misconfiguration —
the same class/rating DF-3318 received. Not a write primitive: no
unprivileged-only path to the OOB write was found (the in-file write sinks
are privileged or filter-gated).

## Fix validation

`fix.diff` adds set-side `sin_len > sizeof(struct sockaddr_in)` rejection on
SIOCAIFADDR (addr/mask/dstaddr/broadaddr), SIOCSIFDSTADDR, SIOCSIFBRDADDR,
and in `in_ifinit()` before `:998` (plus the DF-3319 hunks). Rebuilt in-guest
(kernel #3, 0 warnings):

* stock #0: setup OK, leak shows pointers (3/3).
* patched #3: `./setup lo0` ⇒ **EINVAL** (`SIOCAIFADDR(lo0, len=200):
  Invalid argument`); `./leak` ⇒ no entry; normal
  `ifconfig lo0 alias 127.200.0.200 netmask 255.0.0.0` succeeds and removes
  cleanly — no functional regression (`fix_run.log`).

## Lines cited

* `sys/netinet/in.c:998` — verbatim `ia_addr = *sin` (the persistence)
* `sys/netinet/in.c:543-545` — ia_addr/ia_dstaddr/ia_netmask exported as ifaddr sockaddrs
* `sys/netinet/in.c:602, :625, :668, :1062-1063` — further verbatim sin_len copies
* `sys/net/if.c:1996-1997, :2578-2592` — unpriv SIOCGIFCONF → sa_len-sized copyout
* `sys/net/rtsock.c:1140, :1175, :1202` — sa_len-sized route message copies
* `sys/kern/sys_generic.c:668-680` — ioctl scratch sizing (context)

## 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.
