#!@runtimeShell@ test -n "$SANE_SANDBOX_DEBUG" && set -x cliArgs=() name= firejailProfile= rootPaths=() homePaths=() net= dns=() method= firejailFlags=() bwrapFlags=() debug() { [ -n "$SANE_SANDBOX_DEBUG" ] && printf "[debug] %s" "$1" >&2 } loadProfileByPath() { # profile format is simply a list of arguments one would pass to this sane-sandboxed script itself, # with one argument per line readarray -t _profArgs < <(cat "$1") parseArgs "${_profArgs[@]}" } tryLoadProfileByName() { if [ -z "$name" ]; then name="$1" fi _profileDirs=(@profileDirs@) for _profileDir in "${_profileDirs[@]}"; do _profile="$_profileDir/$1.profile" debug "try profile at path: '$_profile'" if [ -f "$_profile" ]; then loadProfileByPath "$_profile" break fi done if [ -z "$firejailProfile" ]; then _fjProfileDirs=(@firejailProfileDirs@) for _fjProfileDir in "${_fjProfileDirs[@]}"; do _fjProfile="$_fjProfileDir/$1.profile" debug "try firejail profile at path: '$_fjProfile'" if [ -f "$_fjProfile" ]; then firejailProfile="$_fjProfile" fi done fi } ## parse CLI args into the variables declared above ## args not intended for this helper are put into $parseArgsExtra parseArgs() { parseArgsExtra=() while [ "$#" -ne 0 ]; do _arg="$1" shift case "$_arg" in (--) # rest of args are for the CLI parseArgsExtra+=$@ break ;; (--sane-sandbox-debug) SANE_SANDBOX_DEBUG=1 set -x ;; (--sane-sandbox-replace-cli) # keep the sandbox flags, but clear any earlier CLI args. # this lets the user do things like `mpv --sane-sandbox-replace-cli sh` to enter a shell # with the sandbox that `mpv` would see. parseArgsExtra=() ;; (--sane-sandbox-disable) SANE_SANDBOX_DISABLE=1 ;; (--sane-sandbox-method) method="$1" shift ;; (--sane-sandbox-dns) # N.B.: these named temporary variables ensure that `set -x` causes $1 to be printed _dns="$1" dns+=("$_dns") shift ;; (--sane-sandbox-firejail-arg) _fjFlag="$1" firejailFlags+=("$_fjFlag") shift ;; (--sane-sandbox-bwrap-arg) _bwrapFlag="$1" bwrapFlags+=("$_bwrapFlag") shift ;; (--sane-sandbox-net) net="$1" shift ;; (--sane-sandbox-home-path) _path="$1" homePaths+=("$_path") shift ;; (--sane-sandbox-path) _path="$1" rootPaths+=("$_path") shift ;; (--sane-sandbox-profile) tryLoadProfileByName "$1" shift ;; (*) parseArgsExtra+=("$_arg") ;; esac done } ## FIREJAIL BACKEND firejailIngestRootPath() { firejailFlags+=("--noblacklist=$1" "--whitelist=$1") } firejailIngestHomePath() { firejailFlags+=("--noblacklist="'${HOME}/'"$1" "--whitelist="'${HOME}/'"$1") } firejailIngestNet() { firejailFlags+=("--net=$1") } firejailIngestDns() { firejailFlags+=("--dns=$1") } firejailIngestName() { firejailFlags+=("--join-or-start=$1") } firejailExec() { if [ -n "$firejailProfile" ]; then firejailFlags+=("--profile=$firejailProfile") fi PATH="$PATH:@firejail@/bin" exec firejail "${firejailFlags[@]}" -- "${cliArgs[@]}" } ## BUBBLEWRAP BACKEND bwrapIngestRootPath() { # N.B.: use --dev-bind-try instead of --dev-bind for platform-specific paths like /run/opengl-driver-32 # which don't exist on aarch64, as the -try variant will gracefully fail (i.e. not bind it). # N.B.: `test -r` for paths like /mnt/servo-media, which may otherwise break bwrap when offline with # "bwrap: Can't get type of source /mnt/...: Input/output error" test -r "$1" && bwrapFlags+=("--dev-bind-try" "$1" "$1") } bwrapIngestHomePath() { _path="$HOME/$1" # `test -r` isn't needed here, unless/until i try mounting a symlink like `~/Videos/servo` directly. bwrapFlags+=("--dev-bind" "$_path" "$_path") } bwrapIngestName() { echo "bwrap naming/labeling not yet implemented" } # WIP bwrapExec() { PATH="$PATH:@bubblewrap@/bin" exec bwrap --dev /dev --proc /proc "${bwrapFlags[@]}" -- "${cliArgs[@]}" } ## BACKEND HANDOFF parseArgs "$@" cliArgs+=("${parseArgsExtra[@]}") test -n "$SANE_SANDBOX_DISABLE" && exec "${cliArgs[@]}" ### convert generic args into sandbox-specific args # order matters: for firejail, early args override the later --profile args for _path in "${rootPaths[@]}"; do "$method"IngestRootPath "$_path" done for _path in "${homePaths[@]}"; do "$method"IngestHomePath "$_path" done if [ -n "$net" ]; then "$method"IngestNet "$net" fi for _addr in "${dns[@]}"; do "$method"IngestDns "$_addr" done if [ -n "$name" ]; then "$method"IngestName "$name" fi "$method"Exec echo "sandbox glue failed for method='$method'" exit 1