fuse_vop_nrename leaks a kmalloc'd M_TEMP buffer on every effective rename β unprivileged unbounded kernel heap exhaustion
| Field | Value |
|---|---|
| ID | DF-3030 |
| Status | new |
| Severity | Medium |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H |
| CWE | CWE-401 |
| File | sys/vfs/fuse/fuse_vnops.c |
| Lines | 1219-1227 |
| Area | vfs/fuse |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | kernleak |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
fuse_vop_nrename kmallocs newname (tncp->nc_nlen+1, M_TEMP, M_WAITOK|M_ZERO) whenever the new name differs, uses it ONLY inside fuse_dbg(), and never frees it on any exit path. Each rename(2) permanently leaks ~name-length bytes. VERIFIED: 100,000 unprivileged renames of ~264-char names leaked 19.4MB (474 β 98.1K M_TEMP allocations) in 4.6s; +40k renames β 27.0MB (linear, unbounded). Patched module: zero growth. Any unprivileged user with write permission on any FUSE mount (usermount, or a world/group-writable directory on a system fuse mount) loops renames to exhaust the kernel memory reserve β sustained ~4MB/s per process, trivially parallelized, ending in system-wide allocation failure/panic; mount survives, leak permanent. Fix: kfree after the fuse_dbg (row diff).
Timeline
- 2026-09-02 Discovered during pass-2 audit of fuse_vnops.c (GLM 5.3); leak measured linear + fix validated on rebuilt module.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3030 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fuse_daemon.c | β | 16.5 KB | view raw | |
| rename_leak.c | β | 2.0 KB | view raw | |
| build.sh | β | 130 B | view raw | |
| run.sh | β | 788 B | view raw | |
| run.log | β | 392 B | view raw | |
| fix.diff | β | 315 B | view raw | |
| fix_run.log | β | 702 B | view raw | |
| VERDICT.md | β | 1.3 KB | β raw | |
| env.txt | β | 203 B | view raw |
DF-3030 verdict β REPRODUCED (unbounded kernel heap exhaustion, unprivileged)
Root cause (path:line)
sys/vfs/fuse/fuse_vnops.c:1219-1227:
newname = kmalloc(tncp->nc_nlen + 1, M_TEMP, M_WAITOK | M_ZERO);
KKASSERT(newname);
memcpy(newname, tncp->nc_name, tncp->nc_nlen);
newname[tncp->nc_nlen] = '\0';
fuse_dbg("newname=\"%s\"\n", newname); <-- only use
No kfree(newname) anywhere in the function (verified through the out:
label). The allocation happens on every rename whose target name differs
from the source name.
Reproduction (guest DragonFly 6.5-DEVELOPMENT #0)
BEFORE: temp 474 336K (vmstat -m) su -m maxx -c "./rename_leak /mnt/fuse 50000" # 100000 renames, 4.57s AFTER: temp 98.1K 19.4M + 20000 more iterations (40000 renames): AFTER2: temp 137K 27.0M
Linear, unbounded, no ceiling: an unprivileged user loops renames (the PoC sustains ~22k renames/s; multiple processes multiply this) until the 390M kmem pool is exhausted -> allocation failures/panic system-wide.
Fix validation
fix.diff adds kfree(newname, M_TEMP) right after the debug use (the
allocation itself is only needed by fuse_dbg; kept for minimal diff).
Patched module, identical 100000-renames run: M_TEMP 474 -> 474, 336K in use
before AND after. fix_status=fixed.
Fix verification
fixedPatched module, identical 100000-renames run: M_TEMP unchanged (474 allocs, 336K in use).
fix_run.log, fix.diff
Confirmed kernel references
Detail
Exploit chain
unprivileged user with write permission on any FUSE mount loops rename(2) between two long names (~22k/s per process in the PoC; trivially parallel) -> kernel heap exhaustion -> system-wide allocation failure/panic
Evidence (decisive lines)
['run.log: temp 474/336K -> 98.1K/19.4M after 100k renames, -> 137K/27.0M after 140k', 'fix_run.log: patched 474 -> 474 after 100k renames']
PoC changes
daemon extended with a real synthetic namespace (LOOKUP/CREATE/RENAME/UNLINK bookkeeping; fuse_create_in is 16 bytes incl umask+padding - an 8-byte mirage broke name parsing) and 0777 root dir so unpriv create/rename works
Verified recommended fix
kfree(newname, M_TEMP) after its only use (or drop the allocation and print from tncp->nc_name directly).
Verdict
fuse_vop_nrename kmallocs newname (M_TEMP) on every effective rename and never frees it (only used by fuse_dbg). Verified: 100000 unprivileged renames of ~264-char names permanently leaked 19.4MB of kernel M_TEMP (474->98.1K allocations) in 4.6 seconds; +40000 renames -> 27.0MB, linear and unbounded, an unprivileged user can exhaust kernel memory. Patched module shows zero growth under the identical load.
No comments yet.