diff --git a/modules/programs/make-sandboxed.nix b/modules/programs/make-sandboxed.nix index 8f7956d37..4f1c0d11b 100644 --- a/modules/programs/make-sandboxed.nix +++ b/modules/programs/make-sandboxed.nix @@ -4,7 +4,8 @@ buildPackages, file, gnugrep, - makeBinaryWrapper, + gnused, + makeWrapper, runCommandLocal, runtimeShell, sanebox, @@ -60,7 +61,8 @@ let # the ordering here is specific: inject our deps BEFORE the unwrapped program's # so that the unwrapped's take precendence and we limit interference (e.g. makeWrapper impl) fakeSaneSandboxed - makeBinaryWrapper + gnugrep + makeWrapper ] ++ (unwrapped.nativeBuildInputs or []); disallowedReferences = (unwrapped.disallowedReferences or []) ++ [ # the fake sandbox gates itself behind SANEBOX_DISABLE, so if it did end up deployed @@ -73,15 +75,14 @@ let # my programs refer to sanebox by name, not path, which triggers an over-eager assertion in nixpkgs (so, mask that) : } - makeDocumentedCWrapper() { - # this is identical to nixpkgs' implementation, only replace execv with execvp, the latter which looks for the executable on PATH. - local src docs - src=$(makeCWrapper "$@") - src="''${src/return execv(/return execvp(}" - docs=$(docstring "$@") - printf '%s\n\n' "$src" - printf '%s\n' "$docs" - } + # makeDocumentedCWrapper() { + # # this is identical to nixpkgs' implementation, only replace execv with execvp, the latter which looks for the executable on PATH. + # local src=$(makeCWrapper "$@") + # src="''${src/return execv(/return execvp(}" + # local docs=$(docstring "$@") + # printf '%s\n\n' "$src" + # printf '%s\n' "$docs" + # } sandboxWrap() { local _dir="$1" @@ -90,8 +91,7 @@ let # N.B.: unlike stock `wrapProgram`, we place the unwrapped binary in a subdirectory and *preserve its name*. # the upside of this is that for applications which read "$0" to decide what to do (e.g. busybox, git) # they work as expected without any special hacks. - # if desired, makeWrapper-style naming could be achieved by leveraging `exec -a ` - # or `make-wrapper --inherit-argv0` + # though even so, the sandboxer still tries to preserve the $0 which it was invoked under mkdir -p "$_dir/.sandboxed" if [[ "$(readlink $_dir/$_name)" =~ ^\.\./ ]]; then # relative links which ascend a directory (into a non-bin/ directory) @@ -101,7 +101,13 @@ let else mv "$_dir/$_name" "$_dir/.sandboxed/" fi - makeBinaryWrapper ${sanebox'} "$_dir/$_name" --suffix PATH : /run/current-system/sw/libexec/sanebox ${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" f ]) extraSandboxArgs))} --add-flags "$_dir/.sandboxed/$_name" + makeShellWrapper ${sanebox'} "$_dir/$_name" --suffix PATH : /run/current-system/sw/libexec/sanebox \ + ${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" f ]) extraSandboxArgs))} \ + --add-flags "$_dir/.sandboxed/$_name" + # `exec`ing a script with an interpreter will smash $0. instead, source it to preserve $0: + # - + substituteInPlace "$_dir/$_name" \ + --replace-fail 'exec ' 'source ' } crawlAndWrap() { diff --git a/pkgs/additional/sanebox/sanebox b/pkgs/additional/sanebox/sanebox index 913fab5d6..210370f45 100755 --- a/pkgs/additional/sanebox/sanebox +++ b/pkgs/additional/sanebox/sanebox @@ -94,6 +94,14 @@ netGateway=default dns=() # VAR -> VALUE map of environment variables to add to the sandboxed program's environment declare -A portalEnv +argv0= +case "${0:-8}" in + ("sanebox"|"/sanebox") + ;; + (*) + argv0="$0" + ;; +esac # arguments to forward onto a specific backend (if that backend is active) bwrapArgs=() @@ -501,6 +509,7 @@ parseArgs() { # this lets the user do things like `mpv --sanebox-replace-cli sh` to enter a shell # with the sandbox that `mpv` would see. parseArgsExtra=() + argv0= ;; (--sanebox-disable) isDisable=1 @@ -754,7 +763,8 @@ bwrapGetCli() { done cliArgs=( - "$_bwrap" \ + "$_bwrap" + --argv0 "$argv0" "${bwrapUnshareCgroup[@]}" "${bwrapUnshareIpc[@]}" "${bwrapUnshareNet[@]}" @@ -921,7 +931,7 @@ capshonlyGetCli() { locate _capsh "capsh" "$CAPSH_FALLBACK" locate _env "env" "$ENV_FALLBACK" - local envArgs=() + local envArgs=(-a "$argv0") for envName in "${!portalEnv[@]}"; do envArgs+=("$envName=${portalEnv[$envName]}") done @@ -984,7 +994,7 @@ pastaonlyIngestCapability() { pastaonlyGetCli() { cliArgs=( "/bin/sh" "-c" - "$pastaNetSetup exec"' "$0" "$@"' + "$pastaNetSetup exec"' "$argv0" "$@"' "${cliArgs[@]}" ) locate _pasta "pasta" "$PASTA_FALLBACK" @@ -1032,7 +1042,7 @@ noneIngestCapability() { : } noneGetCli() { - : + cliArgs=(-a "$argv0" "${cliArgs[@]}") } @@ -1138,6 +1148,9 @@ parseArgsAndEnvironment() { parseArgs "$@" cliArgs+=("${parseArgsExtra[@]}") + if [ -z "$argv0" ]; then + argv0=${cliArgs[0]} + fi if [ -n "$SANEBOX_APPEND" ]; then parseArgs $SANEBOX_APPEND @@ -1175,6 +1188,9 @@ ingestForBackend() { ## TOPLEVEL EXECUTION # no code evaluated before this point should be dependent on user args / environment. +# TODO: use `set -e`, only i'm using `return 1` in places for control flow. +set +e + parseArgsAndEnvironment "$@" # variables meant to be inherited