diff options
| author | 2026-05-29 11:18:12 +0100 | |
|---|---|---|
| committer | 2026-05-29 11:18:12 +0100 | |
| commit | 1a8a19e6286aa58c5a46f03882f8f09e54456051 (patch) | |
| tree | 6d82622e37268ce466104f81cb3b53a20f0ad9b3 | |
| parent | 8ebe3f106e53dc4032428a2e3435c4feea969087 (diff) | |
| download | dotfiles-1a8a19e6286aa58c5a46f03882f8f09e54456051.tar.gz dotfiles-1a8a19e6286aa58c5a46f03882f8f09e54456051.tar.bz2 dotfiles-1a8a19e6286aa58c5a46f03882f8f09e54456051.zip | |
feat(sandbox): bwrap wrappers for mpv, yt-dlp, streamlink
These three tools are the native (non-flatpak) network parsers in the
install set — every other internet-facing app is already flatpak'd. The
threat model is a RCE in a subtitle/extractor/muxer that walks $HOME
looking for SSH keys, GPG keyring, pass store, cloud tokens, etc.
Approach (defence in depth, not full sandboxing):
- bwrap --bind / / keeps Wayland, PipeWire, DBus, GPU, hwaccel and all
config files working transparently.
- --tmpfs over known-sensitive dirs (.ssh, .gnupg, .password-store,
.config/gh, .config/op, .aws, .local/share/keyrings) blanks them
from the sandbox view; a compromised parser literally cannot see them.
- inner PATH stripped of ~/.local/bin so streamlink's spawn of `mpv`
resolves to /usr/bin/mpv and does not re-enter the sandbox.
- --die-with-parent + --new-session for tidy lifecycle.
- Escape hatch: SANDBOX=0 mpv ... bypasses for one invocation.
- Graceful degradation if bwrap is missing (warns and execs anyway).
bubblewrap added explicitly to meta/base.txt (was implicit via flatpak).
Wrappers in ~/.local/bin shadow /usr/bin via dot_zprofile:15 PATH order.
Not symlinked into the Ubuntu VM (nix/vm.nix does not touch ~/.local/bin),
which is fine: those tools on the headless VM don't need sandboxing.
| -rw-r--r-- | dot_local/bin/executable__sandbox-net-parser | 58 | ||||
| -rw-r--r-- | dot_local/bin/executable_mpv | 4 | ||||
| -rw-r--r-- | dot_local/bin/executable_streamlink | 5 | ||||
| -rw-r--r-- | dot_local/bin/executable_yt-dlp | 4 | ||||
| -rw-r--r-- | meta/base.txt | 4 |
5 files changed, 75 insertions, 0 deletions
diff --git a/dot_local/bin/executable__sandbox-net-parser b/dot_local/bin/executable__sandbox-net-parser new file mode 100644 index 0000000..648ad0f --- /dev/null +++ b/dot_local/bin/executable__sandbox-net-parser @@ -0,0 +1,58 @@ +#!/usr/bin/env sh +# Sandbox wrapper for tools that parse data from untrusted network +# sources (mpv, yt-dlp, streamlink). The threat model is RCE in a +# subtitle / muxer / extractor that walks the user's home directory +# looking for SSH/GPG keys, password store, cloud tokens, etc. +# +# Compromise: most of the system is still reachable (--bind / /), so +# Wayland, PipeWire, DBus, GPU, hardware accel and config files all +# work transparently; the sandbox only tmpfs-shadows known-sensitive +# directories so a compromised parser cannot read them. +# +# Set SANDBOX=0 to bypass entirely for a single invocation: +# SANDBOX=0 mpv weird-codec-file.mkv +# +# Usage (called by the per-tool wrappers): _sandbox-net-parser /usr/bin/mpv "$@" + +set -eu + +if [ "${SANDBOX:-1}" = "0" ]; then + bin=$1 + shift + exec "$bin" "$@" +fi + +if ! command -v bwrap >/dev/null 2>&1; then + printf '%s: bwrap not installed; falling back to direct exec\n' "$0" >&2 + bin=$1 + shift + exec "$bin" "$@" +fi + +bin=$1 +shift + +# Prevent re-entry: any tool spawned inside the sandbox that resolves +# `mpv`/`yt-dlp`/`streamlink` via PATH (e.g. streamlink launching mpv) +# must find the real binary, not another wrapper that would try to +# nest a second bwrap and fail. Strip ~/.local/bin and nix-profile/bin +# from PATH inside the namespace. +inner_path='/usr/local/sbin:/usr/local/bin:/usr/bin' + +exec bwrap \ + --bind / / \ + --dev-bind /dev /dev \ + --proc /proc \ + --tmpfs /root \ + --tmpfs "$HOME/.ssh" \ + --tmpfs "$HOME/.gnupg" \ + --tmpfs "$HOME/.password-store" \ + --tmpfs "$HOME/.config/gh" \ + --tmpfs "$HOME/.config/op" \ + --tmpfs "$HOME/.aws" \ + --tmpfs "$HOME/.local/share/keyrings" \ + --tmpfs "$HOME/.local/share/pass" \ + --setenv PATH "$inner_path" \ + --die-with-parent \ + --new-session \ + -- "$bin" "$@" diff --git a/dot_local/bin/executable_mpv b/dot_local/bin/executable_mpv new file mode 100644 index 0000000..ba6787b --- /dev/null +++ b/dot_local/bin/executable_mpv @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +# Thin wrapper: run /usr/bin/mpv inside _sandbox-net-parser. See that +# script for the threat model and the SANDBOX=0 escape hatch. +exec _sandbox-net-parser /usr/bin/mpv "$@" diff --git a/dot_local/bin/executable_streamlink b/dot_local/bin/executable_streamlink new file mode 100644 index 0000000..86ab12a --- /dev/null +++ b/dot_local/bin/executable_streamlink @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +# Thin wrapper: run /usr/bin/streamlink inside _sandbox-net-parser. The +# sandbox strips ~/.local/bin from PATH so streamlink's internal launch +# of `mpv` resolves to /usr/bin/mpv (avoids nested bwrap). +exec _sandbox-net-parser /usr/bin/streamlink "$@" diff --git a/dot_local/bin/executable_yt-dlp b/dot_local/bin/executable_yt-dlp new file mode 100644 index 0000000..3298e3f --- /dev/null +++ b/dot_local/bin/executable_yt-dlp @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +# Thin wrapper: run /usr/bin/yt-dlp inside _sandbox-net-parser. See that +# script for the threat model and the SANDBOX=0 escape hatch. +exec _sandbox-net-parser /usr/bin/yt-dlp "$@" diff --git a/meta/base.txt b/meta/base.txt index 3a0a73b..1f7cdd8 100644 --- a/meta/base.txt +++ b/meta/base.txt @@ -171,6 +171,10 @@ xorg-xwayland # needed for zbarcam's X11 preview # Misc brightnessctl +# Userspace sandbox helper (firejail-less). Used by ~/.local/bin wrappers +# for mpv/yt-dlp/streamlink to hide secrets from network parsers; also +# pulled transitively by flatpak. +bubblewrap # Volume/brightness OSD overlay (driven by ~/.config/sway/{vol,brightness}-osd.sh # writing percentages to $XDG_RUNTIME_DIR/wob.sock). wob |
