update_mp() re-executed on every remount with fspec re-opens all four iconv handles without closing the previous ones β unbounded kernel-heap handle leak via mount -u loop (partial-failure remounts leak the replaced handles too)
Summary
update_mp() opens pm_w2u/pm_u2w/pm_u2d/pm_d2u via msdosfs_iconv->open (:119-132) whenever MSDOSFSMNT_KICONV is set (sticky: pm_flags |= on every call, :113). msdosfs_mount reaches update_mp on the MNT_UPDATE path whenever args.fspec != NULL and matches pm_devvp (:258-279) - each 'mount -u -o <kiconv opts>' re-opens four handles, overwrites the pm_* pointers and leaks the old four (each a kernel iconv_converter allocation plus charset tables). N iterations = 4N leaked handles until unmount (which closes only the last four). Partial-failure remounts (:121-132 return without cleanup) leak the already-replaced handles as well. Privileged mount owner (root; or usermount owner) leaking ~4 converter handles per remount - kmem exhaustion over time; no memory corruption. Phase V skipped (Low). Fix: close existing handles before re-opening. [VERIFIED pass2: update_mp path live-reached 1187 prints but raw-syscall remount fails ENOENT in kernel libiconv on this guest; leak code-certain]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3130 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| remount_leak.c | β | 2.1 KB | view raw | |
| run.log | β | 874 B | view raw | |
| README.md | β | 661 B | β raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| build.sh | β | 154 B | view raw | |
| run.sh | β | 181 B | view raw | |
| manifest.json | β | 748 B | view raw | |
| verdict.json | β | 2.0 KB | view raw | |
| fix.diff | β | 941 B | view raw | |
| env.txt | β | 272 B | view raw |
DF-3130 -- verification pack
Finding: update_mp re-executed on remount leaks four iconv handles per mount -u
Status: not_reproduced / impact leak / confidence certain
What was run
guest: cc -O -lkiconv -o remount_leak remount_leak.c
How to reproduce
guest: mount_msdos -o ro -L zh_CN.GB18030 -D GB18030 /dev/vn0 /mnt && ./remount_leak /dev/vn0 /mnt 40
Expected
code path reached (kernel prints local/dos per attempt); on this guest each re-open fails ENOENT in kernel libiconv so no leak is observable
See VERDICT.md for the full narrative and verdict.json for the persisted machine verdict. Artifacts: remount_leak.c, run.log.
DF-3130 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
The leak is code-certain (update_mp re-opens all four iconv handles on every MNT_UPDATE with fspec and overwrites pm_w2u/pm_u2w/pm_u2d/pm_d2u without closing, and pm_flags keeps MSDOSFSMNT_KICONV sticky so even KICONV-less updates re-open) and the path is confirmed live: 1187 kernel update_mp prints during the attempt loop. But on this guest every re-open of the previously-registered pairs fails with ENOENT inside kernel libiconv when invoked from a raw mount(2) MNT_UPDATE (the CLI pre-registers conversion tables via kiconv(3) at initial mount and no CLI path expresses a kiconv remount), so no handle churn occurs to observe and the vmstat -m iconv counters stay flat. Attempt harness and full logs retained; fix compile-validated.
Kernel references
Exploit chain
(none: availability/correctness finding; no privilege chain)
Fix
close existing handles before re-opening
See fix.diff in this directory (git-apply-able against the read-only sys/ tree; applied only inside the disposable verification guest).
Reproduction
build: guest: cc -O -lkiconv -o remount_leak remount_leak.c
run: guest: mount_msdos -o ro -L zh_CN.GB18030 -D GB18030 /dev/vn0 /mnt && ./remount_leak /dev/vn0 /mnt 40
expected: code path reached (kernel prints local/dos per attempt); on this guest each re-open fails ENOENT in kernel libiconv so no leak is observable
Notes on the PoC (what changed vs the finding sketch)
three iterations: struct msdosfs_args must come from
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_testableConfirmed kernel references
Detail
Evidence (decisive lines)
run.log (40+200 remount attempts, ENOENT, 1187 update_mp prints, iconv counters flat), remount_leak.c (uses the real <vfs/msdosfs/msdosfsmount.h> struct)
PoC changes
three iterations: struct msdosfs_args must come from
Verified recommended fix
close existing handles before re-opening
Verdict
The leak is code-certain (update_mp re-opens all four iconv handles on every MNT_UPDATE with fspec and overwrites pm_w2u/pm_u2w/pm_u2d/pm_d2u without closing, and pm_flags keeps MSDOSFSMNT_KICONV sticky so even KICONV-less updates re-open) and the path is confirmed live: 1187 kernel update_mp prints during the attempt loop. But on this guest every re-open of the previously-registered pairs fails with ENOENT inside kernel libiconv when invoked from a raw mount(2) MNT_UPDATE (the CLI pre-registers conversion tables via kiconv(3) at initial mount and no CLI path expresses a kiconv remount), so no handle churn occurs to observe and the vmstat -m iconv counters stay flat. Attempt harness and full logs retained; fix compile-validated.
No comments yet.