# DF-2703 — vop_* dispatch wrappers pass partially-uninitialized stack argument structures

File: sys/kern/vfs_vopops.c (pass 2, GLM 5.3)
Severity: Low (hardening / latent) — Confidence: certain (by inspection + scripted struct/assignment diff)

## What

Three VOP dispatch wrappers in sys/kern/vfs_vopops.c build the `struct vop_*_args`
on the kernel stack and forget to initialize every field of the ops structure:

| wrapper | missing field | struct definition | type |
|---|---|---|---|
| `vop_mountctl()` (sys/kern/vfs_vopops.c:1292-1315, assignments at 1300-1308) | `ap.a_vp` | sys/sys/vfsops.h:433-443 | `struct vnode *` — **uninitialized kernel-stack pointer** |
| `vop_markatime()` (sys/kern/vfs_vopops.c:1320-1337) | `ap.a_op` | sys/sys/vfsops.h:445-450 | `int` |
| `vop_allocate()` (sys/kern/vfs_vopops.c:1342-1360) | `ap.a_op` | sys/sys/vfsops.h:452-458 | `int` |

The wrapper takes `vp` as a parameter and uses it only for `VFS_MPLOCK(vp->v_mount)`
(vfs_vopops.c:1310) — it never stores it into `ap.a_vp`. Every other wrapper in the
file initializes 100% of its args-struct fields (verified by scripted diff of
`ap.a_*` assignments vs. struct definitions in sys/sys/vfsops.h — only these three
fail, apart from the intentionally vestigial `a_head.a_reserved[4]`).

## Why it matters

The uninitialized bytes are *kernel stack garbage* passed by pointer into every
filesystem's `vop_mountctl` / `vop_markatime` / `vop_allocate` handler. All handlers
in the current tree derive what they need from `ap->a_head.a_ops->head.vv_mount`
(e.g. vop_stdmountctl sys/kern/vfs_default.c:1301-1307, hammer2_vop_mountctl
sys/vfs/hammer2/hammer2_vnops.c:2278-2299, tmpfs_mountctl:1879-1909,
journal_mountctl sys/kern/vfs_jops.c:154-231) and never read `a_vp`/`a_op`, so the
bug is **latent today**: no current dereference of the garbage pointer. It is a
trap for any future handler (or out-of-tree/filesystem-module handler) that does
the natural thing (`ap->a_vp`), which would be a wild-pointer dereference with
attacker-influenced stack contents. Reachability of vop_mountctl is root-gated
(sys_mountctl requires SYSCAP_RESTRICTEDROOT, sys/kern/vfs_syscalls.c:1277-1283);
markatime/allocate are reachable by ordinary users.

## Recommended fix

```diff
--- a/sys/kern/vfs_vopops.c
+++ b/sys/kern/vfs_vopops.c
@@ vop_mountctl(...)
 	ap.a_head.a_desc = &vop_mountctl_desc;
 	ap.a_head.a_ops = ops;
+	ap.a_vp = vp;
 	ap.a_op = op;
@@ vop_markatime(...)
 	ap.a_head.a_desc = &vop_markatime_desc;
 	ap.a_head.a_ops = ops;
+	ap.a_op = 0;
 	ap.a_vp = vp;
@@ vop_allocate(...)
 	ap.a_head.a_desc = &vop_allocate_desc;
 	ap.a_head.a_ops = ops;
+	ap.a_op = 0;
 	ap.a_vp = vp;
```

(Better: delete the dead `a_op` fields from `struct vop_markatime_args` /
`struct vop_allocate_args` entirely — no wrapper parameter and no handler reads them.)

## Reproduction status

Not executed (Phase V skipped): Low/Info hardening finding, latent — no observable
misbehavior exists on a stock kernel because no handler reads the uninitialized
fields. Verified by scripted marshalling audit + source survey of all handlers.
