# DF-3475 — `ng_callout()` silently discards the previously-armed item (leak on re-arm while pending)

## Where

`sys/netgraph7/netgraph/ng_base.c:3247-3269` (`ng_callout()`):

```c
	oitem = callout_arg(c);
	callout_reset(c, ticks, &ng_callout_trampoline, item);
	return (0);
```

`oitem` is read and then dropped on the floor. If the callout was still
pending (armed by a previous `ng_callout()` and not yet fired), the old item
is orphaned: nothing owns it, `ng_uncallout()` can no longer reach it, and
the `NG_NODE_REF`/`NG_HOOK_REF` taken for it in `ng_callout()` are never
released.

## Impact

- One leaked `struct ng_item` per re-arm-while-pending.
- Worse: the leaked item pins a **node reference** — the node can never reach
  refs==0, so `ng_unref_node()` never frees it (M_NETGRAPH_NODE leak) and the
  node type's `refs` never returns to 1, making the type permanently
  unloadable (`kldunload` returns EBUSY forever).

Severity Info: requires a node type that re-arms the same `struct callout`
via `ng_callout()` while it is still pending (an API misuse, but one the API
silently accepts — FreeBSD's ng_callout historically freed/reused `oitem`,
and the read of `oitem` here shows the intent was to handle it). In-tree
users re-arm from inside the timeout callback (safe: item already consumed)
or on fresh callouts, so there is no known in-tree trigger; filed as a
hardening/robustness defect of the core API.

## Fix (sketch, included in fix.diff)

```c
 	oitem = callout_arg(c);
 	callout_reset(c, ticks, &ng_callout_trampoline, item);
+	if (oitem != NULL && oitem != item)
+ 		NG_FREE_ITEM(oitem);	/* drop our orphaned reference */
```

with the same refs==0 caveat as DF-3474 (use `ng_free_item()` for a
never-sent item; a fired-but-not-yet-applied item must instead be left to
the queue/apply path — distinguishing those needs a flag, so the safe
minimal fix is to only free when the callout was still PENDING, which
`callout_stop()`-style return of `callout_reset` ... simplest correct check:
`if (oitem != NULL && callout_pending item was replaced)` — see fix.diff for
the conservative variant that only frees items that never entered the queue,
tracked via NGQF_FREE already being clear and refs==0).

## PoC

Skipped (Info severity — no demonstrated security impact; per audit contract
Low/Info hardening findings are not QEMU-verified). Evidence pack documents
the code path only.
