# DF-4941 — if_ic: SIOCSIFMTU frees the working buffers even when the replacement allocation fails (installs NULL ic_obuf/ic_ifbuf)

**File:** `sys/dev/netif/ic/if_ic.c` (icioctl SIOCSIFMTU, lines 205–223)
**Verdict: source-proven, PoC not executed** (triggering the allocation
failure deterministically requires kernel-memory exhaustion; see VERDICT.md).
Fix (`fix.diff`) authored from the line-accurate root cause, compile-checked
against the guest tree, **not runtime-validated**.

## The bug

```c
sc->ic_ifbuf = kmalloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_WAITOK);   /* 211 */
sc->ic_obuf  = kmalloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_WAITOK);   /* 214 */
if (iptr) kfree(iptr, M_DEVBUF);                                     /* 217 */
if (optr) kfree(optr, M_DEVBUF);                                     /* 220 */
sc->ic_if.if_mtu = ifr->ifr_mtu;                                     /* 222 */
```

There is no NULL check and no rollback. `M_WAITOK` is widely assumed to
never fail, but on DragonFly that is false for these sizes:

- the generic SIOCSIFMTU wrapper allows `72 <= ifr_mtu <= 65535`
  (sys/net/if.c:2272, IF_MINMTU/IF_MAXMTU, sys/net/if_var.h:558-559), so
  the allocation is up to 65539 bytes;
- allocations at/above `ZoneLimit` go to `kmem_slab_alloc()` which
  **returns NULL on failure even with M_WAITOK**
  (sys/kern/kern_slaballoc.c:942-950);
- for zone-sized allocations, zone creation failure also unwinds to NULL
  (kern_slaballoc.c:1070-1072 `if (z == NULL) goto fail;`).

Under kernel-map pressure, `ifconfig ic0 mtu 65535` therefore:
1. kfree()s the *working* buffer pair (lines 217-220),
2. installs two NULL pointers,
3. still updates `if_mtu` (line 222) and returns success.

From that moment the interface is armed with the DF-2001 sinks:
`icintr` INTR_RECEIVE `*sc->ic_cp++` (line 309) and `icoutput`'s
`bcopy(..., sc->ic_obuf, ICHDRLEN)` (line 358) dereference NULL — a
deterministic kernel panic (local DoS) on the next traffic or received
byte, caused by an ordinary error path rather than the DF-2001 pre-alloc
condition.

## Fix

Allocate the replacements first with `M_NULLOK`; on failure free only the
failed new allocations and return `ENOBUFS`, leaving the working pair and
the old MTU untouched (fix.diff).

## Why not runtime-verified

The failure precondition is kmem exhaustion for a 64 KB-class allocation.
Deliberately exhausting kernel memory on the shared audit guest risks
wedging unrelated subsystems (and the VM), and the mechanism (source trace
above) is deterministic. Recorded as untested rather than risking a
low-value DoS of the test environment; the root cause is fully cited.
