Skip to content

Linux bwrap sandbox: shell/exec spawn fails with EINVAL (os error 22) — /dev/fd miscategorized as a device file when it is a directory symlink #174

Description

@bradsmi13

Summary

On Linux systems where /dev/fd is a symlink to a directory (/proc/self/fd) — e.g. Fedora — every shell_command / exec_command fails at the process-spawn level with:

failed to spawn process: Invalid argument (os error 22)

…even echo test. File tools (read/write/edit) and MCP servers work fine — because MCP servers are spawned outside the bwrap sandbox, whereas shell/exec tools are wrapped by it.

Environment

  • Devo Desktop (Electron) + CLI devo v0.1.32, Fedora (kernel 6.19).
  • bwrap (bubblewrap) 0.11.0, installed and working standalone (bwrap --dev-bind / / /bin/echo okok).
  • /dev/fd -> /proc/self/fd (i.e. a directory), which is the default on modern Linux.

Root cause (from devo-server log)

Every failing shell attempt is preceded by:

WARN devo_sandbox::profiles: crates/sandbox/src/profiles.rs:314:
  Could not allow device file path="/dev/fd" error=Expected a file but got a directory: /dev/fd

/dev/fd is in the sandbox's DEVICE_FILES list, but on this system it is a directory (symlink → /proc/self/fd). The device-file allow fails, the resulting bwrap invocation is malformed, and the kernel rejects the spawn with EINVAL. It should be handled like the DEVICE_DIRS entries (e.g. /dev/pts), or resolved through the symlink / skipped when is_dir().

Reproduction (CLI)

mkdir -p repro/.devo && cd repro
# A sandboxing profile -> EINVAL:
printf '[permission]\nsandbox_profile="workspace"\n' > .devo/config.toml
devo prompt "Use your shell tool to run exactly: echo test"
#   -> failed to spawn process: Invalid argument (os error 22)

# sandbox off -> works:
printf '[permission]\nsandbox_profile="off"\n' > .devo/config.toml
devo prompt "Use your shell tool to run exactly: echo test"
#   -> test

Secondary issue: Desktop server ignores the global sandbox setting

The Desktop devo server does not honor the global [permission].sandbox_profile = "off" — only a per-project override works:

[projects."/abs/path/to/repo"]
sandbox_profile = "off"

The CLI devo prompt honors the global key; the Desktop server appears to resolve the sandbox per-project and fall back to a sandboxing default when a project has no entry. Users who set the global key to off still get sandboxed shell failures in Desktop. (Env DEVO_SANDBOX_LAUNCHER=none, a top-level sandbox_profile, and permission_preset="full-access" do not disable it.)

Suggested fix

  1. In crates/sandbox/src/profiles.rs, classify /dev/fd as a device directory (or realpath it, or skip when is_dir()), so the bwrap invocation is well-formed where /dev/fd is a directory symlink.
  2. Have the Desktop server honor the global [permission].sandbox_profile default, consistent with the CLI.

Happy to test a patch build.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions