sandboxing: fix checkSandboxed
to handle packages with multiple outputs
This commit is contained in:
parent
e3e86a43a9
commit
f875db916d
|
@ -39,7 +39,8 @@ let
|
|||
else
|
||||
let
|
||||
makeSandboxArgs = pkgs.callPackage ./make-sandbox-args.nix { };
|
||||
makeSandboxed = pkgs.callPackage ./make-sandboxed.nix { sanebox = config.sane.programs.sanebox.package; };
|
||||
# makeSandboxed = pkgs.callPackage ./make-sandboxed.nix { sanebox = config.sane.programs.sanebox.package; };
|
||||
makeSandboxed = pkgs.callPackage ./make-sandboxed.nix { };
|
||||
|
||||
vpn = lib.findSingle (v: v.default) null null (builtins.attrValues config.sane.vpn);
|
||||
|
||||
|
|
|
@ -229,43 +229,54 @@ let
|
|||
priority = ((prevAttrs.meta or {}).priority or 0) - 1;
|
||||
};
|
||||
passthru = (prevAttrs.passthru or {}) // extraPassthru // {
|
||||
checkSandboxed = runCommandLocal "${pkgName}-check-sandboxed" {} ''
|
||||
checkSandboxed = runCommandLocal "${pkgName}-check-sandboxed" {
|
||||
nativeBuildInputs = [ sanebox ];
|
||||
buildInputs = builtins.map (out: finalAttrs.finalPackage."${out}") (finalAttrs.outputs or [ "out" ]);
|
||||
} ''
|
||||
set -e
|
||||
# invoke each binary in a way only the sandbox wrapper will recognize,
|
||||
# ensuring that every binary has in fact been wrapped.
|
||||
_numExec=0
|
||||
_checkExecutable() {
|
||||
echo "checking if $1 is sandboxed"
|
||||
PATH="${finalAttrs.finalPackage}/bin:${sanebox}/bin:$PATH" \
|
||||
SANEBOX_DISABLE=1 \
|
||||
"$1" --sanebox-replace-cli echo "printing for test" \
|
||||
local dir="$1"
|
||||
local binname="$2"
|
||||
echo "checking if $dir/$binname is sandboxed"
|
||||
# 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.
|
||||
"$dir/$binname" --sanebox-replace-cli echo "printing for test" \
|
||||
| grep "printing for test"
|
||||
_numExec=$(( $_numExec + 1 ))
|
||||
}
|
||||
_checkDir() {
|
||||
for b in $(ls "$1"); do
|
||||
if [ -d "$1/$b" ]; then
|
||||
local dir="$1"
|
||||
for b in $(ls "$dir"); do
|
||||
if [ -d "$dir/$b" ]; then
|
||||
if [ "$b" != .sandboxed ]; then
|
||||
_checkDir "$1/$b"
|
||||
_checkDir "$dir/$b"
|
||||
fi
|
||||
elif [ -x "$1/$b" ]; then
|
||||
_checkExecutable "$1/$b"
|
||||
elif [ -x "$dir/$b" ]; then
|
||||
_checkExecutable "$dir" "$b"
|
||||
else
|
||||
test -n "$CHECK_DIR_NON_BIN"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# *everything* in the bin dir should be a wrapped executable
|
||||
if [ -e "${finalAttrs.finalPackage}/bin" ]; then
|
||||
_checkDir "${finalAttrs.finalPackage}/bin"
|
||||
fi
|
||||
for outDir in $buildInputs; do
|
||||
echo "starting crawl from package output: $outDir"
|
||||
# *everything* in the bin dir should be a wrapped executable
|
||||
if [ -e "$outDir/bin" ]; then
|
||||
echo "checking toplevel dir at $outDir/bin"
|
||||
_checkDir "$outDir/bin"
|
||||
fi
|
||||
|
||||
# the libexec dir is 90% wrapped executables, but sometimes also .so/.la objects.
|
||||
# note that this directory isn't flat
|
||||
if [ -e "${finalAttrs.finalPackage}/libexec" ]; then
|
||||
CHECK_DIR_NON_BIN=1 _checkDir "${finalAttrs.finalPackage}/libexec"
|
||||
fi
|
||||
# the libexec dir is 90% wrapped executables, but sometimes also .so/.la objects.
|
||||
# note that this directory isn't flat
|
||||
if [ -e "$outDir/libexec" ]; then
|
||||
echo "checking toplevel dir at $outDir/libexec"
|
||||
CHECK_DIR_NON_BIN=1 _checkDir "$outDir/libexec"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "successfully tested $_numExec binaries"
|
||||
test "$_numExec" -ne 0
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{ lib, stdenv
|
||||
, bash
|
||||
, bubblewrap
|
||||
, coreutils
|
||||
, passt
|
||||
, landlock-sandboxer
|
||||
, libcap
|
||||
|
@ -24,7 +25,8 @@ stdenv.mkDerivation {
|
|||
--replace-fail '@bwrap@' '${lib.getExe bubblewrap}' \
|
||||
--replace-fail '@landlockSandboxer@' '${lib.getExe landlock-sandboxer}' \
|
||||
--replace-fail '@capsh@' '${lib.getExe' libcap "capsh"}' \
|
||||
--replace-fail '@pasta@' '${lib.getExe' passt "pasta"}'
|
||||
--replace-fail '@pasta@' '${lib.getExe' passt "pasta"}' \
|
||||
--replace-fail '@env@' '${lib.getExe' coreutils "env"}'
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
|
@ -36,6 +38,16 @@ stdenv.mkDerivation {
|
|||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
runtimeDeps = [
|
||||
bubblewrap
|
||||
coreutils
|
||||
landlock-sandboxer
|
||||
libcap
|
||||
passt
|
||||
];
|
||||
};
|
||||
|
||||
meta = {
|
||||
description = ''
|
||||
helper program to run some other program in a sandbox.
|
||||
|
|
|
@ -6,6 +6,7 @@ BWRAP_FALLBACK='@bwrap@'
|
|||
LANDLOCK_SANDBOXER_FALLBACK='@landlockSandboxer@'
|
||||
CAPSH_FALLBACK='@capsh@'
|
||||
PASTA_FALLBACK='@pasta@'
|
||||
ENV_FALLBACK='@env@'
|
||||
|
||||
|
||||
## EARLY DEBUG HOOKS
|
||||
|
@ -254,13 +255,17 @@ parent() {
|
|||
|
||||
# `locate outVar <bin-name> </path/to/default>` => if `<bin-name>` is on PATH, then return that, else </path/to/default>
|
||||
locate() {
|
||||
# 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
|
||||
local outVar="$1"
|
||||
local bin="$2"
|
||||
local loc="$3"
|
||||
# N.B.: `bin=$(command -v $bin)` would make more sense, but it forks.
|
||||
for dir in ${PATH//:/ }; do
|
||||
if [ -e "$dir/$bin" ]; then
|
||||
loc="$dir/$bin"
|
||||
break
|
||||
fi
|
||||
done
|
||||
declare -g "$outVar"="$loc"
|
||||
}
|
||||
|
||||
# `urldecode outVar <uri>`
|
||||
|
@ -680,6 +685,7 @@ bwrapGetCli() {
|
|||
# --unshare-uts
|
||||
# --unshare-user (implicit to every non-suid call to bwrap)
|
||||
locate _bwrap "bwrap" "$BWRAP_FALLBACK"
|
||||
locate _env "env" "$ENV_FALLBACK"
|
||||
if [ -n "$bwrapUsePasta" ]; then
|
||||
# pasta drops us into an environment where we're root, but some apps complain if run as root.
|
||||
# TODO: this really belongs on the `pastaonlyGetCli` side.
|
||||
|
@ -697,7 +703,7 @@ bwrapGetCli() {
|
|||
"${bwrapUnshareUts[@]}"
|
||||
"${bwrapVirtualizeDev[@]}" "${bwrapVirtualizeProc[@]}" "${bwrapVirtualizeTmp[@]}"
|
||||
"${bwrapFlags[@]}" --
|
||||
env "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
"$_env" "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
)
|
||||
if [ -n "$bwrapUsePasta" ]; then
|
||||
pastaonlyGetCli
|
||||
|
@ -769,9 +775,10 @@ landlockGetCli() {
|
|||
# invoke the actual user command.
|
||||
locate _sandboxer "sandboxer" "$LANDLOCK_SANDBOXER_FALLBACK"
|
||||
locate _capsh "capsh" "$CAPSH_FALLBACK"
|
||||
cliArgs=(env LL_FS_RO= LL_FS_RW="$landlockPaths"
|
||||
locate _env "env" "$ENV_FALLBACK"
|
||||
cliArgs=("$_env" LL_FS_RO= LL_FS_RW="$landlockPaths"
|
||||
"$_sandboxer"
|
||||
"$_capsh" "--caps=$capshCapsArg" --no-new-privs --shell="/usr/bin/env" -- "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
"$_capsh" "--caps=$capshCapsArg" --no-new-privs --shell="$_env" -- "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -823,8 +830,9 @@ capshonlyIngestCapability() {
|
|||
|
||||
capshonlyGetCli() {
|
||||
locate _capsh "capsh" "$CAPSH_FALLBACK"
|
||||
locate _env "env" "$ENV_FALLBACK"
|
||||
cliArgs=(
|
||||
"$_capsh" "--caps=$capshCapsArg" --no-new-privs --shell="/usr/bin/env" -- "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
"$_capsh" "--caps=$capshCapsArg" --no-new-privs --shell="$_env" -- "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -911,6 +919,12 @@ noneGetCli() {
|
|||
## ARGUMENT POST-PROCESSING
|
||||
|
||||
loadLinkCache() {
|
||||
if ! [ -e /etc/sanebox/symlink-cache ]; then
|
||||
# don't error if the link cache is inaccessible.
|
||||
# this can happen during nix builds e.g.
|
||||
return
|
||||
fi
|
||||
|
||||
# readarray -t: reads some file into an array; each line becomes one element
|
||||
readarray -t _linkCacheArray < /etc/sanebox/symlink-cache
|
||||
for link in "${_linkCacheArray[@]}"; do
|
||||
|
|
Loading…
Reference in New Issue
Block a user