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

wildCaseCmp() recurses once per '*': star-heavy rule names exhaust the devfs core thread stack

Summary

The wildcard matcher recurses per '*' ('less-optimal' branch, devfs_core.c:2902-2903) with 80-byte frames; rule names up to PATH_MAX-1 allow a few hundred nested frames inside checkname during APPLY - on the devfs core thread. Minimal PoC (300-star name, PERM cmd, one APPLY): 'Fatal double fault, rip = wildCaseCmp+6 (push %r15)'; stock-kernel threshold measured between ~60 and ~95 stars (incidental reproductions at 252 and ~95). VERIFIED. Privileged (root or jailed root via DF-3197). Fix validated (reject NAME patterns with >32 '*'s at ADD -> EINVAL).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3202 Β· 10 files
FileTypeDescriptionSize
README.md β€” 211 B ↓ raw
VERDICT.md β€” 2.1 KB ↓ raw
build.sh β€” 91 B view raw
env.txt β€” 415 B view raw
fix.diff β€” 8.6 KB view raw
panic.txt β€” 13.5 KB view raw
run.fixed.log β€” 122 B view raw
run.sh β€” 91 B view raw
star_rec.c β€” 2.0 KB view raw
verdict.json β€” 2.2 KB view raw

DF-3202 β€” wildCaseCmp() recurses once per '*' (80B frames); star-heavy rule names exhaust the devfs core thread stack. See VERDICT.md. Build: cc -static -O -o star_rec star_rec.c ; Run as root (double fault).

VERDICT.md
↓ download raw

DF-3202 β€” wildCaseCmp() unbounded recursion: stack exhaustion from star-heavy rule names

Root cause

wildCaseCmp() (sys/vfs/devfs/devfs_core.c:2875) recurses once per '*' processed β€” the "less-optimal" branch at :2902-2903:

for (i = 0; s + i < mary[d]; ++i)
    if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) ...

The compiled frame is 80 bytes (objdump: push %rbp + 5 regs + sub $0x18 + return address). A DEVFS_RULE_NAME rule whose name is a few hundred '*'s therefore recurses a few hundred frames deep inside devfs_rule_checkname() when DEVFS_RULE_APPLY walks the tree β€” on the devfs core thread β€” and exhausts the kernel stack.

Reproduced (minimal PoC, clean boot)

Rule name = 300 '*'s, DEVFS_RULE_PERM (checkname runs for NAME rules regardless of cmd), one DEVFS_RULE_APPLY:

Fatal double fault
rip = 0xffffffff8091c316        <- wildCaseCmp+6 : push %r15
panic: double fault

Incidental reproductions during this audit: 252-star name (DF-3200 control pattern) and ~95-star name (DF-3199 offset-100 pattern) β€” the threshold on this kernel is between ~60 and ~95 stars.

Fix

fix.diff: reject NAME patterns with more than 32 '*'s at rule-add time (32 x 80 B = 2.5 KB worst case; real devfs.rules patterns use a handful of wildcards). A full iterative rewrite of the matcher would also work but is more invasive.

Files

star_rec.c, build.sh, run.sh, panic.txt, fix.diff, run.fixed.log, verdict.json, manifest.json

Incidental reproductions (earlier in the session)

  • 252-star pattern (DF-3200 control rule): first crash of the session (boot.log preserved at DF-3201/panic.doublefault.2.txt).
  • ~95-star pattern (DF-3199 offset-100 rule): crashed the leak run at the same rip.

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

fixed
baseline reproduced→ patch + rebuild →patched clean

fixed kernel rejects the 300-star name at ADD with EINVAL; apply never runs

['DF-3202/run.fixed.log']
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Tue Sep 8 10:25:07 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Confirmed kernel references

Detail

Exploit chain

privileged ADD {NAME '<300 stars>', PERM} + APPLY '*' -> per-node wildCaseCmp recursion -> stack exhaustion double fault

Evidence (decisive lines)

['panic.txt: Fatal double fault rip=0xffffffff8091c316 = wildCaseCmp+6', 'run.fixed.log: ADD rejected EINVAL (star cap)']

PoC changes

none beyond compile fixes

Verified recommended fix

reject NAME patterns with more than 32 '*'s at rule-add (or make wildCaseCmp iterative)

Verdict

wildCaseCmp() recurses once per '*' (devfs_core.c:2902-2903) with 80-byte frames (objdump-verified: push %rbp + 5 regs + sub $0x18 + ret). Rule names may be up to PATH_MAX-1, so a few hundred stars = a few hundred nested frames inside devfs_rule_checkname on the devfs core thread. Minimal PoC (300-star name, PERM cmd, one APPLY): 'Fatal double fault, rip = wildCaseCmp+6 (push %r15), panic: double fault'. Incidental reproductions at 252 and ~95 stars put the stock-kernel threshold between ~60 and ~95 stars.