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

msdosfs_sync() never initializes scaninfo.waitfor β€” uninitialized kernel-stack read gates metadata flushing: sync(2)/umount can silently skip fsync of dirty denodes depending on stack garbage's MNT_LAZY bit (DF-specific regression; NetBSD sets ctx.waitfor, FreeBSD passes waitfor directly)

Summary

struct scaninfo {rescan, allerror, waitfor} (:740-744) is passed to vmntvnodescan, but msdosfs_sync only sets allerror and rescan (:804-805) - the waitfor = waitfor assignment was lost in DFly's vmntvnodescan port. msdosfs_sync_scan then reads info->waitfor (:839) in the skip condition '(RB_EMPTY(dirty) || (info->waitfor & MNT_LAZY))': when the garbage bit is set, denodes with de_flag metadata pending but no dirty buffers are skipped by a forced sync - the very vnodes sync(2)/umount(2) must flush. NetBSD's equivalent sets ctx.waitfor; FreeBSD's inline loop uses waitfor directly. Uninit value never copied to userspace (no leak); impact is silent metadata-sync skipping (data-integrity). Static proof (assignment provably absent, read provable); Phase V skipped (Low). Fix: one line (scaninfo.waitfor = waitfor). [VERIFIED pass2: uninit waitfor read gates metadata flushing with provably-absent assignment; one-line fix compile-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3129 Β· 9 files
FileTypeDescriptionSize
fix.diff β€” 421 B view raw
README.md β€” 374 B ↓ raw
VERDICT.md β€” 1.5 KB ↓ raw
build.sh β€” 106 B view raw
run.sh β€” 88 B view raw
manifest.json β€” 447 B view raw
verdict.json β€” 1.3 KB view raw
fix.diff β€” 421 B view raw
env.txt β€” 272 B view raw

DF-3129 -- verification pack

Finding: msdosfs_sync never initializes scaninfo.waitfor (uninit read gates flushing)

Status: not_reproduced / impact corruption / confidence certain

What was run

n/a

How to reproduce

n/a

Expected

n/a

See VERDICT.md for the full narrative and verdict.json for the persisted machine verdict. Artifacts: fix.diff.

VERDICT.md
↓ download raw

DF-3129 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

Static proof is airtight: struct scaninfo.waitfor is never assigned anywhere in msdosfs_sync (only allerror and rescan are set) while msdosfs_sync_scan reads info->waitfor in the skip condition (RB_EMPTY(dirty) || (info->waitfor & MNT_LAZY)), so a forced sync skips denodes with pending metadata whenever the garbage bit matches MNT_LAZY. The effect is silent metadata-integrity loss with no runtime signature, and the uninit value never reaches userspace, so dynamic observation is not meaningful; the one-line fix is compile-validated in the combined build.

Kernel references

Exploit chain

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

Fix

scaninfo.waitfor = waitfor

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

Reproduction

build: n/a

run: n/a

expected: n/a

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

(none)

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-3129

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md walk over msdosfs_vfsops.c:740-839 showing the assignment provably absent (NetBSD sets ctx.waitfor, FreeBSD uses waitfor directly)

Verified recommended fix

scaninfo.waitfor = waitfor

Verdict

Static proof is airtight: struct scaninfo.waitfor is never assigned anywhere in msdosfs_sync (only allerror and rescan are set) while msdosfs_sync_scan reads info->waitfor in the skip condition (RB_EMPTY(dirty) || (info->waitfor & MNT_LAZY)), so a forced sync skips denodes with pending metadata whenever the garbage bit matches MNT_LAZY. The effect is silent metadata-integrity loss with no runtime signature, and the uninit value never reaches userspace, so dynamic observation is not meaningful; the one-line fix is compile-validated in the combined build.