# DF-3499 — ng_fec_get_unit: bcopy(NULL,…,0) elides the NULL guard → unconditional kfree(NULL) panic on first node creation

- File: `sys/netgraph/fec/ng_fec.c` (v1 netgraph, LIVE module `ng_fec.ko`)
- Lines: 276-283 (`ng_fec_get_unit`)
- Severity: Medium (deterministic kernel panic / local DoS; trigger = one
  netgraph control message, which requires the netgraph control socket
  (root-only on stock DFly via `caps_priv_check(SYSCAP_RESTRICTEDROOT)`))
- Bucket: base:netgraph (DoS)

## Build

In-guest, stock module (no patches):

    cd /usr/src/sys/netgraph/fec && make

## Run

    kldload ng_socket
    kldload /usr/src/sys/netgraph/fec/ng_fec.ko
    ngctl mkpeer fec c0 c1        # any fec node creation

## Expected

Immediate kernel panic:

    panic: trying to free NULL pointer
    _kfree() at _kfree+0x558
    _kfree() at _kfree+0x558
    ng_fec_constructor() at ng_fec_constructor+0x39e
    ng_mkpeer() ...

The module is unusable at HEAD: the very first `ng_fec_get_unit()` call takes
the "extend array" branch with `ng_fec_units == NULL` / `ng_fec_units_len == 0`
and executes `bcopy(NULL, newarray, 0)`. `bcopy` is `__builtin_memmove`
(sys/sys/systm.h:262-265), whose header comment states the compiler "assumes
that (to) and (from) cannot be NULL (even when (len) might be 0), and will
optimize-out later NULL tests" — the explicit `if (ng_fec_units != NULL)`
guard at ng_fec.c:280 is optimized out of the shipped object code (verified by
disassembly: `mov %r9,%rdi; call kfree` with no test/branch; DWARF maps the
call to ng_fec.c:281), so `kfree(NULL)` executes and panics.

## Root cause chain

1. `ng_fec.c:266-267` loop exits immediately (`ng_fec_units_len == 0`),
   `index == ng_fec_units_len` → extend branch.
2. `ng_fec.c:276` `bcopy(ng_fec_units /* NULL */, newarray, 0)` — UB per
   DFly's own bcopy macro documentation.
3. `ng_fec.c:280-281` guard elided by the compiler → `kfree(NULL)`.
4. `sys/kern/kern_slaballoc.c:1406-1407` → `panic("trying to free NULL pointer")`.

## Fix

Guard the bcopy itself (see fix.diff). Validated in-guest: with the guard the
constructor proceeds past `ng_fec_get_unit` (creation then trips the separate,
pre-existing netisr/ifnet_lock defect filed as DF-3500; driven from thread
context, node creation fully succeeds with this fix applied).
