diff --git a/modules/programs/sane-sandboxed b/modules/programs/sane-sandboxed index 48c6ae83..ab65a1aa 100644 --- a/modules/programs/sane-sandboxed +++ b/modules/programs/sane-sandboxed @@ -74,7 +74,7 @@ bwrapFlags=() ## UTILITIES/BOILERPLATE -# `normPath nameOfOutVar "$path"` +# `normPath outVar "$path"` # remove duplicate //, reduce '.' and '..' (naively). # expects a full path as input # chomps trailing slashes. @@ -133,23 +133,35 @@ normPath() { # realpath --logical --no-symlinks --canonicalize-missing "$1" # } -# `parent nameOfOutVar "$path"` +# `parent outVar "$path"` # return the path to this file or directory's parent, even if the input doesn't exist. parent() { normPath "$1" "$2/.." - # normPath "$(dirname "$1")" } -# `locate ` => print the full path to `` if it's on PATH, else print `` +# `locate outVar ` => if `` is on PATH, then return that, else locate() { - command -v "$1" || echo "$2" + # N.B.: explicitly avoid returning the output of `command -v`, for optimization. + # unlike other bash builtins, `x="$(command -v y)"` forks, whereas just `command -v y` does not. + if command -v "$2" > /dev/null; then + declare -g "$1"="$2" + else + declare -g "$1"="$3" + fi } +# `urldecode outVar ` # convert e.g. `file:///Local%20Users/foo.mp3` to `file:///Local Users/foo.mp3` urldecode() { + local outVar="$1" + shift + # source: - : "${*//+/ }" - echo -e "${_//%/\\x}" + # replace each `+` with space + local i="${*//+/ }" + # then replace each `%` with `\x` + # and have `echo` evaluate the escape sequences + declare -g "$outVar"="$(echo -e "${i//%/\\x}")" } @@ -158,7 +170,7 @@ urldecode() { 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") + readarray -t _profArgs < "$1" parseArgs "${_profArgs[@]}" } @@ -228,7 +240,7 @@ tryArgAsPath() { # URI to an absolute path which is presumably on this vfs # commonly found when xdg-open/mimeo passes a path on to an application # if URIs to relative paths exist, this implementation doesn't support them - _path="/$(urldecode "${_arg:8}")" + urldecode _path "${_arg:7}" elif [ "${_path:0:1}" = "-" ]; then # 99% chance it's a CLI argument. if not, use `./-<...>` return @@ -401,7 +413,7 @@ firejailExec() { if [ -n "$firejailProfile" ]; then firejailFlags+=("--profile=$firejailProfile") fi - _firejail="$(locate firejail @firejail@/bin/firejail)" + locate _firejail "firejail" "@firejail@/bin/firejail" exec \ "$_firejail" "${firejailFlags[@]}" -- \ env "${extraEnv[@]}" "${cliArgs[@]}" @@ -451,7 +463,7 @@ bwrapExec() { # --unshare-cgroup # --unshare-uts # --unshare-user (implicit to every non-suid call to bwrap) - _bwrap="$(locate bwrap @bubblewrap@/bin/bwrap)" + locate _bwrap "bwrap" "@bubblewrap@/bin/bwrap" exec \ "$_bwrap" --unshare-cgroup --unshare-ipc --unshare-user --unshare-uts "${bwrapUnshareNet[@]}" "${bwrapUnsharePid[@]}" --dev /dev --proc /proc --tmpfs /tmp "${bwrapFlags[@]}" -- \ env "${extraEnv[@]}" "${cliArgs[@]}" @@ -517,8 +529,8 @@ landlockExec() { # so trampoline through `capsh` as well, to drop privs. # N.B: capsh passes its arg to bash (via /nix/store/.../bash), which means you have to `-c "my command"` to # invoke the actual user command. - _sandboxer="$(locate sandboxer @landlockSandboxer@/bin/sandboxer)" - _capsh="$(locate capsh @libcap@/bin/capsh)" + locate _sandboxer "sandboxer" "@landlockSandboxer@/bin/sandboxer" + locate _capsh "capsh" "@libcap@/bin/capsh" LL_FS_RO= LL_FS_RW="$landlockPaths" exec \ "$_sandboxer" \ "$_capsh" "--caps=$capshCapsArg" --no-new-privs --shell="/usr/bin/env" -- "${extraEnv[@]}" "${cliArgs[@]}" @@ -568,7 +580,7 @@ capshonlyIngestCapability() { } capshonlyExec() { - _capsh="$(locate capsh @libcap@/bin/capsh)" + locate _capsh "capsh" "@libcap@/bin/capsh" exec \ "$_capsh" "--caps=$capshCapsArg" --no-new-privs --shell="/usr/bin/env" -- "${extraEnv[@]}" "${cliArgs[@]}" }