mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
feat: Add support for Landlock based Sandbox for Linux (#238)
* feat: Initial implementation of landlock based sandbox driver * fix: Handle seccom probe failure * fix: Remove unnecessary seccomp probe * fix: Use file based policy load * fix: Keep bpf filter in memory * fix: Use TSYNC for seccom filter * fix: Use TSYNC for seccom filter * fix: Update landlock translator * fix: Landlock sandbox implementation * fix: Landlock + seccomp based sandboxing on Linux * fix: Misc fixes * fix: Cleanup sandbox files * fix: Handle mandatory deny API change post merge * fix: Landlock write access translation * chore: Fix linter issues * ci: Use /tmp for npm cache for landlock
This commit is contained in:
+57
-3
@@ -48,7 +48,8 @@ like `${HOME}/**` do not opt out of `${HOME}/.aws`. The unnamed absolute form st
|
||||
|
||||
## Requirements
|
||||
|
||||
- Bubblewrap on Linux
|
||||
- Linux kernel 5.13+ with Landlock enabled (default, no external dependencies)
|
||||
- Bubblewrap on Linux (fallback for kernels < 5.13, or when `PMG_SANDBOX_DRIVER=bubblewrap` is set)
|
||||
- Seatbelt on MacOS
|
||||
|
||||
<details>
|
||||
@@ -203,13 +204,66 @@ Next time you run `pmg pnpm install`, the custom policy template will be used in
|
||||
| Platform | Supported | Implementation |
|
||||
| -------- | --------- | ----------------------------------- |
|
||||
| MacOS | Yes | Seatbelt sandbox-exec |
|
||||
| Linux | Yes | Bubblewrap with namespace isolation |
|
||||
| Linux | Yes | Landlock (default, kernel 5.13+) or Bubblewrap (fallback) |
|
||||
| Windows | No | Not yet supported |
|
||||
|
||||
### Platform-Specific Limitations
|
||||
|
||||
<details>
|
||||
<summary>Linux (Bubblewrap)</summary>
|
||||
<summary>Linux (Landlock, default)</summary>
|
||||
|
||||
**Default sandbox on kernel 5.13+**: Landlock provides kernel-native filesystem access control
|
||||
without requiring external binaries or unprivileged user namespaces.
|
||||
|
||||
For the architecture, design tradeoffs, and known limitations see
|
||||
[sandbox-landlock.md](./sandbox-landlock.md).
|
||||
|
||||
**Deny enforcement**: Deny rules (DenyRead, DenyWrite, DenyExec) are enforced via seccomp
|
||||
user notifications. This introduces a small TOCTOU window (microseconds) between reading
|
||||
the path and responding.
|
||||
|
||||
**Deny enforcement across the process tree**: seccomp-notify resolves the path argument of
|
||||
an intercepted `openat(2)` by reading `/proc/<pid>/mem` of the trapping process. PMG ships
|
||||
this in a two-stage architecture so enforcement applies to direct targets AND every
|
||||
descendant (grandchildren, great-grandchildren, etc.):
|
||||
|
||||
1. The helper process (`pmg __landlock_sandbox_exec`) clones a tiny shim
|
||||
(`pmg __landlock_shim`) with `CLONE_NEWUSER` and a uid/gid map of `0 -> host uid`.
|
||||
The shim runs as uid 0 inside a fresh user namespace so it has `CAP_SYS_ADMIN` in that
|
||||
namespace.
|
||||
2. The shim installs the seccomp-notify filter **without** `PR_SET_NO_NEW_PRIVS` (permitted
|
||||
by `CAP_SYS_ADMIN` in the ns). It then applies Landlock and `execve`s the real target.
|
||||
3. Because `NO_NEW_PRIVS` was never set, subsequent `execve` calls in the tree do **not**
|
||||
reset `dumpable` to 0, so the helper can keep opening `/proc/<pid>/mem` for any
|
||||
descendant. Deny rules like `~/.ssh` are enforced for the full process tree.
|
||||
|
||||
The user namespace is purely a capability vehicle. Host uid/gid are preserved through the
|
||||
mapping, so targets see the same filesystem ownership they normally would. Tools that
|
||||
refuse to run as root (npm's root-in-container warning) are unaffected because the
|
||||
outside-view uid never changes.
|
||||
|
||||
**Requirements**: unprivileged user namespaces must be enabled (`unprivileged_userns_clone=1`
|
||||
on Debian/Ubuntu; default on most modern distros). If disabled, the helper fails with an
|
||||
EPERM on `clone()` and the sandbox falls back to Bubblewrap.
|
||||
|
||||
**Network filtering**: Not enforced. Landlock supports TCP port filtering only (V4+, no hostname).
|
||||
Use `--proxy-mode` for network control.
|
||||
|
||||
**PID/IPC namespace isolation**: Applied best-effort via `CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS`.
|
||||
If unavailable, a warning is printed and the command continues. Set `PMG_SANDBOX_DRIVER=bubblewrap`
|
||||
to force Bubblewrap if namespace isolation is required.
|
||||
|
||||
**`/proc` access**: The sandbox supervisor requires `/proc` read access. When PID namespace
|
||||
isolation succeeds, `/proc` is scoped to the child's namespace. When it fails, `/proc`
|
||||
exposes all system processes.
|
||||
|
||||
**Fallback**: If Landlock is unavailable (kernel < 5.13), Bubblewrap is used automatically.
|
||||
Set `PMG_SANDBOX_DRIVER=bubblewrap` to force Bubblewrap.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Linux (Bubblewrap, fallback)</summary>
|
||||
|
||||
**Filesystem permissions are coarse-grained**: [Bubblewrap](https://github.com/containers/bubblewrap) uses bind mounts for filesystem isolation.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user