Repository navigation
feat(sandbox): run the guest server as an unprivileged user - #214
Merged
Merged
Conversation
codev-init and the WSL boot script now drop to the image's codev user (uid 1000) for the server itself; PID 1, the mounts, and the vsock/socat bridges stay root. WSL additionally gets /etc/wsl.conf at import so the Windows drives automount as that user. No host-uid remapping: measured on macOS 15 that Virtualization.framework's virtio-fs performs host operations as the process owning the VM and reports shared files as root in the guest, so guest ownership never gates workspace access. Verified on a rebuilt image — the server reports uid=1000(codev) and can still append to host files, create directories, write its home, and read the baked skills, with results landing on the host owned by the host user. vz takes effect with the next published image (codev-init is baked); the WSL half is host-generated and applies to the current image. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 4c, item 2 — closes the "guest server runs as root" gap (the privilege half of the CoWork/SharedRoot lesson: escapes happen at the mount seam, so the process touching those mounts should not be root).
What changed
image/guest/codev-init): PID 1, the mounts, and the vsock bridges stay root; the server execs undersetpriv --reuid=codev --regid=codev --init-groups(uid 1000), after achownof the guest home so the root-copied/etc/skelfiles stay writable.wsl/provider.ts): same drop in the host-generated boot script, plus/etc/wsl.confwritten at import (automount options = "metadata,uid=1000,gid=1000", then a terminate so the first start reads it) — Windows has no uid to match, so the guest's own user owns the automounted drives.--unshare-userwith no--uidkeeps the invoking host user, there is no root in that sandbox to drop.The design changed after measurement
The plan was to carry the host uid/gid into
boot.jsonand remap the guest user, because virtio-fs was assumed to check guest access against host file ownership. Measured on macOS 15, that is not how it behaves: Virtualization.framework's virtio-fs performs operations host-side as the process owning the VM and reports every shared file asrootinside the guest, so guest ownership never gates workspace access. The first attempt also exposed why the remap would have been actively harmful — macOS users are in gid 20, which collides with Debian'sdialout, and the collision guard silently fell back to root.So the remap and all its
CODEV_HOST_UID/GIDplumbing are gone: the guest simply drops to the image's existingcodevuser. Less code, no collision cases, no host-specific state in the image.Verification (rebuilt image, real VM)
e2e-vzon a freshly built image:health: OK / path api: OK / broker: OK, then via a guest pty:…and the files it created land on the host owned by the host user (
minh:staff). Sandbox suite 92 pass / 2 skip; new WSL test asserts thewsl.confautomount line, thesetprivexec, and that the bind mounts still happen before the drop.Rollout
codev-initis baked, so this is inert until the next image respin. Worth batching with any other image-level work, since each respin costs every existing sandbox a ~750MB re-download (via Reset, per feat(sandbox): make reset the image-upgrade path #211).setprivalready exists in the shipped rootfs. Not yet exercised on real Windows: the drop and thewsl.confautomount are unit-tested only, so they want a pass on the Windows box before the fleet leans on them.🤖 Generated with Claude Code