modules/programs: when sandboxing, use makeBinaryWrapper if supported

This commit is contained in:
2024-09-06 00:07:37 +00:00
parent b1b12c353d
commit 850c975321

View File

@@ -6,7 +6,8 @@
gnugrep,
gnused,
linkFarm,
makeWrapper,
makeBinaryWrapper,
makeShellWrapper,
runCommandLocal,
sanebox,
writeShellScriptBin,
@@ -59,7 +60,8 @@ let
# so that the unwrapped's take precendence and we limit interference (e.g. makeWrapper impl)
fakeSaneSandboxed
gnugrep
makeWrapper
makeBinaryWrapper
makeShellWrapper
] ++ (unwrapped.nativeBuildInputs or []);
disallowedReferences = (unwrapped.disallowedReferences or []) ++ [
# the fake sandbox gates itself behind SANEBOX_DISABLE, so if it did end up deployed
@@ -71,14 +73,14 @@ let
assertExecutable() {
: # 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=$(makeCWrapper "$@")
# src="''${src/return execv(/return execvp(}"
# local 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"
@@ -99,18 +101,26 @@ let
mv "$_dir/$_name" "$_dir/.sandboxed/"
fi
# N.B.: double `escapeShellArg`: once for the shell wrapper, and again for runtime because the shell wrapper doesn't escape.
# spotcheck this by seeing if animatch (requires a path "Holy Pangolin") works
makeShellWrapper ${sanebox'} "$_dir/$_name" --suffix PATH : /run/current-system/sw/libexec/${sanebox.pname} \
--inherit-argv0 \
${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" (lib.escapeShellArg f) ]) extraSandboxArgs))} \
--add-flags "$_dir/.sandboxed/$_name"
if [ -n "${sanebox.interpreter or ""}" ]; then
# N.B.: double `escapeShellArg`: once for the shell wrapper, and again for runtime because the shell wrapper doesn't escape.
# spotcheck this by seeing if animatch (requires a path "Holy Pangolin") works
makeShellWrapper ${sanebox'} "$_dir/$_name" \
--suffix PATH : /run/current-system/sw/libexec/${sanebox.pname} \
--inherit-argv0 \
${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" (lib.escapeShellArg f) ]) extraSandboxArgs))} \
--add-flags "$_dir/.sandboxed/$_name"
# `exec`ing a script with an interpreter will smash $0. instead, source it to preserve $0:
# - <https://github.com/NixOS/nixpkgs/issues/150841#issuecomment-995589961>
substituteInPlace "$_dir/$_name" \
--replace-fail 'exec -a "$0" ' 'source '
else
# we can use a binary shell wrapper since the wrapper's environment is capable of forwarding argv[0].
makeBinaryWrapper ${sanebox'} "$_dir/$_name" \
--suffix PATH : /run/current-system/sw/libexec/${sanebox.pname} \
--inherit-argv0 \
${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" f ]) extraSandboxArgs))} \
--add-flags "$_dir/.sandboxed/$_name"
fi
}
@@ -406,6 +416,8 @@ let
local dir="$1"
local binname="$2"
echo "checking if $dir/$binname is sandboxed"
echo " sandboxer is ${sanebox.name}"
echo " PATH=$PATH"
# XXX: call by full path because some binaries (e.g. util-linux) would otherwise
# be shadowed by things the nix builder implicitly puts on PATH.
# additionally, call via qemu and manually specify the interpreter *if the file has one*.
@@ -457,7 +469,7 @@ let
};
});
make-sandboxed = { pkgName, package, wrapperType, embedSandboxer ? false, extraSandboxerArgs ? [], passthru ? {} }@args:
make-sandboxed = { pkgName, package, wrapperType, embedSandboxer ? false, extraSandboxerArgs ? [], passthru ? {} }:
let
unsandboxed = package;
sanebox' = if embedSandboxer then