β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-0664

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0664 Β· 8 files
FileTypeDescriptionSize
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
README.md readme PoC evidence pack overview
↓ download 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.

VERDICT.md verdict NOT REPRODUCED β€” cited file is dead code
↓ download raw

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:336 ngd_softc sc β€” single global softc.
  • :345 SLIST_FOREACH(tmp, &sc->head, links) in ng_device_rcvdata β€” no lock.
  • :371-373 reads/writes connection->loc and memcpy into readq β€” concurrent with ngdwrite/ngdread which also touch loc and readq.
  • :396-411 ng_device_disconnect frees readq and SLIST_REMOVEs with no synchronization against in-flight readers.
  • :518, :572, :617 β€” ngdread/ngdwrite/ngdpoll all do the same unlocked SLIST_FOREACH lookup of dev->connection.
  • No lockmgr(9), crit_enter(), spinlock, or refcount is taken on the connection object 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.c and its header) to prevent confusion, the same recommendation as DF-0663.

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_testable

n/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.