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)
PoC verification
Evidence pack
findings/poc/DF-3202 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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).
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
fixedfixed kernel rejects the 300-star name at ADD with EINVAL; apply never runs
['DF-3202/run.fixed.log']
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.
No comments yet.