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

Unconditional kprintf() log flood in mbnambuf_write() from crafted β€” or merely long-LFN β€” FAT directories: unbounded kernel console/msgbuf spam from unprivileged directory churn

Summary

mbnambuf_write() emits two UNCONDITIONAL kprintf()s (:1038 'non-decreasing id', :1048 'file name length too large') on every rejected LFN slot. Upstream FreeBSD gates both behind #ifdef MSDOSFS_DEBUG; DragonFly removed the guard. Each directory scan re-prints once per offending entry: msdosfs_lookup (lookup.c:274) for every open/stat/exec path walk, and msdosfs_readdir (vnops.c:1665) for every getdents. Trigger (a) crafted image: N repeated LFN slot triples -> N 'non-decreasing id' lines per scan; 10 full 13-char LFN slots -> 'file name length 130 too large'. Trigger (b) NO crafted data: a stock Windows-created volume legitimately holds LFNs up to 255 UCS-2 chars, but :1047 caps reassembly at 127 BYTES, so every lookup/getdents of such a directory prints per slot. An unpriv user looping 'ls /mnt/dir' floods the msgbuf/dmesg and the serial console (serialized, slow) without bound, and can grow /var unboundedly where console output is logged - a persistent, rate-unlimited kernel-side resource drain driven purely by on-disk metadata. The user cannot be rate-limited by the kernel. Impact ceiling: unbounded dmesg/console/log spam, console-lock contention stalls, /var exhaustion - availability nuisance, no memory corruption, no info leak. Unverified (Low/log-spam per contract); repro sketch in summary. Fix: gate both prints behind MSDOSFS_DEBUG exactly as upstream (behavioral returns unchanged). [VERIFIED pass2: reproduced - 1312 unconditional kernel log lines per 100 unpriv scans echoed on serial console; fix A/B delta 0]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3115 Β· 13 files
FileTypeDescriptionSize
craft_lfn.py β€” 5.3 KB view raw
run_guest.sh β€” 1.1 KB view raw
run.log β€” 866 B view raw
console_flood_excerpt.log β€” 70.2 KB view raw
README.md β€” 677 B ↓ raw
VERDICT.md β€” 2.2 KB ↓ raw
build.sh β€” 140 B view raw
run.sh β€” 208 B view raw
manifest.json β€” 860 B view raw
verdict.json β€” 2.2 KB view raw
fix.diff β€” 812 B view raw
env.txt β€” 272 B view raw
compile_validation.txt β€” 1.8 KB view raw

DF-3115 -- verification pack

Finding: unconditional kprintf log flood in mbnambuf_write from crafted/long LFN directories

Status: reproduced / impact denial_of_service / confidence certain

What was run

host: python3 craft_lfn.py out.img A|B

How to reproduce

guest: vnconfig -c -S 2m /dev/vn0 img && mount_msdos -o ro /dev/vn0 /mnt && su -m nobody -c 100x ls/stat loop, count dmesg lines

Expected

1212 non-decreasing lines + 100 too-large lines per 100 passes; console log floods

See VERDICT.md for the full narrative and verdict.json for the persisted machine verdict. Artifacts: craft_lfn.py, run_guest.sh, run.log, console_flood_excerpt.log.

VERDICT.md
↓ download raw

DF-3115 verification

Kernel: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Bottom line

Unprivileged ls/stat churn on a crafted FAT directory drives the two unconditional kprintfs in mbnambuf_write at unbounded rate: pattern A (two id-1 LFN slots per group, 12 groups) printed 1212 non-decreasing-id lines across 100 unprivileged ls+stat passes; pattern B (10 full 13-char LFN slots, 130 bytes reassembled) printed 100 file-name-length-too-large lines across 100 ls passes. The serial console echoes every line (1312 msdosfs lines captured on the console log during the run), i.e. an unprivileged user floods msgbuf and any logging console with no kernel-side rate limit; a stock Windows LFN of 255 UCS-2 chars hits the 127-byte cap on ordinary directories. Availability only.

Kernel references

Exploit chain

(none: availability/correctness finding; no privilege chain)

Fix

gate both prints behind MSDOSFS_DEBUG exactly as upstream FreeBSD; combined fixed kernel: same workload emits zero lines

See fix.diff in this directory (git-apply-able against the read-only sys/ tree; applied only inside the disposable verification guest).

Reproduction

build: host: python3 craft_lfn.py out.img A|B

run: guest: vnconfig -c -S 2m /dev/vn0 img && mount_msdos -o ro /dev/vn0 /mnt && su -m nobody -c 100x ls/stat loop, count dmesg lines

expected: 1212 non-decreasing lines + 100 too-large lines per 100 passes; console log floods

Notes on the PoC (what changed vs the finding sketch)

first craft attempt printed nothing: win2unixfn only reaches mbnambuf_write when the highest-ordinal LFN slot carries WIN_LAST (0x40) so the checksum re-establishes; craft_lfn.py now sets it and a matching chksum byte

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

not_testable
↓ fix.diffper-fix-DF-3115

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log (both patterns, before/after msgbuf counts), console_flood_excerpt.log (serial console echo of 1312 lines), craft_lfn.py (WIN_LAST + chksum details needed to reach mbnambuf_write)

PoC changes

first craft attempt printed nothing: win2unixfn only reaches mbnambuf_write when the highest-ordinal LFN slot carries WIN_LAST (0x40) so the checksum re-establishes; craft_lfn.py now sets it and a matching chksum byte

Verified recommended fix

gate both prints behind MSDOSFS_DEBUG exactly as upstream FreeBSD; combined fixed kernel: same workload emits zero lines

Verdict

Unprivileged ls/stat churn on a crafted FAT directory drives the two unconditional kprintfs in mbnambuf_write at unbounded rate: pattern A (two id-1 LFN slots per group, 12 groups) printed 1212 non-decreasing-id lines across 100 unprivileged ls+stat passes; pattern B (10 full 13-char LFN slots, 130 bytes reassembled) printed 100 file-name-length-too-large lines across 100 ls passes. The serial console echoes every line (1312 msdosfs lines captured on the console log during the run), i.e. an unprivileged user floods msgbuf and any logging console with no kernel-side rate limit; a stock Windows LFN of 255 UCS-2 chars hits the 127-byte cap on ordinary directories. Availability only.