# DF-3526 — netgraph7 ng_iface: first node creation panics in kfree(NULL)
#          (bcopy() UB makes GCC drop the NULL guard on ng_iface_units)

## What

Creating the first `netgraph7` ng_iface node panics the kernel deterministically:

    panic: trying to free NULL pointer
    _kfree() at _kfree+0x558
    ng_iface_constructor() at ng_iface_constructor+0x312
    ng_make_node() -> ng_apply_item() -> ngthread()

`ng_iface_get_unit()` (sys/netgraph7/iface/ng_iface.c:292-303) passes the
initially-NULL `ng_iface_units` to `bcopy()`. `sys/systm.h` maps bcopy onto
`__builtin_memmove` and documents that GCC may then assume the operand
non-NULL and delete later NULL tests — the `if (ng_iface_units != NULL)`
guard at :300 is dead code in the compiled module, so the first
array-growth (i.e. the FIRST node ever created) calls `kfree(NULL)`, which
is an unconditional `panic()` (sys/kern/kern_slaballoc.c:1406-1407).
Production (non-INVARIANTS) kernels are equally affected.

This is the ng7 twin of v1 DF-3485 (sys/netgraph/iface/ng_iface.c:290-295):
same code pattern, separate file/module (ng7 module set), separate fix.

NOTE: the OTHER half of the v1 lead does NOT carry over — ng7 does NOT
share DF-3486 (if_attach from netisr control path). ng7 funnels every
first-hop control message to the dedicated `ngthread` via
`lwkt_sendmsg(ng_cpuport(0))` (ng_base.c:1956-1961), a kernel-thread
context in which `if_attach()` is legal: with only the bcopy fix applied,
the full ng_iface lifecycle (mkpeer -> ng0 -> GET_IFNAME -> shutdown)
succeeds, 20/20 + a parallel pair. See VERDICT.md.

## Trigger privilege

ROOT ONLY (verified live): ng7 ng_socket control sockets require
`caps_priv_check(SYSCAP_RESTRICTEDROOT)` (sys/netgraph7/socket/ng_socket.c:182-185);
uid 1001 gets EPERM (unpriv_check.txt). Severity Low (privileged DoS).

## Build / Run (in-guest, root)

    # 1. build ng7 modules (netgraph core, ng_socket, ng_iface)
    cd /usr/src/sys/netgraph7/netgraph  && make
    cd ../socket                        && make
    cd ../iface                         && make
    cc -O2 -o iface_con iface_con.c

    # 2. load and fire
    kldload /usr/src/sys/netgraph7/netgraph/netgraph.ko
    kldload /usr/src/sys/netgraph7/socket/ng_socket.ko
    kldload /usr/src/sys/netgraph7/iface/ng_iface.ko
    ./iface_con create          # -> instant panic, guest dead

## Expected

Stock modules: `panic: trying to free NULL pointer` at
ng_iface_constructor+0x312 (the unguarded kfree; see panic.txt,
disasm.stock.txt + reloc.stock.txt: +0xd76 memmove flows into
+0xdce _kfree with no NULL test). Reproduced 3/3 on independent
boots (run.log, run.2.log, run.3.log).

With fix.diff (module rebuild only): creation succeeds
(disasm.fix26.txt: real `test/je` before kfree), `ifname=ng0`,
clean shutdown, 20/20 lifecycle + parallel stress clean (fix_run.log).

## Fix validation

    cd /usr/src && patch -p1 < fix.diff   # bcopy call guarded by units_len>0
    (rebuild ng_iface module only, reload, run stress.sh)
