4.7 KiB
P15-032 / G09 vnode-backed image gate
Decision rule
This gate is source-preparatory only. It does not link its model into EROFS and
does not authorize B39 merely because a declared state sequence looks safe. It
pins and extracts the relevant FreeBSD 15 vnode, pager, mount, GEOM, md(4),
nullfs, unionfs, tarfs, and deadfs contracts, compiles an owned-temporary C
lifecycle model generated from P15-032-input.json, and rejects adversarial
false-GO mutations.
The runner exits with:
0: gate GO;10: gate STOP;20or another nonzero value: runner failure;124: absolute gate timeout.
All phases have absolute deadlines. The generated C source and its output are copied into the requested evidence directory; the temporary executable is removed by the runner trap.
Closeable local vnode contract
The pinned FreeBSD sources support a coherent local lifecycle:
- Use an explicit
vnode:/absolute/pathtag; GEOM remains explicit or legacy GEOM syntax. A mount and alldevice.Nsources use one backend kind. - Resolve with
namei, requireVREG, retain vnode identity withvn_open_vnode(FREAD), retain the mounter credential withcrhold, and use that credential for every sourceVOP_READ. - Apply
VOP_SET_TEXTbefore first I/O. The default write-count contract rejects existing or later writers withETXTBSY; retain a size snapshot and convert a short source read intoEIO. Rename or pathname replacement does not change the held vnode identity. - Read synchronously into
UIO_SYSSPACEunder a source range lock and source vnode lock. FreeBSD's old vnode-pager fallback drops the VM object write lock beforeVOP_READ, so no user-buffer pager fault is introduced by this read shape. - Register the source mount with
vfs_register_upper_from_vpbefore first I/O. On unmount, reject new I/O, drain delayed and in-flight completions,vflush, unregister the upper mount, unset text, close the vnode, release the held credential, and then release the final mount-private reference. A forced dead source returnsENXIOrather than silently changing identity. - Keep GEOM open/read/close and vnode open/read/close as disjoint tagged-union branches. This preserves the existing GEOM and multidevice behavior.
The generated model checks this order and independently removes each local invariant to ensure that every mutation is rejected.
Blocking FreeBSD contract
The required pre-I/O self and ancestor check is transitive across VFS and GEOM, not only across pathname aliases:
regular source vnode
-> source filesystem
-> md(4) GEOM provider
-> md_s.s_vnode.vnode
-> another filesystem vnode
The final identity edge is not available through a generic, identity-preserving FreeBSD API:
VOP_GETLOWVNODEexposes vnode-stack aliases such as nullfs and unionfs, but it does not traverse a filesystem's GEOM storage dependency.vfs_register_upper_from_vppins the immediate source vnode mount and orders its unmount, but it does not register hidden GEOM-to-vnode backing edges.md(4)stores the held backing vnode in the privatestruct md_sdefined inmd.c. Its GEOM object exposes onlyvoid *softc; dump configuration exposes a pathname, not a held vnode identity.- Re-resolving that pathname fails the rename/replace invariant. Casting
g_geom.softcto a copied privatestruct md_sis an undocumented, class-specific dependency and does not cover other filesystem-private or GEOM-private file-backed providers.
Consequently a visible-only oracle can approve all vnode, credential, pager,
resize, and unmount checks while missing the hidden backing-vnode ancestor. The
gate includes that case as an adversarial false-GO control. There is no sound
place to return the required single cycle errno (EDEADLK) because the cycle
identity cannot first be discovered.
Result
P15-032 is STOP and B39 is STOP-NO-SOURCE. Recursive I/O and its lock
graph cannot be statically excluded for the requested regular-file source
surface using documented generic FreeBSD interfaces. A safe future GO needs a
new kernel dependency API that returns and pins transitive backing vnode
identities, or an explicitly narrower feature contract whose permitted source
filesystems have no hidden storage dependencies. Neither change is in B39's
authorized write set.
Run from the repository root:
repo-pre-15/tests/pre15/gates/P15-032.sh \
--base bd5a09054e5cf89efd4db82aadb051f20b06ebf7 \
--freebsd-src /work/build/freebsd-src \
--output /absolute/owned/output/path
No EROFS source, Makefile, feature documentation, B39 case, or B39 fixture is modified by this STOP addendum. D, H, K, Q, TC006, TC179, TC184, smoke, and the full feature suite are not run at the gate stage.