diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-14 21:26:47 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-15 17:24:42 -0300 |
| commit | a624a56e289e4a02a411f83741f0f2c9fc0f0b2e (patch) | |
| tree | b87e3ca10dd1c4417112164f792b5da1e26de0a6 /docs/v9fs.md | |
| parent | 95681ff7017b8a9e4c8f9fa6a7371d1233432f2f (diff) | |
| download | pardes-a624a56e289e4a02a411f83741f0f2c9fc0f0b2e.tar.gz pardes-a624a56e289e4a02a411f83741f0f2c9fc0f0b2e.zip | |
Add Linux Tty9p mounted terminals and forward raw TTY keys
Diffstat (limited to 'docs/v9fs.md')
| -rw-r--r-- | docs/v9fs.md | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/docs/v9fs.md b/docs/v9fs.md new file mode 100644 index 00000000..51b35a46 --- /dev/null +++ b/docs/v9fs.md @@ -0,0 +1,107 @@ +# Linux terminals with a kernel 9P mount + +Execute `Tty9p`, or press `SPC n 9` in editor mode, to open a terminal below +this pane with the current Pardes session mounted through Linux v9fs. + +The new pane asks for your sudo password when needed. After mounting, it starts +your configured shell as your normal user, with your account's supplementary +groups. The shell receives `PARDES_MOUNT`, the absolute mountpoint: + +```sh +ls "$PARDES_MOUNT/self/pane" +cat "$PARDES_MOUNT/self/index" +cat "$PARDES_MOUNT/self/README" +ls -l "$PARDES_MOUNT/self/new" +cat "$PARDES_MOUNT/self/pane/$PARDES_PANE/body" +``` + +The mount belongs to that pane's subprocess tree. Other panes and the editor +core keep their original mount namespace. It works in native Linux TTY and SDL +sessions, including detached sessions. A frontend attaching from elsewhere does +not perform the mount; the session host starts the new terminal. + +## Build and setup + +The normal Linux build installs the ordinary `pardes-v9fs` executable beside +`pardes` and `pardes-gui`: + +```sh +zig build +``` + +Start an updated editor to get the builtin. An already running core retains +its old code. The host resolves the helper beside its own executable; +`PARDES_V9FS_HELPER=/absolute/path/to/pardes-v9fs` overrides this for development +builds whose editor and helper live in different build-cache directories. + +Linux must support `9p` and its Unix transport (`9pnet_fd`). v9fs mounting needs +`CAP_SYS_ADMIN` in the initial user namespace, which sudo supplies. The launcher +uses `sudo -E` to retain the shell environment; local sudo policy must allow +that. It restores the caller's PATH after dropping privileges because sudo's +`secure_path` can replace it even with `-E`. + +No setuid installation, passwordless sudo policy, system group, or FUSE is +installed. The helper currently accepts explicit mount paths and a command; +it is not a restricted privilege broker. Do not grant it blanket passwordless +access. A group-authorized helper would require a separate restricted design. + +## Runtime organization + +`src/linux/v9fs.zig` builds `pardes-v9fs` and provides helper discovery to the +native host. `Tty9p` marks the new pane for a mounted shell; `host_io.forkShell` +starts the normal interactive shell and queues a quoted helper command. For +bash and fish, the command waits for the shell's prompt-ready mark. The helper +runs as a foreground shell job, so sudo uses the terminal like a manually run +command. Authentication failure or cancellation returns to the original shell; +exiting the mounted shell also returns there. + +The unprivileged launcher creates a private temporary mountpoint and invokes +sudo inside the new PTY. The elevated helper creates a private mount namespace, +makes propagation recursively private, and mounts the session's Unix socket +with `version=9p2000,cache=none,access=any,nosuid,nodev,noexec`. It restores the +calling user's account groups, drops all real/effective/saved root IDs and +mount capabilities, and executes the shell. Ordinary commands such as sudo +remain available for subsequent explicit authentication. The launcher waits for sudo, +forwards termination signals, and removes its empty temporary directory on exit. +Namespace destruction releases the mount when its last process exits. + +The core stays outside the mount namespace because its event loop serves 9P. +A blocking filesystem operation through its own mount could wait for a request +that the blocked event loop must service. Even pathname resolution may do this. + +Each `Tty9p` currently creates its own mount and consumes a server connection; +the session has four application connection slots across all transports. This +is the explicit per-pane version. A shared launcher for all pane shells remains +future work. Detached sessions retain the running mounted pane when frontends +leave; Dump/Restore does not reconstruct mounted-shell namespaces. Descendants +that deliberately outlive the terminal may retain their namespace until exit. + +## Tests + +```sh +zig build v9fs-terminal-test -Dplatform=tty +zig build v9fs-driver-test -Dplatform=tty +zig build 9p-test -Dplatform=tty +sudo -v +zig build v9fs-test -Dplatform=tty +``` + +`v9fs-terminal-test` exercises the builtin, real launcher, PTY input, session +environment, quoted helper paths, hidden password input, and core responsiveness +using an unprivileged sudo stand-in. It checks that authentication failure and +interruption clean up the temporary mountpoint and leave the original shell usable. It does not claim kernel-mount coverage. + +`v9fs-test` mounts through the same runtime helper. Its driver keeps the editor +unprivileged and uses `sudo -n`, retaining the calling terminal's authorization. +Missing authorization or kernel support fails the test instead of skipping it. +It checks mount isolation, privilege dropping, inherited access, directory +refresh, body reads and truncation, independent wire updates, addressed edits, +shell redirection to ctl, Exec dispatch, rendered screen JSON, and OS-file reads. + +Linux follows `O_TRUNC` with a `Twstat` carrying zero length and an `mtime` hint. +Pardes accepts this truncation without storing caller-selected timestamps; +standalone timestamp, permission, and ownership changes remain unsupported. + +The initial kernel probe passed on this host on 2026-09-14. The broader +`fs-test` has an existing syntax-bold assertion failure at `test/fs.py:459`, +also reproduced on the cached editor binary preceding the truncation fix. |
