# DF-3534 — VERDICT

**REPRODUCED (leak, certain).** Discovered during the DF-3531 Phase V when
the post-fix node counts refused to go flat: a refcount ledger
(instrumented ng_unref_node + inlined _NG_NODE_REF with return-address
tagging) showed the tty node acquiring 9 refs and releasing only 8 in a
single connect+data cycle, with the orphan being the creation-time
reference — and isolation runs then proved the leak needs nothing but a
ldisc install/remove.

## Mechanism

ng7 `ng_rmnode()` (ng_base.c:686-751) unrefs only its own extra reference
when the type has a `shutdown` method; the constructor ref is the
shutdown method's job (ng_pred1.c:351 does exactly this).  ng7
ngt_shutdown (tty/ng_tty.c:553-571) never does `NG_NODE_UNREF(node)` →
after ngt_close the node refcount parks at 1 forever.

Ledger excerpt (1 cycle, node 0xfffff8004f1e87f0; full trace in the DF-3531
verification session): 9 NGREF acquisitions (creation via
ngt_open→ng_make_node_common; hook; timer items; connect-path noderef;
rmnode extra; …) vs 8 NGUNREF releases — last observed state `refs=1`,
never freed.  Socket nodes in the same cycles reach `-> FREED` — only the
tty nodes strand.

## Reproduction numbers

Stock-equivalent behavior (kernel #1 + layer-2 module, i.e. the DF-3531
item leak already neutralized — see isolation.log):

    nodd 500:     netgraph_node 3 -> 503    (+1/cycle, no hook/data/timer)
    nodata 500:   -> 1003                   (+1/cycle)
    socksock 500: -> 1003                   (FLAT — generic path clean)
    full 500:     -> 1.47K                  (+1/cycle)

On the fully stock kernel/module the effect is the same +1 node/cycle
stacked under DF-3531's item leak (baseline run.log of DF-3531:
netgraph_node 2 → 1.96K after 2000 stall cycles).

## Fix validation

fix.diff = 2 lines (SET_PRIVATE(NULL) + NG_NODE_UNREF) in ngt_shutdown,
module rebuild only.  Result (fix_validation.log, kernel #1 + layer-2 +
this fix):

    nodd 500:                 nodes 2 -> 2   (FLAT)
    stall-close 2000 x2:      nodes 2 -> 2 -> 2 (FLAT), items 9 in-use flat
    netgraph_hook in-use 0 throughout

The patched state later panicked during DF-3531's drain-mode stress with
`memory chunk already free` — that is the DF-3531 layer-1/layer-2
close-vs-fire race (double-free of an in-flight timer item), NOT this
fix: nodd-mode (no timer at all) ran clean and flat, and the same panic
signature was reproduced on a build without the ngt_shutdown change.

## Environment

Same guest/session as DF-3531 (see ../DF-3531/env.txt).

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