Missing locking enables TOCTOU/UAF races across all device entry points
Summary
Entire file uses single global softc with SLIST of connections NO mutex. All 6 entry points (ngdread :518 ngdwrite :572 ngdioctl :464 ngdpoll :617 ngdopen ngdclose) do unlocked SLIST_FOREACH to map dev->connection. Netgraph callbacks (rcvdata :345 disconnect :396 newhook :247) mutate same list+per-conn state no sync. Concurrent readers race on loc: both read loc both subtract amnt second memcpy(readq,readq+amnt,loc-amnt) :532 underflows if loc decremented. rcvdata :371 reads loc+m_len while ngdwrite writes loc no lock. No cdevsw entry takes ref on connection so concurrent disconnect (frees readq) racing in-flight ngdread = UAF.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0664 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | readme | PoC evidence pack overview | 1.1 KB | β raw |
| VERDICT.md | verdict | NOT REPRODUCED β cited file is dead code | 3.2 KB | β raw |
| build.sh | build-script | no source to build; prints dead-code evidence | 400 B | view raw |
| run.sh | run-script | re-prints conf/files exclusion + netgraph7 rewrite | 422 B | view raw |
| env.txt | environment | host uname + conf/files grep | 402 B | view raw |
| fix.diff | suggested-fix | delete dead sys/netgraph/ng_device.c (git apply --check OK) | 15.0 KB | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0664 β PoC evidence pack
Summary
- File:
sys/netgraph/ng_device.c(OLD netgraph v0 device) - Claim: Missing locking across all 6 cdevsw entry points enables TOCTOU/UAF.
Verdict
NOT REPRODUCED on this kernel β cited file is dead code (not in
sys/conf/files; superseded by sys/netgraph7/ng_device.c which has
proper locking). Same dead-code conclusion as DF-0663. See VERDICT.md.
How to "reproduce" (the source-level analysis only)
No build or run is needed: the cited file is not compiled, so there is
no live binary to run against. The verify_dead_code.sh script just
re-confirms the conf/files exclusion + absence from the running kernel's
symbol table + absence of a loadable module.
./verify_dead_code.sh # prints the three negative checks
Environment
See env.txt for the guest uname, kldstat, and the conf/files grep.
Fix
fix.diff deletes the dead sys/netgraph/ng_device.c. This supersedes
the finding's source-level locking proposal β patching a file that is
not compiled in buys nothing; the netgraph7 rewrite has none of these
bugs.
DF-0664 β VERDICT
Verdict: NOT REPRODUCED on this kernel β cited file is DEAD CODE (not built)
The missing-locking / TOCTOU / UAF claims against
sys/netgraph/ng_device.c are real at the source level (the file
does use a global softc + SLIST with no mutex; the cdevsw entry points
do unlocked SLIST_FOREACH; rcvdata/disconnect mutate the list
concurrently with readers β verbatim from the cited lines). However,
the cited file is not built by any standard kernel configuration or
loadable module on DragonFly master:
$ grep "ng_device" sys/conf/files netgraph7/ng_device.c optional netgraph7_device
Only the rewritten sys/netgraph7/ng_device.c is registered (under
optional netgraph7_device); it uses priv_p / IF queues with proper
locking and has none of the cited bugs. The OLD sys/netgraph/ng_device.c
is retained as historical dead code and is never compiled.
Verified on the running guest (#0 build, 6.5-DEVELOPMENT):
- nm /boot/kernel/kernel | grep ngdwrite β no matches
- ls /boot/kernel/ | grep ng_device β no matches
- kldstat β no ng_device module loaded; none exists at /boot/kernel/
This is the same dead-code situation already established for DF-0663 (SLIST_REMOVE-on-never-inserted-element), which was verified against the same file with the same conclusion.
Mechanism (cited line-by-line; would be real if compiled)
sys/netgraph/ng_device.c:336ngd_softc scβ single global softc.:345SLIST_FOREACH(tmp, &sc->head, links)inng_device_rcvdataβ no lock.:371-373reads/writesconnection->locand memcpy intoreadqβ concurrent withngdwrite/ngdreadwhich also touchlocandreadq.:396-411ng_device_disconnectfreesreadqandSLIST_REMOVEs with no synchronization against in-flight readers.:518,:572,:617βngdread/ngdwrite/ngdpollall do the same unlockedSLIST_FOREACHlookup ofdev->connection.- No
lockmgr(9),crit_enter(),spinlock, or refcount is taken on theconnectionobject anywhere in the file.
If this file were compiled in, concurrent read()/disconnect() (or
rcvdata/ngdread) racing on the same hook could UAF the readq
buffer or underflow connection->loc β corruption/panic.
Why the live kernel cannot trigger this
The file is not registered in sys/conf/files. To make it live, an
administrator would have to manually add a line such as
netgraph/ng_device.c optional netgraph_device and rebuild the kernel
β something no DragonFly release has shipped in many years (netgraph7
superseded netgraph v0). The active netgraph7/ng_device.c rewrite
uses priv_p and per-connection locks.
Privilege / threat model
- Latent dead-code bug, not exploitable on stock DragonFly.
- The realistic recommendation is to delete the dead file
(
sys/netgraph/ng_device.cand its header) to prevent confusion, the same recommendation as DF-0663.
Recommended fix
Delete the dead file (preferred), or if kept for historical reference,
add proper locking + connection refcounts. The bundled fix.diff
deletes the file. This supersedes the finding's source-level
locking proposal (which would patch a file that is not compiled in).
Fix verification
not_testablen/a
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Dead code. sys/netgraph/ng_device.c not in conf/files. Netgraph7 rewrite is the live one. Same as DF-0663.
No comments yet.