DF-2699
vfs_setpublicfs() leaks nfs_pub.np_index when MNT_EXPUBLIC is re-exported on the same mount without MNT_DELEXPORT
| Field | Value |
|---|---|
| ID | DF-2699 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-401 Missing Release of Memory |
| File | sys/kern/vfs_subr.c |
| Lines | 2272 (gate :2246-2247) |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-08-30 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
vfs_export() only frees the previous WebNFS public index when MNT_DELEXPORT is passed. Exporting MNT_EXPORTED|MNT_EXPUBLIC twice on the SAME mount passes the EBUSY gate (vfs_setpublicfs allows mp == nfs_pub.np_mount), and :2272 assigns nfs_pub.np_index = kmalloc(...) unconditionally, dropping the previous M_TEMP allocation. Repeatable kernel memory leak; root-only. (With non-default vfs.usermount=1 the FS-internal export path via args.export is also worth an upstream look — sys_mount's MNT_EXPORTED flag check does not see args.export.ex_flags.)
Recommended fix
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -2269,6 +2269,9 @@ vfs_setpublicfs(struct mount *mp, struct netexport *nep,
int namelen;
error = vn_get_namelen(rvp, &namelen);
if (error)
return (error);
+ if (nfs_pub.np_index != NULL)
+ kfree(nfs_pub.np_index, M_TEMP);
nfs_pub.np_index = kmalloc(namelen, M_TEMP, M_WAITOK);
Timeline
- 2026-08-30 Discovered during pass-2 audit of vfs_subr.c (GLM 5.3).
No comments yet.