make-sandboxed: preserve outputs of multiple-output packages
especially, this fixes the dconf service, since we keep '/libexec'
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
file,
|
file,
|
||||||
gnugrep,
|
gnugrep,
|
||||||
gnused,
|
gnused,
|
||||||
|
linkFarm,
|
||||||
makeWrapper,
|
makeWrapper,
|
||||||
runCommandLocal,
|
runCommandLocal,
|
||||||
runtimeShell,
|
runtimeShell,
|
||||||
@@ -55,9 +56,7 @@ let
|
|||||||
env = (unwrapped.env or {}) // {
|
env = (unwrapped.env or {}) // {
|
||||||
SANEBOX_DISABLE = 1;
|
SANEBOX_DISABLE = 1;
|
||||||
};
|
};
|
||||||
# TODO: handle multi-output packages; until then, squash lib into the main output, particularly for `libexec`.
|
outputs = unwrapped.outputs or [ "out" ];
|
||||||
# (this line here only affects `inplace` style wrapping)
|
|
||||||
outputs = lib.remove "lib" (unwrapped.outputs or [ "out" ]);
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
# the ordering here is specific: inject our deps BEFORE the unwrapped program's
|
# 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)
|
# so that the unwrapped's take precendence and we limit interference (e.g. makeWrapper impl)
|
||||||
@@ -197,59 +196,77 @@ let
|
|||||||
;
|
;
|
||||||
|
|
||||||
# helper used for `wrapperType == "wrappedDerivation"` which simply symlinks all a package's binaries into a new derivation
|
# helper used for `wrapperType == "wrappedDerivation"` which simply symlinks all a package's binaries into a new derivation
|
||||||
symlinkDirs = suffix: symlinkRoots: pkgName: package: (runCommandLocal "${pkgName}-${suffix}" {
|
symlinkDirs = suffix: symlinkRoots: pkgName: package: let
|
||||||
|
# remove altogether some problem outputs which i don't have a use for in the deployed system
|
||||||
|
outputs = lib.remove "dev" (package.outputs or [ "out" ]);
|
||||||
|
in (runCommandLocal "${pkgName}-${suffix}" {
|
||||||
env.symlinkRoots = lib.concatStringsSep " " symlinkRoots;
|
env.symlinkRoots = lib.concatStringsSep " " symlinkRoots;
|
||||||
nativeBuildInputs = [ gnused ];
|
nativeBuildInputs = [ gnused ];
|
||||||
|
inherit outputs;
|
||||||
|
propagatedBuildOutputs = [ ]; #< disable propagation, since we disabled the `dev` output via which things are ordinarily propagated
|
||||||
} ''
|
} ''
|
||||||
set -e
|
set -e
|
||||||
symlinkPath() {
|
symlinkPath() {
|
||||||
if [ -e "$out/$1" ]; then
|
local inbase="$1"
|
||||||
|
local outbase="$2"
|
||||||
|
local path="$3"
|
||||||
|
if [ -e "$outbase/$path" ]; then
|
||||||
: # already linked. may happen when e.g. the package has bin/foo, and sbin -> bin.
|
: # already linked. may happen when e.g. the package has bin/foo, and sbin -> bin.
|
||||||
elif [ -L "${package}/$1" ]; then
|
elif [ -L "$inbase/$path" ]; then
|
||||||
local target=$(readlink "${package}/$1")
|
local target=$(readlink "$inbase/$path")
|
||||||
if [[ "$target" =~ ^${package}/ ]]; then
|
if [[ "$target" =~ ^$inbase/ ]]; then
|
||||||
# absolute link back into the same package
|
# absolute link back into the same package
|
||||||
echo "handling $1: descending into absolute symlink to same package: $target"
|
echo "handling $path: descending into absolute symlink to same package: $target"
|
||||||
target=$(echo "$target" | sed 's:${package}/::')
|
target=$(echo "$target" | sed 's:${package}/::')
|
||||||
ln -s "$out/$target" "$out/$1"
|
ln -s "$outbase/$target" "$outbase/$path"
|
||||||
# create/link the backing path
|
# create/link the backing path
|
||||||
# N.B.: if some leading component of the backing path is also a symlink... this might not work as expected.
|
# N.B.: if some leading component of the backing path is also a symlink... this might not work as expected.
|
||||||
local parent=$(dirname "$out/$target")
|
local parent=$(dirname "$out/$target")
|
||||||
mkdir -p "$parent"
|
mkdir -p "$parent"
|
||||||
symlinkPath "$target"
|
symlinkPath "$inbase" "$outbase" "$target"
|
||||||
elif [[ "$target" =~ ^/nix/store/ ]]; then
|
elif [[ "$target" =~ ^/nix/store/ ]]; then
|
||||||
# absolute link to another package
|
# absolute link to another package
|
||||||
echo "handling $1: symlinking absolute store path: $target"
|
echo "handling $path: symlinking absolute store path: $target"
|
||||||
ln -s "$target" "$out/$1"
|
ln -s "$target" "$outbase/$path"
|
||||||
else
|
else
|
||||||
# relative link
|
# relative link
|
||||||
echo "handling $1: descending into relative symlink: $target"
|
echo "handling $path: descending into relative symlink: $target"
|
||||||
ln -s "$target" "$out/$1"
|
ln -s "$target" "$outbase/$path"
|
||||||
local parent=$(dirname "$1")
|
local parent=$(dirname "$path")
|
||||||
local derefParent=$(dirname "$out/$parent/$target")
|
local derefParent=$(dirname "$outbase/$parent/$target")
|
||||||
$(set -x && mkdir -p "$derefParent")
|
$(set -x && mkdir -p "$derefParent")
|
||||||
symlinkPath "$parent/$target"
|
symlinkPath "$inbase" "$outbase" "$parent/$target"
|
||||||
fi
|
fi
|
||||||
elif [ -d "${package}/$1" ]; then
|
elif [ -d "$inbase/$path" ]; then
|
||||||
echo "handling $1: descending into directory"
|
echo "handling $path: descending into directory"
|
||||||
mkdir -p "$out/$1"
|
mkdir -p "$outbase/$path"
|
||||||
items=($(ls -a "${package}/$1"))
|
items=($(ls -a "$inbase/$path"))
|
||||||
for item in "''${items[@]}"; do
|
for item in "''${items[@]}"; do
|
||||||
if [ "$item" != . ] && [ "$item" != .. ] && [[ "$item" != .* ]]; then
|
if [ "$item" != . ] && [ "$item" != .. ] && [[ "$item" != .* ]]; then
|
||||||
symlinkPath "$1/$item"
|
symlinkPath "$inbase" "$outbase" "$path/$item"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
elif [ -e "${package}/$1" ]; then
|
elif [ -e "$inbase/$path" ]; then
|
||||||
echo "handling $1: symlinking ordinary file"
|
echo "handling $path: symlinking ordinary file"
|
||||||
ln -s "${package}/$1" "$out/$1"
|
ln -s "$inbase/$path" "$outbase/$path"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
mkdir -p "$out"
|
|
||||||
_symlinkRoots=($symlinkRoots)
|
crawlOutput() {
|
||||||
for root in "''${_symlinkRoots[@]}"; do
|
local inbase="$1"
|
||||||
echo "crawling top-level directory for symlinking: $root"
|
local outbase="$2"
|
||||||
symlinkPath "$root"
|
mkdir -p "$outbase"
|
||||||
done
|
_symlinkRoots=($symlinkRoots)
|
||||||
|
for root in "''${_symlinkRoots[@]}"; do
|
||||||
|
echo "crawling top-level directory for symlinking: $inbase/$root -> $outbase"
|
||||||
|
symlinkPath "$inbase" "$outbase" "$root"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
${lib.concatMapStringsSep "\n" (o:
|
||||||
|
"crawlOutput ${package."${o}"} $" + o
|
||||||
|
) outputs}
|
||||||
|
|
||||||
# allow downstream wrapping to hook this (and thereby actually wrap binaries, etc)
|
# allow downstream wrapping to hook this (and thereby actually wrap binaries, etc)
|
||||||
runHook postInstall
|
runHook postInstall
|
||||||
runHook postFixup
|
runHook postFixup
|
||||||
@@ -288,55 +305,67 @@ let
|
|||||||
|
|
||||||
# remove any files which exist in sandoxedBin (makes it possible to sandbox /opt-style packages)
|
# remove any files which exist in sandoxedBin (makes it possible to sandbox /opt-style packages)
|
||||||
removeUnwanted() {
|
removeUnwanted() {
|
||||||
local file_=$(basename "$1")
|
local outbase="$1"
|
||||||
if [ -f "$out/$1" ] || [ -L "$out/$1" ]; then
|
local path="$2"
|
||||||
if [ -e "${sandboxedBin}/$1" ]; then
|
local file_=$(basename "$path")
|
||||||
rm "$out/$1"
|
if [ -f "$outbase/$path" ] || [ -L "$outbase/$path" ]; then
|
||||||
fi
|
for sboxBase in ${lib.concatStringsSep " " sandboxedBin.all}; do
|
||||||
elif [ -d "$out/$1" ]; then
|
if [ -e "$sboxBase/$path" ]; then
|
||||||
local files=($(ls -a "$out/$1"))
|
rm "$outbase/$path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
elif [ -d "$outbase/$path" ]; then
|
||||||
|
local files=($(ls -a "$outbase/$path"))
|
||||||
for item in "''${files[@]}"; do
|
for item in "''${files[@]}"; do
|
||||||
if [ "$item" != . ] && [ "$item" != .. ]; then
|
if [ "$item" != . ] && [ "$item" != .. ]; then
|
||||||
removeUnwanted "$1/$item"
|
removeUnwanted "$outbase" "$path/$item"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
removeUnwanted ""
|
|
||||||
|
|
||||||
# fixup a few files i understand well enough
|
for output in $outputs; do
|
||||||
for d in \
|
local outdir=''${!output}
|
||||||
$out/etc/xdg/autostart/*.desktop \
|
removeUnwanted "$outdir" ""
|
||||||
$out/share/applications/*.desktop \
|
|
||||||
$out/share/dbus-1/{services,system-services}/*.service \
|
# fixup a few files i understand well enough
|
||||||
$out/{etc,lib,share}/systemd/{system,user}/*.service \
|
for d in \
|
||||||
; do
|
$outdir/etc/xdg/autostart/*.desktop \
|
||||||
# Exec: dbus and desktop files
|
$outdir/share/applications/*.desktop \
|
||||||
# ExecStart,ExecReload: systemd service files
|
$outdir/share/dbus-1/{services,system-services}/*.service \
|
||||||
for key in Exec ExecStart ExecReload; do
|
$outdir/{etc,lib,share}/systemd/{system,user}/*.service \
|
||||||
for binLoc in bin libexec sbin; do
|
; do
|
||||||
trySubstitute "$d" "$key=%s/$binLoc/"
|
# Exec: dbus and desktop files
|
||||||
|
# ExecStart,ExecReload: systemd service files
|
||||||
|
for key in Exec ExecStart ExecReload; do
|
||||||
|
for binLoc in bin libexec sbin; do
|
||||||
|
trySubstitute "$d" "$key=%s/$binLoc/"
|
||||||
|
done
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
passthru = (prevAttrs.passthru or {}) // {
|
passthru = let
|
||||||
# check that sandboxedNonBin references only sandboxed binaries, and never the original unsandboxed binaries.
|
# 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.
|
# do this by dereferencing all sandboxedNonBin symlinks, and making `unsandboxed` a disallowedReference.
|
||||||
checkSandboxed = let
|
sandboxedNonBin = fixHardcodedRefs unsandboxed sandboxedBin unsandboxedNonBin;
|
||||||
sandboxedNonBin = fixHardcodedRefs unsandboxed sandboxedBin unsandboxedNonBin;
|
outputs = sandboxedNonBin.outputs or [ "out" ];
|
||||||
in runCommandLocal "${sandboxedNonBin.name}-check-sandboxed"
|
checkSandboxed = runCommandLocal "${sandboxedNonBin.name}-check-sandboxed"
|
||||||
{ disallowedReferences = [ unsandboxed ]; }
|
{
|
||||||
|
inherit outputs;
|
||||||
|
disallowedReferences = [ unsandboxed ];
|
||||||
|
passthru.flat = linkFarm "${sandboxedNonBin.name}-check-sandboxed-flat" (builtins.map (o: { name = o; path = checkSandboxed."${o}"; }) outputs);
|
||||||
|
}
|
||||||
# dereference every symlink, ensuring that whatever data is behind it does not reference non-sandboxed binaries.
|
# dereference every symlink, ensuring that whatever data is behind it does not reference non-sandboxed binaries.
|
||||||
# the dereference *can* fail, in case it's a relative symlink that refers to a part of the non-binaries we don't patch.
|
# the dereference *can* fail, in case it's a relative symlink that refers to a part of the non-binaries we don't patch.
|
||||||
# in such case, this could lead to weird brokenness (e.g. no icons/images), so failing is reasonable.
|
# in such case, this could lead to weird brokenness (e.g. no icons/images), so failing is reasonable.
|
||||||
# N.B.: this `checkSandboxed` protects against accidentally referencing unsandboxed binaries from data files (.deskop, .service, etc).
|
# N.B.: this `checkSandboxed` protects against accidentally referencing unsandboxed binaries from data files (.deskop, .service, etc).
|
||||||
# there's an *additional* `checkSandboxed` further below which invokes every executable in the final package to make sure the binaries are truly sandboxed.
|
# there's an *additional* `checkSandboxed` further below which invokes every executable in the final package to make sure the binaries are truly sandboxed.
|
||||||
''
|
(lib.concatMapStringsSep "\n" (o:
|
||||||
cp -R --dereference "${sandboxedNonBin}" "$out" # IF YOUR BUILD FAILS HERE, TRY SANDBOXING WITH "inplace"
|
"cp -R --dereference ${sandboxedNonBin."${o}"} $" + o
|
||||||
''
|
) sandboxedNonBin.outputs or [ "out" ])
|
||||||
;
|
;
|
||||||
};
|
in (prevAttrs.passthru or {}) // { inherit checkSandboxed; };
|
||||||
});
|
});
|
||||||
|
|
||||||
# symlink the non-binary files from the unsandboxed package,
|
# symlink the non-binary files from the unsandboxed package,
|
||||||
@@ -414,7 +443,7 @@ let
|
|||||||
test "$_numExec" -ne 0
|
test "$_numExec" -ne 0
|
||||||
mkdir "$out"
|
mkdir "$out"
|
||||||
# forward prevAttrs checkSandboxed, to guarantee correctness for the /share directory (`sandboxNonBinaries`).
|
# forward prevAttrs checkSandboxed, to guarantee correctness for the /share directory (`sandboxNonBinaries`).
|
||||||
ln -s ${nonBin.checkSandboxed or "/dev/null"} "$out/sandboxed-non-binaries"
|
ln -s ${nonBin.checkSandboxed.flat or "/dev/null"} "$out/sandboxed-non-binaries"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -450,13 +479,25 @@ let
|
|||||||
pkgName
|
pkgName
|
||||||
(symlinkBinaries pkgName unsandboxed);
|
(symlinkBinaries pkgName unsandboxed);
|
||||||
sandboxedNonBin = sandboxNonBinaries pkgName unsandboxed sandboxedBin;
|
sandboxedNonBin = sandboxNonBinaries pkgName unsandboxed sandboxedBin;
|
||||||
in symlinkJoin {
|
outputs = lib.unique (
|
||||||
name = "${pkgName}-sandboxed-all";
|
(sandboxedBin.outputs or [ "out" ])
|
||||||
paths = [ sandboxedBin sandboxedNonBin ];
|
++ (sandboxedNonBin.outputs or [ "out" ])
|
||||||
|
);
|
||||||
|
in runCommandLocal "${pkgName}-sandboxed-all" {
|
||||||
|
inherit outputs;
|
||||||
|
nativeBuildInputs = [ xorg.lndir ];
|
||||||
passthru = { inherit sandboxedBin sandboxedNonBin unsandboxed; };
|
passthru = { inherit sandboxedBin sandboxedNonBin unsandboxed; };
|
||||||
# specifically, for priority
|
# specifically, for priority
|
||||||
meta = extractMeta sandboxedBin;
|
meta = extractMeta sandboxedBin;
|
||||||
};
|
} ''
|
||||||
|
${lib.concatMapStringsSep "\n" (o:
|
||||||
|
"mkdir -p $" + o + "\n"
|
||||||
|
+ (lib.optionalString ((sandboxedBin."${o}" or null) != null) ("lndir -silent ${sandboxedBin.${o}} $" + o + "\n"))
|
||||||
|
+ (lib.optionalString ((sandboxedNonBin."${o}" or null) != null) ("lndir -silent ${sandboxedNonBin.${o}} $" + o + "\n"))
|
||||||
|
) outputs}
|
||||||
|
runHook postInstall
|
||||||
|
runHook postFixup
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
packageWrapped = sandboxedBy."${wrapperType}";
|
packageWrapped = sandboxedBy."${wrapperType}";
|
||||||
in
|
in
|
||||||
|
Reference in New Issue
Block a user