sys_fchown() performs VFS_ACCOUNT() ownership-transfer accounting against the cwd's mount instead of the chowned file's mount
| Field | Value |
|---|---|
| ID | DF-2670 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N |
| CWE | CWE-706 Use of Incorrectly-Resolved Name or Reference |
| File | sys/kern/vfs_syscalls.c |
| Lines | 3637 |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-08-29 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
fchown(2) passes p->p_fd->fd_ncdir.mount (the caller's
working-directory mount) to setfown(), whose VFS_ACCOUNT transfers
Β±size for old/new owner on that mount. With cwd and target file on
different mounts (cd into tmpfs /tmp, fchown an fd on /usr), the file's
mount accounting is never updated (quota bypass) and the cwd mount
accumulates phantom deltas (spurious EDQUOT for unrelated users).
Correct siblings: kern_chown() :3578 (nd->nl_nch.mount) and
kern_ftruncate() :4123 (vq_vptomp(vp)); kern_fstatfs() :1495-1496 shows
the intended f_nchandle.mount/v_mount selection.
Threat model & preconditions
Unprivileged once quotas are enabled (non-default config); stock guest wires no vfs_account β inspection-certain, untested live.
Recommended fix
Pass (fp->f_nchandle.mount ? fp->f_nchandle.mount : ((struct vnode
*)fp->f_data)->v_mount) to setfown() in sys_fchown(), mirroring
kern_fstatfs(). (Diff in findings/poc/DF-2670/README.md.)
Timeline
- 2026-08-29 Discovered during pass-2 audit of vfs_syscalls.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2670 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.2 KB | β raw | |
| verdict.json | β | 1.5 KB | view raw | |
| manifest.json | β | 500 B | view raw |
DF-2670 β sys_fchown() charges VFS_ACCOUNT() against the cwd's mount, not the file's mount
Impact (quota accounting corruption; non-default config)
fchown(2) performs its ownership-transfer accounting
(VFS_ACCOUNT(mp, o_uid, o_gid, -size) / VFS_ACCOUNT(mp, uid, gid, +size),
sys/kern/vfs_syscalls.c:3560-3561) against p->p_fd->fd_ncdir.mount β
the mount of the caller's current working directory β instead of the
mount of the file being chowned (fp->f_nchandle.mount /
vp->v_mount). When cwd and target file live on different mounts (trivial
to arrange: cd /tmp (tmpfs), fchown(fd_of_file_on_/usr)):
- the file's real mount never gets its accounting adjusted β the new owner's usage on that mount is under-counted β quota bypass;
- the cwd's mount gets phantom Β±size adjustments for uids that may not
even own bytes there β accounting corruption / spurious
EDQUOTfor unrelated users; - repeated chowns can drive a mount's accounting to arbitrary values.
Only manifests when VFS quota accounting is wired (non-default
vfs.quota_enabled + quota-enabled mount), which is why the stock guest
shows nothing β VFS_ACCOUNT is a no-op there. Certain by inspection.
Root cause (line-accurate)
if (error == 0)
error = setfown(p->p_fd->fd_ncdir.mount, /* <-- WRONG mount */
(struct vnode *)fp->f_data, uap->uid, uap->gid);
Compare the correct siblings:
* kern_chown() :3578: setfown(nd->nl_nch.mount, vp, uid, gid)
(the file's mount);
* kern_ftruncate() :4123: mp = vq_vptomp(vp) (mount of the file's
vnode).
Not verified on the guest
Same reason as DF-2669: stock mounts don't wire vfs_account, so the
mis-accounting is invisible without a quota-enabled setup; code-level
conclusion is unambiguous (three sibling call sites, two correct, one not).
Recommended fix
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ sys_fchown()
if (error == 0)
- error = setfown(p->p_fd->fd_ncdir.mount,
+ error = setfown((fp->f_nchandle.mount) ? fp->f_nchandle.mount :
+ ((struct vnode *)fp->f_data)->v_mount,
(struct vnode *)fp->f_data, uap->uid, uap->gid);
(mirrors the mp selection already used by kern_fstatfs() at :1495-1496).
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
['findings/poc/DF-2670/README.md (code excerpts + line refs + suggested fix)']
PoC changes
n/a β inspection-only finding
Verified recommended fix
Pass fp->f_nchandle.mount (falling back to vp->v_mount) instead of p->p_fd->fd_ncdir.mount to setfown() in sys_fchown().
Verdict
Certain-by-inspection wrong-mount accounting: sys_fchown() (sys/kern/vfs_syscalls.c:3637) passes p->p_fd->fd_ncdir.mount β the mount of the caller's CWD β to setfown(), whose VFS_ACCOUNT() transfers ownership accounting on that mount instead of the mount of the file being chowned (fp->f_nchandle.mount / vp->v_mount). With cwd and file on different mounts the file's quota accounting is never updated (quota bypass) while the CWD's mount gets phantom Β±size deltas (spurious EDQUOT for unrelated users). Not exercised on the guest because stock mounts do not wire vfs_account; code-level defect unambiguous (kern_chown():3578 and kern_ftruncate():4123 select the file's mount correctly).
No comments yet.