You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have searched existing requests and this hasn't been proposed yet
If this request came from a chat session issue, I included relevant session context and redacted secrets
Problem statement
Operators deploying MOLTIS without a container runtime (Fly.io Firecracker VMs, bare metal without Docker/Podman, corporate environments forbidding DinD) land on restricted-host, which provides env-clearing and ulimits but zero filesystem isolation (crates/tools/src/sandbox/platform.rs:209-214). Commands like cat /data/secrets/api_key or sqlite3 /data/home/memory.db .dump run unrestricted. The container sandbox solves this via namespaces but requires a runtime that many deployments don't have.
This interacts with — and complements — the other exec-layer gaps we've reported:
Argv-level path deny (#816) is userspace static analysis. Landlock is kernel-layer VFS enforcement. Together they form real defense-in-depth for sandbox-less deployments.
Proposed solution
Extend RestrictedHostSandbox with optional Landlock FS rules applied via pre_exec. The Linux landlock crate (v0.4.4, maintained by the kernel LSM author Mickaël Salaün, MIT/Apache-2.0, ~6.7M downloads) provides the Rust API.
Config API is an open design question — happy to iterate with maintainers. Two candidate interfaces:
Option A — fs_allow_paths (matches Landlock native semantics):
[sandbox]
backend = \"restricted-host\"fs_allow_paths = [\"/usr\", \"/bin\", \"/lib\", \"/tmp\", \"/data/home/workspace\"]# Everything outside = denied by Landlock at VFS layer
Operator expresses negative intent. Implementation constructs implicit safe-default allow set and omits the denied paths. More intuitive but requires carefully-chosen defaults.
Option C — both with rules-based composition.
Option A is implementation-simpler and matches kernel semantics. Option B matches what operators actually want to express. Preference depends on whether maintainers want to invest in the allow-set default curation. Would value your input before committing to either.
Insertion point:RestrictedHostSandbox::exec() at platform.rs:220 — build ruleset in parent, apply in child via cmd.pre_exec(move || ruleset.restrict_self()?). Standard pattern, async-signal-safe (Landlock syscalls are raw libc, no allocations or locks).
Use best_effort() mode so MOLTIS runs unchanged on kernels < 5.13; log warn! when restrictions couldn't be applied.
Alternatives considered
Container sandbox (Docker/Podman) — requires runtime not available on Fly.io Firecracker, bare metal installs, restricted corporate environments
bubblewrap/firejail — require setuid binaries not present in constrained environments; adds deployment complexity
seccomp path filtering — possible but requires BPF programs order-of-magnitude more complex than Landlock's declarative API
chroot() — classic, but requires root, can be escaped, outdated
Implementation outline
Approximately 110 LOC, ~1-2 days for a Rust engineer familiar with the codebase:
Add landlock = { version = \"0.4\", optional = true } to crates/tools/Cargo.toml with cfg(target_os = \"linux\")
Add FS policy fields to SandboxConfig in crates/tools/src/sandbox/types.rs (and the corresponding schema crate) with #[serde(default)]
In RestrictedHostSandbox::exec() at platform.rs:220: if policy is non-empty and cfg(target_os = \"linux\"), build RulesetCreated handling all AccessFs rights, add path_beneath allow rules, apply via cmd.pre_exec
Handle RulesetCreated ownership in pre_exec closure — may need to rebuild ruleset from path list inside the closure if RulesetCreated isn't Send
Acceptance criteria
Configured deny (or allow) policy causes cat /data/secrets/foo inside restricted-host exec to fail with EACCES / exit code 1
Empty/default config produces identical behavior to current restricted-host (back-compat)
MOLTIS starts normally on kernel < 5.13 via best_effort() (no hard fail)
warn! emitted when Landlock restrictions could not be applied
Linux-only: compiles and passes all tests on macOS without the Landlock code path
No regression in existing restricted_host.rs tests
Category
Sandbox
How important is this to your workflow?
Medium — would be very helpful
Additional context
Fly.io kernel version verified:6.12.47-fly (well above the 5.13 ABI v1 minimum — we'd get modern Landlock including ABI v3 TRUNCATE and ABI v4 network-port restrictions if future features want them).
Tradeoff vs container sandbox — Landlock is weaker than full namespace isolation (no network/process isolation, same PID namespace, only kernel VFS enforcement). But it's infinitely stronger than current restricted-host which has zero FS isolation, and it works where containers can't.
Honest gap — allowlist vs denylist semantics: Landlock is fundamentally allowlist — its path_beneath rules permit access. Expressing operator intent "deny /data/secrets" requires either (a) fs_allow_paths where operator enumerates the positive set, or (b) fs_deny_paths with implementation-provided safe-default allow set minus denied paths. The config-API question above is which way makes sense for MOLTIS.
Reference files for implementation:
crates/tools/src/sandbox/platform.rs:220 — insertion point for pre_exec
crates/tools/src/sandbox/types.rs:153 — SandboxConfig where new fields go
crates/tools/src/sandbox/router.rs:235-238 — restricted-host backend selection (no changes needed)
crates/tools/src/sandbox/tests/restricted_host.rs — test suite to extend
Preflight Checklist
Problem statement
Operators deploying MOLTIS without a container runtime (Fly.io Firecracker VMs, bare metal without Docker/Podman, corporate environments forbidding DinD) land on
restricted-host, which provides env-clearing and ulimits but zero filesystem isolation (crates/tools/src/sandbox/platform.rs:209-214). Commands likecat /data/secrets/api_keyorsqlite3 /data/home/memory.db .dumprun unrestricted. The container sandbox solves this via namespaces but requires a runtime that many deployments don't have.This interacts with — and complements — the other exec-layer gaps we've reported:
LD_PRELOAD=/path cat /secret)cat/sed/echo)Argv-level path deny (#816) is userspace static analysis. Landlock is kernel-layer VFS enforcement. Together they form real defense-in-depth for sandbox-less deployments.
Proposed solution
Extend
RestrictedHostSandboxwith optional Landlock FS rules applied viapre_exec. The Linuxlandlockcrate (v0.4.4, maintained by the kernel LSM author Mickaël Salaün, MIT/Apache-2.0, ~6.7M downloads) provides the Rust API.Config API is an open design question — happy to iterate with maintainers. Two candidate interfaces:
Option A —
fs_allow_paths(matches Landlock native semantics):Operator expresses positive intent. Matches Landlock's allowlist model exactly. Simpler implementation.
Option B —
fs_deny_paths(matches operator intuition):Operator expresses negative intent. Implementation constructs implicit safe-default allow set and omits the denied paths. More intuitive but requires carefully-chosen defaults.
Option C — both with rules-based composition.
Option A is implementation-simpler and matches kernel semantics. Option B matches what operators actually want to express. Preference depends on whether maintainers want to invest in the allow-set default curation. Would value your input before committing to either.
Insertion point:
RestrictedHostSandbox::exec()atplatform.rs:220— build ruleset in parent, apply in child viacmd.pre_exec(move || ruleset.restrict_self()?). Standard pattern, async-signal-safe (Landlock syscalls are raw libc, no allocations or locks).Use
best_effort()mode so MOLTIS runs unchanged on kernels < 5.13; logwarn!when restrictions couldn't be applied.Alternatives considered
$(...), base64 obfuscation, variable expansion, or indirect reads. Landlock enforces at the kernel VFS layer regardless of shell tricksImplementation outline
Approximately 110 LOC, ~1-2 days for a Rust engineer familiar with the codebase:
landlock = { version = \"0.4\", optional = true }tocrates/tools/Cargo.tomlwithcfg(target_os = \"linux\")SandboxConfigincrates/tools/src/sandbox/types.rs(and the corresponding schema crate) with#[serde(default)]RestrictedHostSandbox::exec()atplatform.rs:220: if policy is non-empty andcfg(target_os = \"linux\"), buildRulesetCreatedhandling allAccessFsrights, addpath_beneathallow rules, apply viacmd.pre_exec#[cfg(target_os = \"linux\")]integration tests verifying denied paths return EACCESRulesetCreatedownership inpre_execclosure — may need to rebuild ruleset from path list inside the closure ifRulesetCreatedisn'tSendAcceptance criteria
cat /data/secrets/fooinsiderestricted-hostexec to fail with EACCES / exit code 1best_effort()(no hard fail)warn!emitted when Landlock restrictions could not be appliedrestricted_host.rstestsCategory
Sandbox
How important is this to your workflow?
Medium — would be very helpful
Additional context
Fly.io kernel version verified:
6.12.47-fly(well above the 5.13 ABI v1 minimum — we'd get modern Landlock including ABI v3TRUNCATEand ABI v4 network-port restrictions if future features want them).Tradeoff vs container sandbox — Landlock is weaker than full namespace isolation (no network/process isolation, same PID namespace, only kernel VFS enforcement). But it's infinitely stronger than current
restricted-hostwhich has zero FS isolation, and it works where containers can't.Honest gap — allowlist vs denylist semantics: Landlock is fundamentally allowlist — its
path_beneathrules permit access. Expressing operator intent "deny/data/secrets" requires either (a)fs_allow_pathswhere operator enumerates the positive set, or (b)fs_deny_pathswith implementation-provided safe-default allow set minus denied paths. The config-API question above is which way makes sense for MOLTIS.Reference files for implementation:
crates/tools/src/sandbox/platform.rs:220— insertion point forpre_execcrates/tools/src/sandbox/types.rs:153—SandboxConfigwhere new fields gocrates/tools/src/sandbox/router.rs:235-238—restricted-hostbackend selection (no changes needed)crates/tools/src/sandbox/tests/restricted_host.rs— test suite to extendlandlockcrate on crates.io