Expand description
Every runtime write, append, create, removal and decision-read inside a capsule’s workdir, performed relative to a held directory descriptor with no symbolic link followed.
The capsule’s shell commands can write anywhere in the accessible workdir, and without
--workdir the session directory is that workdir. The runtime itself is unconfined, so a
path it builds by joining names onto the workdir and hands to std::fs resolves whatever the
capsule planted there: task.md -> ~/victim.txt turns the runtime’s task write into a write to
the operator’s file, and tools -> ~/.local/bin turns a tool install into an install outside
the capsule. WorkdirRoot is the one way the runtime touches those paths.
§The walk
A relative path is split on /; a segment that is empty, . or .. is refused before any
syscall, which also refuses an absolute path. Each directory segment is opened with
openat(parent, name, O_DIRECTORY | O_NOFOLLOW) from the descriptor the previous segment
produced, starting at the anchor’s own descriptor, so no step resolves a name the capsule could
have swapped for a link and no step resolves anything from the anchor’s host path. A segment
that fails to open is fstatat(AT_SYMLINK_NOFOLLOW)-ed to say whether it was a link.
This per-component walk is the only implementation, on Linux and macOS alike, for the reason
crate::resource_plane keeps one portable resolution path: openat2(RESOLVE_BENEATH) is
Linux-only and could only ever be an extra layer over a portable path that has to be correct by
itself. Every primitive is rustix’s safe wrapper over the POSIX *at call of the same name.
§Paths in refusals
A WorkdirRefusal names its paths relative to the accessible workdir with the real
session id — .murmur/ses_…/plans/plan-1.json, the form peer_file_fetch.stored_path uses —
whichever root the call went through. Without --workdir the two roots are the same directory
and a session path has no .murmur/<id>/ prefix.
§The refusal latch
Every refusal is also pushed onto a latch every clone of both roots shares. A best-effort
writer that swallows its error (a hook log, a blob, MURMUR.md) still leaves the refusal
there, and the task loop drains it with WorkdirRoot::take_refusals at its checkpoints and
fails the task.
Structs§
- Workdir
Refusal - One refused call.
pathandrefused_atare relative to the accessible workdir. - Workdir
Root - A held directory descriptor inside (or at) the accessible workdir, and the only way the runtime reads its own decisions from, or writes into, that tree.
Enums§
- Entry
Kind - What
fstatat(AT_SYMLINK_NOFOLLOW)found at a path’s last component. - Refusal
Reason - Why a call was refused. The wire names are what
workdir_path_refused.reasoncarries. - Workdir
Error - Error from a
WorkdirRootcall. - Workdir
Operation - What a refused call was trying to do. The wire names are what
workdir_path_refused.operationcarries.
Constants§
- DEFAULT_
DIR_ MODE - Mode for a directory created with no reason to choose another:
std::fs::create_dir’s, so the umask decides the result exactly as it does forstd. - DEFAULT_
FILE_ MODE - Mode for a file written with no reason to choose another:
std::fs::File::create’s, on the same terms asDEFAULT_DIR_MODE.