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

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.

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2670 Β· 3 files
FileTypeDescriptionSize
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 EDQUOT for 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)

sys/kern/vfs_syscalls.c:3637:

    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).

--- 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_testable
per-fix-DF-2670

Confirmed 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).