Repository navigation
feat(minimal): lay out the split VM users, directories and socket modes (T65) - #2561
norrietaylor merged 11 commits into
Conversation
Adds a vm-users item that creates minimal-vmm and minimal-gvproxy, the provider dir at 0710 group minimal-vmm, vmm/, the gvproxy, gvproxy config and gate dirs, and a sudoers drop-in with the spawns and the stop rules.
The provider dir may be 0710 with group minimal-vmm, vmm/ is verified and never created, and each socket takes its mode and group from the design's table, staying 0600 while this process does not hold the group.
The guest-control and guest-telemetry doors admit the minimal-vmm uid beside the daemon's own. The data volume is created 0600 and the boot log 0640, whatever the umask gives.
…y-and-the-vmm-child-as-their-dedicated
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
|
Reviewed: 1 finding, none blocking at Address the comments on the diff. Clobber: none seen. |
There was a problem hiding this comment.
arch-review: CONDITIONS · 3 conditions · the full ruling
The parts that landed match the T57 layout, but the task proof is not delivered. gvproxy and the VMM child still run as the login user. Do not close #2560, and file each undone item as an issue (C1). The root script in vm_users_script() tests for a symlink and then runs cd -P in a separate step. A login process can swap in a symlink between the two steps, so root can give a root-owned directory to minimal-vmm. Add the parent-inode check in C2. Do not offer the vm-users item yet (C3), because its sudo rules name subcommands that minvmd does not have. Two plan questions go to a person as escalations.
Ruled at c2a33a5 against gominimal/arch@109541a48c31 by claude-opus-5-5.
The switch config is created fresh with O_NOFOLLOW at mode 0640, and its group is minimal-gvproxy when this process holds that group. A symlink or an entry with another owner at the path is refused.
|
/revise Round 1 of #2561, on the arch ruling at c2a33a5 and four review findings. No round is in flight. The epic owner narrowed T65 on 2026-10-25 to the foundation this PR delivered (#2560 and the plan comment now read "Lay out the split users, directories and socket modes for a split-user VMM"). The
One commit, Conventional Commits subject, body lines at most 72 characters. Generated by Claude Code |
|
That Nothing to type again: the command gets a rocket when its round starts, or a refusal that names the reason. No round was counted for it yet. |
The login owns the provider dir and can swap an entry for a symlink between the -L test and the cd. Root now compares the physical path with the path it means after each cd, vmm/ included, before it changes anything.
There was a problem hiding this comment.
arch-review: CONDITIONS · 2 conditions · the full ruling
The two fixes in this push conform. The pwd -P check pins each directory before root changes it. write_config writes gvproxy.yaml as the repo design says. But gvproxy and the VMM child still run as the login, so Gatehouse §6.10 line 831 is not met. The undone work has no issues. C1 files each item as a residual. C2 keeps #2560 open and marks the proof leg not_run. Two questions go to a person: the split of T65, and custody of a default install in ~/.local/bin.
Ruled at 1c004ea against gominimal/arch@109541a48c31 by claude-opus-5-5.
|
Round 1 of 10 on the runtime's review findings, pushed as
Verify Converted to a draft: something above needs a person before review. Review threads the coder judged:
The proof is only partly true at this branch. A person can see that min finalize-install creates minimal-vmm and minimal-gvproxy, the provider dir at 0710 group minimal-vmm, vmm/, the gvproxy, gvproxy config and gate dirs, and the sudoers drop-in. The root walk now checks pwd -P after each cd. The sockets take the modes and groups of the design. gvproxy.yaml is written 0640 with group minimal-gvproxy. The guest and telemetry doors admit the minimal-vmm uid. gvproxy and the VMM child do NOT run as their dedicated users yet. Nothing spawns through sudo -n on this branch. Notes from the agent: Revise round 1. Threads 1 and 2: the vm-users script now compares The rest of the spawn layer cannot be done inside its layers without breaking the VM. I left it undone on purpose:
|
The vm-users script now keeps the device and inode of . before each cd -P, and requires them at .. after it. A symlink swapped in between the -L test and the cd stops the script before root changes anything. The item is no longer offered: its drop-in names minvmd subcommands that do not exist yet. T66 (#2566) adds it back with the sudo spawns. The item refuses when a split group has another member, and names it. The script adds the login with gpasswd -a and removes nobody. It also refuses when the provider dir does not exist yet. sudoers_arg rejects the sudoers wildcard characters. vmm_uid in minvmd no longer caches a miss. The gvproxy.yaml writer in net.rs leaves this PR. It moves to T66.
|
Round 2 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
At this branch, the vm-users script in Notes from the agent: Commit 89cacf7. Directive item 1: the script keeps |
…y-and-the-vmm-child-as-their-dedicated
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
This head conforms for the narrowed T65 scope. The live changes fail closed. The guest doors admit minimal-vmm only when the user exists, and the host door keeps its check. A socket opens to a group only when the process holds that group. The vm-users root step is not offered, so no drop-in names the missing subcommands. The process separation in Gatehouse §6.10 line 831 is residual #2566. C1: name in the #2566 residual the work it does not name now. The biggest item is the root move of data-vol.raw into vmm/.
Ruled at 89cacf7 against gominimal/arch@109541a48c31 by claude-opus-5-5.
…T65) The vm-users script prints the provider path in double quotes, so a path with $, a backtick or a backslash is now refused. The item works on the canonical provider dir, so a symlinked /home does not fail the walk. The guest door tests the own uid before the minimal-vmm lookup.
…y-and-the-vmm-child-as-their-dedicated
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The compare conforms. The new path refusal and the canonical provider path keep the root script literal and under custody (§7.1 line 258). The script still walks the real path and checks each owner. The guest door admits the same uids as before. BEP-047 stays open until T66 (#2566) adds the sudo -n spawns and gives the vm-users item its caller back. C1 records this.
Ruled at 8f77c1f against gominimal/arch@109541a48c31 by claude-opus-5-5.
|
Round 3 of 10 on the runtime's review findings, pushed as
Verify Review threads the coder judged:
The vm-users script in Notes from the agent: Revise round 3. All three findings are valid, and each one has a fix. The test now covers paths with $(...), a backtick and a backslash. The refusal cause text changed to name the setup script and the new characters. cargo clippy -p minimal -p minvmd --all-targets showed warnings only in minimald and minimald-rpc, which this change does not touch. just clippy-strict was not run. |
There was a problem hiding this comment.
Babysitter approval at 8f77c1f: every merge gate passes at this head (arch PASS at 8f77c1f, zero open threads, every lane aggregator green). Squash title feat(minimal): lay out the split VM users, directories and socket modes (T65) and the squashed message pass commitlint. Queued for squash merge.
Generated by Claude Code
T65 — Run gvproxy and the VMM child as their dedicated users
slice: S8
kind: task
covers: BEP-047
size: L
est: 380 code, 320 tests
executor: agent
difficulty: needs care
model: strongest
diagnostics: when
minimal-vmmorminimal-gvproxyis missing, orsudo -ncannot run a spawn, the VM host daemon refuses to start with the error the T57 design's ownership model names, on stderrobservability: one info log line at start naming the user gvproxy and the VMM child run as
layers:
- install:
- crates/minimal/src/cmd/finalize_install.rs: creates the
minimal-vmmandminimal-gvproxyusers and groups, the provider dir at 0710 groupminimal-vmm,vmm/,<gvproxy dir>,<gvproxy config dir>and<gate dir>asdocs/design/2026-10-25-split-user-vmm-provider-dir.mdlays them out, and the sudoers drop-in with the gvproxy, VMM and EGW spawns and the two stop rules (root-owned absolute paths, literal arguments,env_resetwith an emptyenv_keep,umask=0077withumask_overridefor gvproxy) (split from T38 on 2026-10-25 by the epic owner)test: cargo nextest run -p minimal finalize_install_creates_the_split_users_dirs_and_drop_in
- sockets:
- crates/minvmd/src/sock.rs:
prepare_socket_dir,restrict_owned_dirandverify_provider_dir_ownershipaccept 0710 with groupminimal-vmmand verifyvmm/;enforce_socket_permissionsandverify_socket_permissionstake the mode and the group from the design's tabletest: cargo nextest run -p minvmd split_user_provider_dir_modes_are_enforced
- spawn:
- crates/minvmd/src/cmd/run.rs: spawns gvproxy and the VMM child through
sudo -n -uunder the drop-in, each in a new process group, never sending SIGKILL to thatsudo, with per-run values on descriptor 0; movesssh.sock,timekeep.sock,boot.loganddata-vol.rawtovmm/, the switch socket to<gvproxy dir>, andgvproxy.yamlandgvproxy-bep.sockto<gvproxy config dir>; stops thechmodofssh.sock; refuses to start whensudo -nfails- crates/minvmd/src/cmd/vmm_child.rs: creates
vmm/boot.logwith mode 0640, takes the gate socket path from<gate dir>, and sets the mode ofssh.sockafter libkrun binds it- crates/minvmd/src/volume.rs:
create_sparse_rawcreatesvmm/data-vol.rawwith mode 0600, and the supervisor refuses a group or other write bit on either file- crates/minvmd/src/net.rs:
HostGvproxy::spawnstarts gvproxy throughsudo -n -u minimal-gvproxy, andGvproxyConfig::with_config_pathwritesgvproxy.yamlat 0640 groupminimal-gvproxy- crates/minvmd/src/control.rs: the guest door admits the
minimal-vmmuid and the supervisor's own uid; the host door keeps its check- crates/minvmd/src/guest_telemetry.rs:
accept_loopadmits theminimal-vmmuid and the supervisor's own uidtest: cargo nextest run -p minvmd gvproxy_and_vmm_run_as_their_dedicated_users
produces: none
consumes: none
proof: gvproxy runs as
minimal-gvproxyand the VMM child asminimal-vmm, each spawned throughsudo -nunder the drop-in, with the provider dir,vmm/and the gvproxy dirs at the modes the T57 design names, and the guest and telemetry doors admit theminimal-vmmuid.depends on:
- blocked by T57
Proof
The proof is NOT delivered in full. gvproxy and the VMM child still run as the login user, not through sudo -n. A person can now see these parts. On Linux with the VM backend, min finalize-install offers a 'vm-users' item. Its script creates minimal-vmm and minimal-gvproxy, sets the provider dir to 0710 group minimal-vmm, creates vmm/ (0750), the gvproxy dir (0750), the gvproxy config dir (0750) and the gate dir (2710). It writes /etc/sudoers.d/minimal-vm and checks it with visudo. minvmd accepts a 0710 provider dir with group minimal-vmm, and it applies the T57 socket table (0660 with the group when the process holds it, else 0600). The guest-control and guest-telemetry doors admit the minimal-vmm uid. The data volume is created 0600 and the boot log 0640.
Notes from the agent: The spawn layer is not done, and it cannot be done inside the task's layers. (1) crates/minimal-client resolves /ssh.sock, so a move of ssh.sock into vmm/ breaks min. (2) cmd/stop.rs signals vmm_pid directly. A VMM child under another user needs a stop-rule subcommand (proposed name __stop-group) that does not exist. (3) The EGW process (proposed subcommand __egw) does not exist. The supervisor runs as the login and cannot bind in a gate dir that minimal-gvproxy owns. (4) vm.rs, state.rs, net/shuttle.rs (gate_sock_beside), telemetry.rs and image.rs read the per-run values from the environment. A move to descriptor 0 (sudo env_reset) needs changes in those files. (5) The installer puts binaries in user-writable paths such as ~/.local/bin, so a default install cannot get a sudo rule. The vm-users item reports 'cannot' in that case. (6) A home directory ancestor at 0700 or 0750 blocks minimal-vmm from the provider dir. The script walks the path and refuses. Not done for these reasons: the sudo -n spawns, the sudo -n refusal on stderr, the info log line that names the users, the moves to vmm/ and the gvproxy dirs, GvproxyConfig with_config_path at 0640, the supervisor …[truncated]
Tests
cargo nextest run -p minimal finalize_install_creates_the_split_users_dirs_and_drop_incargo nextest run -p minvmd split_user_provider_dir_modes_are_enforcedcargo nextest run -p minvmd gvproxy_and_vmm_run_as_their_dedicated_usersVerify
min task run agent-verifyexited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.Base
The base branch moved while the coder worked; it was merged in before the tests ran.
Residuals
The epic owner narrowed T65 (#2560) on 2026-10-25 to the foundation this PR delivers: the split users, directories and socket modes. Running gvproxy and the VMM child as their own users moved to new tasks.
sudo -nasminimal-gvproxyandminimal-vmm. It offers the vm-users item again, addsminvmd __stop-group, matches the__krun-vmm <vm>rule toKrunVmm, movesgvproxy.yamlto<gvproxy config dir>and writes it at 0640 groupminimal-gvproxy, moves an existingdata-vol.rawintovmm/as root, and refuses to start whensudo -nfails.vm_users_item_on_this_hostkeeps no caller until then.minvmd __egwsubcommand.~/.local/bin, and what a host that cannot meet Gatehouse §6.10 line 831 does.Closes #2560
Generated by Claude Code