ng7 ng_tty: ngt_open() error path leaks sc when ng_name_node() fails
Summary
On ng_name_node() failure (name collision with a pre-existing 'ttyN' node), ngt_open handles the error with a bare NG_NODE_UNREF(sc->node) - but ng7 ng_unref_node() frees the node without invoking nd_shutdown when refs hit zero, and sc has not been attached yet (SET_PRIVATE runs at :221), so the kmalloc'd ngt_sc is orphaned on every failed open. v1's error path uses ng_rmnode (runs shutdown) and does not leak sc (it has the complementary bug, DF-3533). Privileged-gated ~100-byte permanent leak per failed open. Phase V skipped (Low); verdict records not_testable rationale. [VERIFIED pass2: error branch reachable on harness kernel; leak code-certain NG_NODE_UNREF frees without nd_shutdown; measurement confounded by node-lifetime mechanics]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3532 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 359 B | β raw | |
| VERDICT.md | β | 1.7 KB | β raw | |
| build.sh | β | 58 B | view raw | |
| env.txt | β | 329 B | view raw | |
| fix.diff | β | 351 B | view raw | |
| manifest.json | β | 716 B | view raw | |
| run.log | β | 370 B | view raw | |
| run.sh | β | 84 B | view raw | |
| verdict.json | β | 2.0 KB | view raw |
DF-3532 - ng7 ng_tty failed-open sc leak
Harness kernel. gcc -O -o ttyleak7 ttyleak.c; ./ttyleak7 500. Error branch reachable (syslog 'node name exists?'); quantitative leak measurement confounded - see VERDICT.md.
Kernel: DragonFly dfbsd 6.5-DEVELOPMENT #0: Sun Oct 25 20:46:48 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_NG7 x86_64 (harness kernel)
DF-3532 - VERDICT
status: inconclusive | reproduced: 0 | impact: none | confidence: likely
Partially verified, honestly inconclusive on the measurement. The ng7 error branch is REACHABLE on the harness kernel: with a colliding node name pre-created, the failed open logs 'ttyNNN: node name exists?' (the ng7 ngt_open :212-216 branch) - captured in dmesg. The leak itself is code-certain: that branch does sc->flags |= FLG_DIE; NG_NODE_UNREF(sc->node); return(error) - ng7 ng_unref_node frees the node WITHOUT invoking nd_shutdown, and NG_NODE_SET_PRIVATE only runs at :221 AFTER naming succeeds, so the kmalloc'd ngt_softc (~140B, M_NETGRAPH) is orphaned per failed open. The quantitative demonstration was confounded by harness mechanics (ng7 naming-counter state across runs made collisions intermittent; pre-created nodes must be kept hooked to survive; a 500-cycle run produced 500 SUCCESSFUL opens with live-state growth, not leaks). Privileged-gated ~140B permanent leak per failed open stands on code.
Kernel references
Evidence
run.log (dmesg 'tty500/tty501: node name exists?' + vmstat -m netgraph growth lines), ttyleak.c
Recommended fix
free sc on the naming-failure path (kfree(sc, M_NETGRAPH) after the UNREF) or route through shutdown.
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.
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
run.log (dmesg 'tty500/tty501: node name exists?' + vmstat -m netgraph growth lines), ttyleak.c
PoC changes
ttyleak.c adapted to the ng7 wire format; node-name pre-creation must keep nodes hooked to persist
Verified recommended fix
free sc on the naming-failure path (kfree(sc, M_NETGRAPH) after the UNREF) or route through shutdown.
Verdict
Partially verified, honestly inconclusive on the measurement. The ng7 error branch is REACHABLE on the harness kernel: with a colliding node name pre-created, the failed open logs 'ttyNNN: node name exists?' (the ng7 ngt_open :212-216 branch) - captured in dmesg. The leak itself is code-certain: that branch does sc->flags |= FLG_DIE; NG_NODE_UNREF(sc->node); return(error) - ng7 ng_unref_node frees the node WITHOUT invoking nd_shutdown, and NG_NODE_SET_PRIVATE only runs at :221 AFTER naming succeeds, so the kmalloc'd ngt_softc (~140B, M_NETGRAPH) is orphaned per failed open. The quantitative demonstration was confounded by harness mechanics (ng7 naming-counter state across runs made collisions intermittent; pre-created nodes must be kept hooked to survive; a 500-cycle run produced 500 SUCCESSFUL opens with live-state growth, not leaks). Privileged-gated ~140B permanent leak per failed open stands on code.
No comments yet.