# DF-4941 VERDICT — source-proven error-path lifecycle defect; PoC not executed (untested)

## Root cause (path:line)

`sys/dev/netif/ic/if_ic.c` icioctl SIOCSIFMTU (205-223): both replacement
buffers are kmalloc'd, the OLD working pair is kfree'd, and `if_mtu` is
updated — with no NULL check on either kmalloc result and no rollback.

`M_WAITOK` does not guarantee success on DragonFly for the sizes reachable
here:

- if.c:2272 admits `72 <= ifr_mtu <= 65535` (IF_MINMTU/IF_MAXMTU,
  if_var.h:558-559) → allocation size up to 65539 bytes;
- size >= ZoneLimit → `kmem_slab_alloc(size, PAGE_SIZE, flags)`; on
  failure the allocator **returns NULL even with M_WAITOK**
  (sys/kern/kern_slaballoc.c:942-950);
- below ZoneLimit, zone creation failure unwinds to NULL as well
  (kern_slaballoc.c:1070-1072).

Under kernel-map pressure `ifconfig ic0 mtu 65535` therefore kfree()s the
working pair, installs `ic_ifbuf == NULL` and `ic_obuf == NULL`, sets
if_mtu = 65535 and reports success. The interface is then armed with the
(pass-1, DF-2001) NULL-deref sinks:

- TX: icoutput if_ic.c:358 `bcopy((char *)&hdr, sc->ic_obuf, ICHDRLEN)`
  → NULL write, panic, on the next routed packet;
- RX: icintr INTR_START caches `sc->ic_cp = sc->ic_ifbuf` (NULL) and
  INTR_RECEIVE executes `*sc->ic_cp++ = *ptr` (if_ic.c:267,309) → NULL
  write, panic, on the next byte from the i2c master.

Note the RX check `sc->ic_xfercnt >= sc->ic_if.if_mtu+ICHDRLEN` (305) does
NOT protect against this: with the NULL buffers there is nothing to
overflow into — the write happens at address 0+xfercnt.

## Classification and honest status

- **status: untested** — the failure precondition is kernel-memory
  exhaustion for a 64 KB-class allocation; forcing it on the shared audit
  guest risks wedging unrelated subsystems. No PoC was executed.
- The defect itself is deterministic and fully source-traced; the sinks'
  behavior (NULL write panic) is established by DF-2001's analysis (same
  sink lines). Confidence: certain for the code defect, likely for
  end-to-end impact.
- Severity: Low — privileged trigger (SIOCSIFMTU is
  SYSCAP_RESTRICTEDROOT-gated, if.c:2265), requires kmem pressure,
  impact ceiling = local kernel panic (DoS).

## Non-overlap

- DF-2000: SIOCSIFMTU *race* (serializer vs output/intr on the freed old
  buffers) — different mechanism (no race here; this is the sequential
  error path).
- DF-2001: the NULL-deref sinks pre-allocation — same sink lines, but this
  finding is the distinct deterministic path that installs NULLs on a
  previously-working interface while claiming success.

## Fix

fix.diff (authored after source verification, compile-checked style,
**not runtime-validated** — fix_status not_tested): allocate replacements
with `M_WAITOK|M_NULLOK` first; on any failure free only the new
allocations and return ENOBUFS, leaving the working pair and old MTU
intact.

## Kernel references

- sys/dev/netif/ic/if_ic.c:205-223 (no NULL check / no rollback)
- sys/dev/netif/ic/if_ic.c:358, 267+309 (the NULL-deref sinks, DF-2001)
- sys/net/if.c:2261-2292 (generic SIOCSIFMTU, bounds, privilege)
- sys/net/if_var.h:558-559 (IF_MINMTU 72 / IF_MAXMTU 65535)
- sys/kern/kern_slaballoc.c:942-950 (large alloc returns NULL with M_WAITOK)
- sys/kern/kern_slaballoc.c:1070-1072 (zone create failure → NULL)

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