Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ae7242e
chore: files changed crates/tinybox-jail/src/bwrap/args.rs,crates/tin…
senamakel Oct 18, 2026
fe525d9
chore: files changed crates/tinybox-jail/Cargo.toml,crates/tinybox-ja…
senamakel Oct 18, 2026
27c125b
chore: files changed crates/tinybox-jail/src/detect_tests.rs,crates/t…
senamakel Oct 18, 2026
28b0909
chore: files changed Cargo.lock,crates/tinybox-jail/src/bwrap/args.rs…
senamakel Oct 18, 2026
0e90170
fix(bwrap): skip denied grants when carving read-only paths
senamakel Oct 18, 2026
b6f042e
feat(jail): add spawn_captured to BubblewrapBackend
senamakel Oct 18, 2026
5013407
test(bwrap): relax process count assertion to reduce flakiness
senamakel Oct 18, 2026
4d5e661
chore: files changed crates/tinybox-jail/tests/bwrap_isolation.rs
senamakel Oct 18, 2026
0bfbdcb
docs(jail): document the bubblewrap backend
senamakel Oct 18, 2026
e75f560
test(bwrap): cover backend availability and spawn paths
senamakel Oct 18, 2026
dab2673
feat(jail): add bwrap argument builder
senamakel Oct 18, 2026
66a026f
feat(jail): add bubblewrap fd plumbing for jail
senamakel Oct 18, 2026
677aeae
chore: files changed Cargo.lock,crates/tinybox-jail/Cargo.toml,crates…
senamakel Oct 19, 2026
16c975d
refactor(bwrap): split jail_args into baseline_mounts and deny_masks
senamakel Oct 19, 2026
aa14000
refactor(tinybox-jail): narrow test support helpers to crate visibility
senamakel Oct 19, 2026
79b4a25
fix(bwrap): address security review of the bubblewrap backend
senamakel Oct 19, 2026
a74b032
feat(bwrap): close inherited file descriptors in the sandbox
senamakel Oct 19, 2026
c691fad
test(tinybox-jail): cover high-numbered leaked descriptors
senamakel Oct 19, 2026
14462ca
test(bwrap): build fd leak probe script with explicit loop
senamakel Oct 19, 2026
dc9a094
test(bwrap): cover probe handling with fake launchers
senamakel Oct 19, 2026
2f8723f
Merge remote-tracking branch 'upstream/main' into tinybox-jail-bwrap
senamakel Oct 19, 2026
ed6f62b
fix(tinybus): decide process isolation per jail instead of per backend
senamakel Oct 19, 2026
2b5ae90
fix(jail): reject grants that reach targets through symlinks in writa…
senamakel Oct 19, 2026
92d9217
feat(bwrap): add version probe for bubblewrap compatibility
senamakel Oct 19, 2026
075124c
feat(jail): add bwrap launcher tests
senamakel Oct 19, 2026
18279ee
feat(bwrap): add support for custom bind mounts
senamakel Oct 19, 2026
8cff8b2
refactor(bwrap): share random suffix helper and tighten isolation tests
senamakel Oct 19, 2026
a8a6844
docs(capability): clarify Kernel isolation level semantics
senamakel Oct 19, 2026
286531b
feat(bwrap): add bubblewrap sandbox launcher
senamakel Oct 19, 2026
135d741
feat(bwrap): probe bubblewrap version and fall back to legacy flags
senamakel Oct 19, 2026
abaf916
test(bwrap): cover args file reachability inside the sandbox
senamakel Oct 19, 2026
93adf46
fix(scripts): count bwrap tests without anchoring to line start
senamakel Oct 19, 2026
18b3b29
test: implement is_suitable_for_untrusted_jail in test backends
senamakel Oct 19, 2026
a57aa20
test(native_shell): qualify Jail type in test backend
senamakel Oct 19, 2026
7775595
test(bwrap): gate userns test on isolation level
senamakel Oct 19, 2026
0986715
feat(jail): add native jail module
senamakel Oct 19, 2026
03e2f09
feat(bwrap): add support for custom bind mount arguments
senamakel Oct 19, 2026
f292a56
feat(jail): add bwrap launcher tests and shared test support
senamakel Oct 19, 2026
2e109b5
feat(tinybox-jail): add integration tests for bwrap fd leaks and isol…
senamakel Oct 19, 2026
73239a5
docs(capability): clarify Process isolation level and bwrap caveats
senamakel Oct 19, 2026
f91c559
refactor(bwrap): drop unused jail parameter from deny_masks
senamakel Oct 19, 2026
1ca18c8
test(bwrap): cover NUL byte injection in environment
senamakel Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions crates/tinybox-core/src/capability/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ pub enum IsolationLevel {
/// launching user's full privileges.
None,
/// The workload runs under a separate user or working directory, but shares
/// the host's process table and filesystem view.
/// the host's process table and filesystem view. A namespace backend that
/// cannot guarantee [`IsolationLevel::Kernel`] for every configuration (for
/// example, because the host network is shared) also reports this level as
/// its conservative minimum; it then states its per-configuration level
/// separately.
Process,
/// Separate namespaces and cgroups. The workload cannot see host processes
/// or escape its root, but shares the host kernel.
/// Separate pid, mount, user and ipc (and, where stated, network)
/// namespaces. The workload cannot see host processes or reach paths
/// outside its root, but shares the host kernel. It does not imply a
/// seccomp filter or resource limits.
Kernel,
/// A separate kernel behind a hypervisor boundary.
Hardware,
Expand Down
11 changes: 10 additions & 1 deletion crates/tinybox-jail/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tinybox-jail"
description = "Per-process directory jail for spawned commands: Landlock, Seatbelt, and AppContainer."
description = "Per-process directory jail for spawned commands: bubblewrap, Landlock, Seatbelt, and AppContainer."
documentation = "https://docs.rs/tinybox-jail"
version.workspace = true
edition.workspace = true
Expand Down Expand Up @@ -30,6 +30,9 @@ serde_json.workspace = true

[target.'cfg(target_os = "linux")'.dependencies]
landlock = { version = "0.4", optional = true }
# `NamespaceProbe` locates `bwrap`; reused so there is one definition of how the
# Linux backends find it.
tinybox-linux.workspace = true

[target.'cfg(windows)'.dependencies]
# AppContainer profile APIs, ACL editing, STARTUPINFOEXW process spawn, and the
Expand All @@ -47,5 +50,11 @@ windows-sys = { version = "0.61", features = [
[dev-dependencies]
tempfile = "3"

[target.'cfg(target_os = "linux")'.dev-dependencies]
# Clears close-on-exec on a descriptor in the fd-leak regression test; the safe
# `fcntl_setfd` avoids `unsafe`, which the workspace forbids. Already in the
# lockfile through tempfile.
rustix = { version = "1", default-features = false, features = ["std", "fs"] }

[lints]
workspace = true
5 changes: 4 additions & 1 deletion crates/tinybox-jail/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ spawns, never the core process itself.
root the same access as the root (Landlock rule, Seatbelt `file-write*`
subpath, `AppContainer` ACL), for host-owned scratch such as a per-call
output-capture directory that must not land inside the root.
- Cache the default backend: Landlock on Linux kernels that support it,
- Cache the default backend: bubblewrap on Linux when `bwrap` is installed and
unprivileged user namespaces work (real process isolation, suitable for
untrusted code), else Landlock on kernels that support it,
Seatbelt on macOS, otherwise the `unsupported` backend.
- Spawn a `std::process::Command` inside the jail, canonicalizing `root`
(and the read-only and read/write paths) first so backends never see `..` or symlink
Expand All @@ -39,6 +41,7 @@ spawns, never the core process itself.
| `crates/tinybox-jail/src/jail.rs` | Core types: the `Jail` description struct (builder plus `canonicalize`/`canonicalize_or_log`) and the `JailBackend` trait (`name`/`is_available`/`spawn`). |
| `crates/tinybox-jail/src/detect.rs` | `pick_backend()`: first available OS backend, else an unsupported backend that fails closed. |
| `crates/tinybox-jail/src/noop.rs` | `NoopBackend`: no enforcement, plain `Command::spawn`. Always available. |
| `crates/tinybox-jail/src/bwrap/` | Bubblewrap backend (Linux only): user/pid/ipc/uts (+net) namespaces, grants as bind mounts, `deny_read` masked, `--die-with-parent`. `isolation()` is the minimum over configurations (`Process` with `--disable-userns`, else `None`); `Kernel` only per jail without `allow_net` (`isolation_for` / `is_suitable_for_untrusted_jail`; hosts must use the per-jail form). Never looks `bwrap` up on `PATH`; the probe is a sanity check, not authentication, and `with_program` skips the ownership check. The caller's environment and credentials travel in a private `--args` file, not in argv or any host process environment (`launcher.rs`), and inherited descriptors above 2 are closed by that launcher. No seccomp filter and no resource limits yet. Landlock is the fallback. Landlock is not layered inside because the kernel denies `mount` to a Landlock-restricted thread. |
| `crates/tinybox-jail/src/linux.rs` | Landlock backend (Linux only, `landlock` feature, on by default). Applies the ruleset to a dedicated spawn thread so no `unsafe` `pre_exec` is needed. |
| `crates/tinybox-jail/src/macos.rs` | Seatbelt backend via `sandbox-exec`. Compiled on every host so the profile renderer is unit-tested everywhere; selected only on macOS. |
| `crates/tinybox-jail/src/windows.rs` | AppContainer implementation; **not compiled**: it needs `unsafe` FFI the workspace forbids and cannot return a waitable `std::process::Child` yet. |
Expand Down
Loading
Loading