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

nlookup_init()/retry path read the shared fd_ncdir/fd_nrdir nchandle pairs without fd_spin while sibling threads swap them β€” torn (ncp,mount) pairs and hold-after-drop race on the jail '..'-gate comparison inputs

Field Value
ID DF-2717
Status new
Severity Medium
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L
CWE CWE-362 Improper Synchronization
File sys/kern/vfs_nlookup.c
Lines 149-161, 225-242, 1380 (torn read vfs_cache.c:996-1025)
Area kern
Confidence likely
Discovered 2026-08-30
Pass 2 (GLM 5.3 second pass)
Bucket memcorrupt
Reported pending
Known CVE none
CVE match novel

Summary

Writers serialize fd_ncdir/fd_nrdir under fdp->fd_spin (kern_fchdir, kern_chdir) β€” and kern_chroot updates fd_nrdir under p_token only, so the writers are not even mutually consistent. The nlookup reader side takes no lock at all: nlookup_init caches nl_basench and immediately cache_copy()s it (a non-atomic two-word load then _cache_hold on the loaded ncp), nlookup_init_at likewise, and every generation-mismatch retry re-dereferences nl_basench after an arbitrarily long walk. Under x86 TSO a chdir/fchdir storm from a sibling thread (fully unprivileged) can interleave to give the reader (old ncp, new mount) β€” a mismatched handle whose mount half flows into the root/jail '..'-gate equality check (confinement is solely mount+ncp equality) β€” or, in the tighter corner where the old cwd ncp is simultaneously being torn out of the namecache topology, a _cache_hold on an ncp whose last ref was just dropped β€” a use-after-free-grade refcount corruption. An established reader protocol exists (checkdirs takes fd_spin shared); nlookup is the hot path that omits it.

Threat model & preconditions

Unprivileged multi-threaded local process: thread A in path lookup while thread B hammers chdir/fchdir. Realistic impact: correctness anomalies/DoS-class misbehavior with a speculative jail-gate-bypass ceiling. Not guest-verified (two-adjacent-loads window; no deterministic oracle without instrumentation) β€” stands on the static protocol violation.

Snapshot the pairs under the existing lock: take spin_lock_shared(&p->p_fd->fd_spin) around the cache_copy in nlookup_init/nlookup_init_at, make kern_chroot update fd_nrdir under fd_spin like chdir/fchdir already do, and stop re-reading nl_basench on retry (use the init-time snapshot or re-read under the spin).

Timeline

  • 2026-08-30 Discovered during pass-2 audit of vfs_nlookup.c (GLM 5.3).

Discussion (0)

No comments yet.