Cordon::Bwrap
Inherits Cordon::Runner < Reference < Object
Linux sandbox runner using Bubblewrap (bwrap).
bwrap uses unprivileged Linux user namespaces — no root required. Rather than evaluating path rules at access time (like SBPL on macOS), it constructs a fresh mount namespace: an allowlist view assembled from explicit bind mounts. Anything not bound simply does not exist inside.
Requires bwrap >= 0.3.0. Available on all major distributions: apt install bubblewrap dnf install bubblewrap pacman -S bubblewrap
Note: some hardened kernels disable unprivileged user namespaces (kernel.unprivileged_userns_clone=0). Call available? before use.
Constants
Passed through from the parent environment after --clearenv. Everything else is stripped; add to policy.env for additional vars.
Bound read-only with --ro-bind-try (silently skipped if absent). Covers dynamic linker and shared-library paths across major Linux distributions — needed for any dynamically-linked binary to start at all, since the kernel loads the ELF interpreter (ld-linux.so) as part of the same execve(2) that launches the target command.
Binary directories (/usr/bin, /bin, /usr/sbin, /sbin) are DELIBERATELY NOT included here. bwrap's mount namespace has no concept of "exec permission" separate from "visible" — unlike SBPL on macOS, which can grant file-read* without process-exec, a bind mount makes a path both readable AND exec-able simultaneously. A policy with no explicit grants would still be able to exec /usr/bin/ruby, /usr/bin/python3, or anything else living in these directories, if they were unconditionally mounted — the exact same class of bypass fixed on the macOS side (see SandboxExec::BASELINE's comment). If your command needs to shell out (e.g. via system()/popen(), or a script with a #!/bin/sh line), merge in Preset::System, which mounts these directories explicitly.
Instance methods
Returns the full argv that would be passed to the OS. Useful for inspection, dry-run output, or logging.
See Runner#run for shell's contract.
Replaces the current process with command, inside the sandbox described by policy. Used for self-relaunch (Cordon.relaunch) — the caller does not resume; either the sandboxed command takes over the process image, or this raises.
Short platform-facing name for this runner (e.g. "bwrap", "sandbox-exec"), used in ConfirmReport output.
Runs command inside the sandbox described by policy.
If shell is true, command must be a single-element array holding
a full shell script string, executed via /bin/sh -c. No
positional-arg forwarding is supported — build the complete script
string yourself before calling. /bin/sh must be exec-granted by
policy (e.g. via Preset::System), same as any other target;
shell: true is not an implicit exec exception.
If shell is false (the default), command is the literal argv — command[0] is exec'd directly with command[1..] as its arguments, no shell involved.