diff --git a/modules/programs/default.nix b/modules/programs/default.nix index d1eeb610e..df8160201 100644 --- a/modules/programs/default.nix +++ b/modules/programs/default.nix @@ -348,6 +348,14 @@ in whether to ship programs which are uniquely slow to build. ''; }; + sane.sandboxHelper = mkOption { + type = types.package; + default = pkgs.callPackage ./sane-sandboxed.nix {}; + description = '' + `sane-sandbox` package. + exposed to facilitate debugging, e.g. `nix build '.#hostConfigs.desko.sane.sandboxHelper'` + ''; + }; }; config = @@ -364,6 +372,9 @@ in }; in lib.mkMerge [ (take (sane-lib.mkTypedMerge take configs)) + { + environment.systemPackages = [ config.sane.sandboxHelper ]; + } { # expose the pkgs -- as available to the system -- as a build target. system.build.pkgs = pkgs; diff --git a/modules/programs/sane-sandboxed b/modules/programs/sane-sandboxed new file mode 100644 index 000000000..b8b3851bf --- /dev/null +++ b/modules/programs/sane-sandboxed @@ -0,0 +1,77 @@ +#!@runtimeShell@ + +test -n "$SANE_SANDBOX_DEBUG" && set -x + +_cli=() +_rootPaths=() +_homePaths=() +_net= +_dns=() +_firejailFlags=() + +allowPath() { + # if the path is relative, add to _homePaths, else _rootPaths + if [ "${1:0:1}" = "/" ]; then + _rootPaths+=("$1") + else + _homePaths+=("$1") + fi +} + +## parse CLI args into the variables declared above + +while [ "$#" -ne 0 ]; do + _arg="$1" + shift + case "$_arg" in + (--) + # rest of args are for the CLI + _cli+=$@ + break + ;; + (--sane-sandbox-disable) + SANE_SANDBOX_DISABLE=1 + ;; + (--sane-sandbox-firejail-arg) + _firejailFlags+=("$1") + shift + ;; + (--sane-sandbox-path) + allowPath "$1" + shift + ;; + (--sane-sandbox-net) + _net="$1" + shift + ;; + (--sane-sandbox-dns) + _dns+=("$1") + shift + ;; + (*) + _cli+=("$_arg") + ;; + esac +done + +test -n "$SANE_SANDBOX_DISABLE" && exec "${_cli[@]}" + +## construct firejail flags from sane-sandbox flags + +for _path in "${_rootPaths[@]}"; do + _firejailFlags+=("--noblacklist=$_path" "--whitelist=$_path") +done + +for _path in "${_homePaths[@]}"; do + _firejailFlags+=("--noblacklist="'${HOME}/'"$_path" "--whitelist="'${HOME}/'"$_path") +done + +if [ -n "$_net" ]; then + _firejailFlags+=("--net=$_net") +fi + +for _addr in "${_dns[@]}"; do + _firejailFlags+=("--dns=$_addr") +done + +PATH="$PATH:@firejail@" exec firejail "${_firejailFlags[@]}" -- "${_cli[@]}" diff --git a/modules/programs/sane-sandboxed.nix b/modules/programs/sane-sandboxed.nix new file mode 100644 index 000000000..3e2e8626a --- /dev/null +++ b/modules/programs/sane-sandboxed.nix @@ -0,0 +1,33 @@ +{ stdenv +, runtimeShell +, firejail +}: + +stdenv.mkDerivation { + pname = "sane-sandboxed"; + version = "0.1"; + src = ./.; #< TODO: should just be `./sane-sandboxed` + + firejail = "${firejail}/bin/firejail"; + inherit runtimeShell; + postPatch = '' + substituteAllInPlace sane-sandboxed + ''; + + installPhase = '' + runHook preInstall + install -d "$out" + install -d "$out/bin" + install -m 755 sane-sandboxed $out/bin/sane-sandboxed + runHook postInstall + ''; + + meta = { + description = '' + helper program to run some other program in a sandbox. + factoring this out allows: + 1. to abstract over the particular sandbox implementation (bwrap, firejail, ...). + 2. to modify sandbox settings without forcing a rebuild of the sandboxed package. + ''; + }; +}