โฌข DragonFlyBSD Kernel Audit
โ† dashboard
DF-0002

sys_fhopen returns spurious success (fd 0) on VREG-without-VM-object invariant violation

Field Value
ID DF-0002
Status new
Severity Info
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:N
CWE CWE-388 7PK - Errors
File sys/kern/vfs_syscalls.c
Lines 4933-4938
Area kern
Confidence certain
Discovered 2026-06-29
Reported pending

Summary

In sys_fhopen, when VOP_OPEN succeeds for a VREG vnode that unexpectedly has no VM object, the code branches to the error-cleanup label without first setting error. Because error is still 0 from the successful VOP_OPEN, the syscall returns 0 (success) to the caller while the result fd (sysmsg_result, initialized to 0 at the syscall entry) is never assigned a real descriptor and the reserved slot is freed. This is a correctness bug, reported as Info because fhopen is gated by SYSCAP_RESTRICTEDROOT (root-only).

Root cause

sys/kern/vfs_syscalls.c:4933-4938:

if (vp->v_type == VREG && vp->v_object == NULL) {
    kprintf("fhopen: regular file did not have VM object: %p\n", vp);
    goto bad_drop;          /* error is still 0 here from VOP_OPEN */
}

The bad_drop path (4986-4988) clears the reserved fd slot (fsetfd(fdp, NULL, indx)) and fdrop()s fp, then falls into bad (vput(vp)) and done (mount_drop(mp)), finally return (error); with error == 0. sysmsg->sysmsg_result is only written on the true success path at line 4981, so it retains the syscall-entry default of 0. The caller therefore sees "success, fd 0" (its own stdin) even though no descriptor was allocated for the fhopen result.

Threat model & preconditions

  • Attacker position: root-equivalent only (caps_priv_check_td(td, SYSCAP_RESTRICTEDROOT) at sys/kern/vfs_syscalls.c:4832).
  • Privileges gained or impact: none (no privilege-boundary crossing). Practical effect is limited to caller confusion (operating on fd 0 instead of a new fd).
  • Required config or capabilities: root. Trigger requires a VREG vnode whose v_object is still NULL after a successful VOP_OPEN, i.e. an internal FS invariant violation (e.g. a buggy/out-of-tree/fuse filesystem).
  • Reachability: fhopen(2) on such a vnode. On normal filesystems the invariant holds and the path is unreachable.

Proof of concept

PoC source: findings/poc/DF-0002/fhopen_spur.c

Build & run

cc -o fhopen_spur findings/poc/DF-0002/fhopen_spur.c
./fhopen_spur /some/target   # as root, on a filesystem that violates the invariant

Expected output

fhopen returned 0 (success)
BUG: fd 0 is stdin, no real descriptor was allocated

(Fixed: fhopen failed as expected: Invalid argument.)

Impact

None security-wise โ€” root-only. Reported for correctness/hardening: an FS invariant violation should not present itself to userspace as a silent success returning a recycled descriptor.

Set error before the goto.

--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -4933,6 +4933,7 @@
            kprintf("fhopen: regular file did not "
                "have VM object: %p\n",
                vp);
+           error = EINVAL;
            goto bad_drop;
        }

References

Timeline

  • 2026-06-29 Discovered during automated file-by-file audit of sys/kern/vfs_syscalls.c.
  • pending Reported to DragonFlyBSD security contact.