make-sandboxed: fix several edge-cases for e.g. brave, firefox, especially around handling of wrapped binaries

This commit is contained in:
2024-08-16 02:15:46 +00:00
parent f3df321713
commit a552ed625b

View File

@@ -156,7 +156,9 @@ let
for item in "''${items[@]}"; do
if [ "$item" != . ] && [ "$item" != .. ]; then
local target="$_dir/$item"
if [ -x "$target" ] && ! [ -d "$target" ]; then
if [ -d "$target" ]; then
crawlAndWrap "$output" "$target"
elif [ -x "$target" ] && [[ "$item" != .* ]]; then
# in the case of symlinks, deref until we find the real file, or the symlink points outside the package
target=$(derefWhileInSameOutput "$output" "$target")
target=$(findUnwrapped "$target")
@@ -165,10 +167,8 @@ let
local bin=$(basename "$target")
sandboxWrap "$parent" "$bin"
fi
elif [ -d "$target" ]; then
crawlAndWrap "$output" "$target"
fi
# ignore all non-binaries
# ignore all non-binaries or "hidden" binaries (to avoid double-wrapping)
fi
done
}
@@ -196,15 +196,14 @@ let
;
# helper used for `wrapperType == "wrappedDerivation"` which simply symlinks all a package's binaries into a new derivation
symlinkBinaries = pkgName: package: (runCommandLocal "${pkgName}-bin-only" {
symlinkDirs = suffix: symlinkRoots: pkgName: package: (runCommandLocal "${pkgName}-${suffix}" {
env.symlinkRoots = lib.concatStringsSep " " symlinkRoots;
nativeBuildInputs = [ gnused ];
} ''
set -e
symlinkPath() {
if [ -e "$out/$1" ]; then
: # already linked. may happen when e.g. the package has bin/foo, and sbin -> bin.
elif ! [ -x "${package}/$1" ]; then
: # not a binary, nor a directory (-x) which could contain binaries
elif [ -L "${package}/$1" ]; then
local target=$(readlink "${package}/$1")
if [[ "$target" =~ ^${package}/ ]]; then
@@ -235,7 +234,7 @@ let
mkdir -p "$out/$1"
items=($(ls -a "${package}/$1"))
for item in "''${items[@]}"; do
if [ "$item" != . ] && [ "$item" != .. ]; then
if [ "$item" != . ] && [ "$item" != .. ] && [[ "$item" != .* ]]; then
symlinkPath "$1/$item"
fi
done
@@ -244,16 +243,22 @@ let
ln -s "${package}/$1" "$out/$1"
fi
}
symlinkPath bin
symlinkPath sbin
symlinkPath libexec
# allow downstream wrapping to hook this (and thereby actually wrap the binaries)
mkdir -p "$out"
_symlinkRoots=($symlinkRoots)
for root in "''${_symlinkRoots[@]}"; do
echo "crawling top-level directory for symlinking: $root"
symlinkPath "$root"
done
# allow downstream wrapping to hook this (and thereby actually wrap binaries, etc)
runHook postInstall
runHook postFixup
'').overrideAttrs (_: {
# specifically, preserve meta.priority
meta = extractMeta package;
});
symlinkBinaries = symlinkDirs "bin-only" [ "bin" "sbin" "libexec" ];
# helper used for `wrapperType == "wrappedDerivation"` which ensures that any copied/symlinked share/ files (like .desktop) files
# don't point to the unwrapped binaries.
# other important files it preserves:
@@ -281,12 +286,9 @@ let
}
# remove any files which exist in sandoxedBin (makes it possible to sandbox /opt-style packages)
# also remove any files which would be "hidden". mostly useful for /opt-style packages which contain nix-wrapped binaries.
removeUnwanted() {
local file_=$(basename "$1")
if [[ "$file_" == .* ]]; then
rm -r "$out/$1"
elif [ -f "$out/$1" ] || [ -L "$out/$1" ]; then
if [ -f "$out/$1" ] || [ -L "$out/$1" ]; then
if [ -e "${sandboxedBin}/$1" ]; then
rm "$out/$1"
fi
@@ -320,8 +322,6 @@ let
passthru = (prevAttrs.passthru or {}) // {
# check that sandboxedNonBin references only sandboxed binaries, and never the original unsandboxed binaries.
# do this by dereferencing all sandboxedNonBin symlinks, and making `unsandboxed` a disallowedReference.
# further, since the sandboxed binaries intentionally reference the unsandboxed binaries,
# we have to patch those out as a way to whitelist them.
checkSandboxed = let
sandboxedNonBin = fixHardcodedRefs unsandboxed sandboxedBin unsandboxedNonBin;
in runCommandLocal "${sandboxedNonBin.name}-check-sandboxed"
@@ -342,25 +342,7 @@ let
# patch them to use the sandboxed binaries,
# and add some passthru metadata to enforce no lingering references to the unsandboxed binaries.
sandboxNonBinaries = pkgName: unsandboxed: sandboxedBin: let
sandboxedWithoutFixedRefs = (runCommandLocal "${pkgName}-sandboxed-non-binary" {
nativeBuildInputs = [ xorg.lndir ];
} ''
set -e
mkdir "$out"
# link in a limited subset of the directories.
# lib/ is the primary one to avoid, because of shared objects that would be unsandboxed if dlopen'd.
# all other directories are safe-ish, because they won't end up on PATH or LDPATH.
for dir in etc share; do
if [ -e "${unsandboxed}/$dir" ]; then
mkdir "$out/$dir"
lndir "${unsandboxed}/$dir" "$out/$dir"
fi
done
runHook postInstall
'').overrideAttrs (_: {
# specifically for meta.priority, though it shouldn't actually matter here.
meta = extractMeta unsandboxed;
});
sandboxedWithoutFixedRefs = symlinkDirs "non-bin" [ "etc" "share" ] pkgName unsandboxed;
in fixHardcodedRefs unsandboxed sandboxedBin sandboxedWithoutFixedRefs;
# take the nearly-final sandboxed package, with binaries and all else, and