modules/programs/sandbox: add an "embedProfile" option to source sandbox settings from the package instead of the system
This commit is contained in:
@@ -43,7 +43,7 @@ let
|
|||||||
in
|
in
|
||||||
makeSandboxed {
|
makeSandboxed {
|
||||||
inherit pkgName package;
|
inherit pkgName package;
|
||||||
inherit (sandbox) binMap method extraConfig;
|
inherit (sandbox) binMap embedProfile extraConfig method;
|
||||||
vpn = if net == "vpn" then vpn else null;
|
vpn = if net == "vpn" then vpn else null;
|
||||||
allowedHomePaths = builtins.attrNames fs ++ builtins.attrNames persist.byPath ++ sandbox.extraHomePaths;
|
allowedHomePaths = builtins.attrNames fs ++ builtins.attrNames persist.byPath ++ sandbox.extraHomePaths;
|
||||||
allowedRootPaths = [
|
allowedRootPaths = [
|
||||||
@@ -222,6 +222,17 @@ let
|
|||||||
how/whether to sandbox all binaries in the package.
|
how/whether to sandbox all binaries in the package.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
sandbox.embedProfile = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
whether to embed the sandbox settings (path access, etc) into the wrapped binary that lives in /nix/store (true),
|
||||||
|
or to encode only a profile name in the wrapper, and use it to query the settings at runtime (false).
|
||||||
|
|
||||||
|
embedded profile means you have to rebuild the wrapper any time you adjust the sandboxing flags,
|
||||||
|
but it also means you can run the program without installing it: helpful for iteration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
sandbox.binMap = mkOption {
|
sandbox.binMap = mkOption {
|
||||||
type = types.attrsOf types.str;
|
type = types.attrsOf types.str;
|
||||||
default = {};
|
default = {};
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
, sane-sandboxed
|
, sane-sandboxed
|
||||||
, writeTextFile
|
, writeTextFile
|
||||||
}:
|
}:
|
||||||
{ pkgName, package, method, vpn ? null, allowedHomePaths ? [], allowedRootPaths ? [], binMap ? {}, extraConfig ? [] }:
|
{ pkgName, package, method, vpn ? null, allowedHomePaths ? [], allowedRootPaths ? [], binMap ? {}, extraConfig ? [], embedProfile ? false }:
|
||||||
let
|
let
|
||||||
sane-sandboxed' = sane-sandboxed.meta.mainProgram; #< load by bin name to reduce rebuilds
|
sane-sandboxed' = sane-sandboxed.meta.mainProgram; #< load by bin name to reduce rebuilds
|
||||||
|
|
||||||
@@ -34,6 +34,15 @@ let
|
|||||||
++ lib.optionals (vpn != null) vpnItems
|
++ lib.optionals (vpn != null) vpnItems
|
||||||
++ extraConfig;
|
++ extraConfig;
|
||||||
|
|
||||||
|
sandboxProfilesPkg = writeTextFile {
|
||||||
|
name = "${pkgName}-sandbox-profiles";
|
||||||
|
destination = "/share/sane-sandboxed/profiles/${pkgName}.profile";
|
||||||
|
text = builtins.concatStringsSep "\n" sandboxFlags;
|
||||||
|
};
|
||||||
|
sandboxProfileDir = "${sandboxProfilesPkg}/share/sane-sandboxed/profiles";
|
||||||
|
|
||||||
|
maybeEmbedProfilesDir = lib.optionalString embedProfile ''"--sane-sandbox-profile-dir" "${sandboxProfileDir}"'';
|
||||||
|
|
||||||
# two ways i could wrap a package in a sandbox:
|
# two ways i could wrap a package in a sandbox:
|
||||||
# 1. package.overrideAttrs, with `postFixup`.
|
# 1. package.overrideAttrs, with `postFixup`.
|
||||||
# 2. pkgs.symlinkJoin, or pkgs.runCommand, creating an entirely new package which calls into the inner binaries.
|
# 2. pkgs.symlinkJoin, or pkgs.runCommand, creating an entirely new package which calls into the inner binaries.
|
||||||
@@ -43,7 +52,7 @@ let
|
|||||||
# but even no.2 has to consider such edge-cases, just less frequently.
|
# but even no.2 has to consider such edge-cases, just less frequently.
|
||||||
# no.1 may bloat rebuild times.
|
# no.1 may bloat rebuild times.
|
||||||
#
|
#
|
||||||
# ultimately, no.1 is probably more reliable, but i expect i'll factor out a switch to allow either approach -- particularly when debugging package buld failures.
|
# ultimately, no.1 is probably more reliable, but i expect i'll factor out a switch to allow either approach -- particularly when debugging package build failures.
|
||||||
package' = if package.override.__functionArgs ? runCommand then
|
package' = if package.override.__functionArgs ? runCommand then
|
||||||
package.override {
|
package.override {
|
||||||
runCommand = name: env: cmd: runCommand name env (cmd + lib.optionalString (name == package.name) ''
|
runCommand = name: env: cmd: runCommand name env (cmd + lib.optionalString (name == package.name) ''
|
||||||
@@ -77,7 +86,7 @@ let
|
|||||||
|
|
||||||
_profiles=("$_profileFromBinMap" "$_name" "${pkgName}" "${unwrapped.pname or ""}" "${unwrapped.name or ""}")
|
_profiles=("$_profileFromBinMap" "$_name" "${pkgName}" "${unwrapped.pname or ""}" "${unwrapped.name or ""}")
|
||||||
# filter to just the unique profiles
|
# filter to just the unique profiles
|
||||||
_profileArgs=()
|
_profileArgs=(${maybeEmbedProfilesDir})
|
||||||
for _profile in "''${_profiles[@]}"; do
|
for _profile in "''${_profiles[@]}"; do
|
||||||
if [ -n "$_profile" ] && ! [[ " ''${_profileArgs[@]} " =~ " $_profile " ]]; then
|
if [ -n "$_profile" ] && ! [[ " ''${_profileArgs[@]} " =~ " $_profile " ]]; then
|
||||||
_profileArgs+=("--sane-sandbox-profile" "$_profile")
|
_profileArgs+=("--sane-sandbox-profile" "$_profile")
|
||||||
@@ -121,11 +130,7 @@ let
|
|||||||
test "$_numExec" -ne 0 && touch "$out"
|
test "$_numExec" -ne 0 && touch "$out"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
sandboxProfiles = writeTextFile {
|
sandboxProfiles = sandboxProfilesPkg;
|
||||||
name = "${pkgName}-sandbox-profiles";
|
|
||||||
destination = "/share/sane-sandboxed/profiles/${pkgName}.profile";
|
|
||||||
text = builtins.concatStringsSep "\n" sandboxFlags;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
in
|
in
|
||||||
|
@@ -4,6 +4,8 @@ isDebug="$SANE_SANDBOX_DEBUG"
|
|||||||
test -n "$isDebug" && set -x
|
test -n "$isDebug" && set -x
|
||||||
isDisable="$SANE_SANDBOX_DISABLE"
|
isDisable="$SANE_SANDBOX_DISABLE"
|
||||||
|
|
||||||
|
profileDirs=(@profileDirs@)
|
||||||
|
|
||||||
cliArgs=()
|
cliArgs=()
|
||||||
cliPathArgs=()
|
cliPathArgs=()
|
||||||
autodetect=
|
autodetect=
|
||||||
@@ -31,17 +33,25 @@ loadProfileByPath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tryLoadProfileByName() {
|
tryLoadProfileByName() {
|
||||||
profilesNamed+=("$1")
|
_profile="$1"
|
||||||
|
if [ "${_profile:0:1}" = "/" ]; then
|
||||||
_profileDirs=(@profileDirs@)
|
# absolute path to profile.
|
||||||
for _profileDir in "${_profileDirs[@]}"; do
|
# consider it an error if it doesn't exist.
|
||||||
_profile="$_profileDir/$1.profile"
|
# in general, prefer to use `--sane-sandbox-profile-dir` and specify the profile by name.
|
||||||
debug "try profile at path: '$_profile'"
|
# doing so maximizes compatibility with anything else that uses the name, like firejail.
|
||||||
if [ -f "$_profile" ]; then
|
|
||||||
loadProfileByPath "$_profile"
|
loadProfileByPath "$_profile"
|
||||||
|
else
|
||||||
|
profilesNamed+=("$_profile")
|
||||||
|
|
||||||
|
for _profileDir in "${profileDirs[@]}"; do
|
||||||
|
_profilePath="$_profileDir/$_profile.profile"
|
||||||
|
debug "try profile at path: '$_profilePath'"
|
||||||
|
if [ -f "$_profilePath" ]; then
|
||||||
|
loadProfileByPath "$_profilePath"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# convert e.g. `file:///Local%20Users/foo.mp3` to `file:///Local Users/foo.mp3`
|
# convert e.g. `file:///Local%20Users/foo.mp3` to `file:///Local Users/foo.mp3`
|
||||||
@@ -160,6 +170,11 @@ parseArgs() {
|
|||||||
tryLoadProfileByName "$1"
|
tryLoadProfileByName "$1"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
(--sane-sandbox-profile-dir)
|
||||||
|
_dir="$1"
|
||||||
|
shift
|
||||||
|
profileDirs+=("$_dir")
|
||||||
|
;;
|
||||||
(*)
|
(*)
|
||||||
parseArgsExtra+=("$_arg")
|
parseArgsExtra+=("$_arg")
|
||||||
;;
|
;;
|
||||||
|
Reference in New Issue
Block a user