Skip to content

fix(sandbox): stop ssh_server_init from overwriting /tmp to 0700#8

Merged
pdettori merged 2 commits intomvpfrom
fix/sandbox-ssh-tmp-permissions
May 2, 2026
Merged

fix(sandbox): stop ssh_server_init from overwriting /tmp to 0700#8
pdettori merged 2 commits intomvpfrom
fix/sandbox-ssh-tmp-permissions

Conversation

@pdettori
Copy link
Copy Markdown

@pdettori pdettori commented May 2, 2026

Summary

  • Root cause: ssh_server_init in ssh.rs was setting the parent directory of the SSH socket path (/tmp) to mode 0700 after prepare_filesystem had already ensured it was 1777. This locked the sandbox user out of /tmp, causing Claude Code to fail with EACCES: permission denied, mkdir '/tmp/claude-998/...'.
  • Fix: Remove the parent directory permission restriction in ssh_server_init. The socket file itself is already 0600, which prevents the sandbox user from connecting.
  • Defense-in-depth (lib.rs): call ensure_sandbox_process_identity() before proto→Rust conversion so prepare_filesystem always sees the correct user/group; add root-fallback in prepare_filesystem matching drop_privileges logic.

Root Cause Analysis

The supervisor startup sequence runs:

  1. prepare_filesystem — sets /tmp to 1777 with correct ownership
  2. ssh_server_init — creates the SSH socket at /tmp/openshell-ssh.sock and overwrites /tmp to 0700
  3. drop_privileges + exec — spawns the sandboxed process as sandbox user

Step 2 undid step 1. The previous fix (PR #7) hardened prepare_filesystem but didn't address ssh_server_init running afterward.

Changes

File Change
crates/openshell-sandbox/src/ssh.rs Remove set_permissions(parent, 0o700) — rely on socket's 0600 instead
crates/openshell-sandbox/src/lib.rs Call ensure_sandbox_process_identity() in load_policy before conversion
crates/openshell-sandbox/src/lib.rs Add root-fallback in prepare_filesystem (mirrors drop_privileges)

Test plan

  • Built supervisor image with fix, loaded into Kind cluster
  • Created sandbox pod, verified /tmp is 1777 root:root
  • Verified SSH socket is 0600 root:root (sandbox user cannot connect)
  • Verified mkdir /tmp/test-fix succeeds as sandbox user
  • Verified sandboxed process runs as sandbox (UID 998)

pdettori added 2 commits May 2, 2026 14:36
The SSH server initialization in ssh.rs was setting the parent directory
of the SSH socket path (`/tmp`) to mode 0700 after prepare_filesystem
had already ensured it was 1777. Since the default socket path is
`/tmp/openshell-ssh.sock`, this effectively locked out the sandbox user
from /tmp entirely, causing Claude Code to fail with:

    EACCES: permission denied, mkdir '/tmp/claude-998/...'

Root cause: ssh_server_init called set_permissions(parent, 0o700) on
the socket's parent directory to prevent the sandbox user from
connecting to the socket. But when the socket lives in /tmp, this
clobbers the world-writable sticky bit that other processes depend on.

Fix: Remove the parent directory permission restriction. The socket file
itself is already set to 0600, which is sufficient to prevent the
sandbox user from connecting.

Defense-in-depth (lib.rs):
- Call ensure_sandbox_process_identity() on the proto policy in
  load_policy before converting to Rust types, so prepare_filesystem
  and drop_privileges always see run_as_user/run_as_group even when
  the server hasn't normalized the policy yet.
- Add root-fallback in prepare_filesystem: when no user/group is
  configured but euid is root, fall back to sandbox:sandbox — matching
  the same logic in drop_privileges.

Signed-off-by: Paolo Dettori <pdettori@gmail.com>
Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Paolo Dettori <dettori@us.ibm.com>
In CI environments (containerized runners), /proc/{pid}/exe may be
unreadable for the forked child process, causing resolve_process_identity
to fail with "failed to resolve peer binary" before reaching the
"ambiguous shared socket ownership" check. Both error paths correctly
deny the connection — accept either in the test assertion.

Signed-off-by: Paolo Dettori <pdettori@gmail.com>
Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Paolo Dettori <dettori@us.ibm.com>
@pdettori pdettori merged commit e62ad60 into mvp May 2, 2026
8 checks passed
@pdettori pdettori deleted the fix/sandbox-ssh-tmp-permissions branch May 2, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant