diff --git a/hosts/common/programs/spotify.nix b/hosts/common/programs/spotify.nix index c0ad5ab2..8e6cfa19 100644 --- a/hosts/common/programs/spotify.nix +++ b/hosts/common/programs/spotify.nix @@ -2,9 +2,10 @@ { sane.programs.spotify = { sandbox.method = "bwrap"; - sandbox.extraFirejailConfig = '' - keep-dev-shm - ''; + sandbox.extraConfig = [ + "--sane-sandbox-firejail-arg" + "--keep-dev-shm" + ]; persist.byStore.plaintext = [ # probably just songs and such (haven't checked) ".cache/spotify" diff --git a/hosts/common/programs/wireshark.nix b/hosts/common/programs/wireshark.nix index d73aa167..af013ac5 100644 --- a/hosts/common/programs/wireshark.nix +++ b/hosts/common/programs/wireshark.nix @@ -5,12 +5,14 @@ in { sane.programs.wireshark = { sandbox.method = "firejail"; - sandbox.extraFirejailConfig = '' + sandbox.extraConfig = [ # somehow needs `setpcap` (makes these bounding capabilities also be inherited?) # else no interfaces appear on the main page - ignore caps.keep dac_override,dac_read_search,net_admin,net_raw - caps.keep dac_override,dac_read_search,net_admin,net_raw,setpcap - ''; + "--sane-sandbox-firejail-arg" + "--ignore=caps.keep dac_override,dac_read_search,net_admin,net_raw" + "--sane-sandbox-firejail-arg" + "--caps.keep=dac_override,dac_read_search,net_admin,net_raw,setpcap" + ]; slowToBuild = true; }; @@ -21,6 +23,6 @@ in }; # the SUID wrapper can't also be a firejail (idk why? it might be that the binary's already *too* restricted). security.wrappers = lib.mkIf cfg.enabled { - dumpcap.source = lib.mkForce "${cfg.package}/bin/.dumpcap-firejailed"; + dumpcap.source = lib.mkForce "${cfg.package}/bin/.dumpcap-sandboxed"; }; } diff --git a/modules/programs/default.nix b/modules/programs/default.nix index a8c5b75c..ca453a17 100644 --- a/modules/programs/default.nix +++ b/modules/programs/default.nix @@ -55,11 +55,12 @@ let in makeSandboxed { inherit pkgName package; - inherit (sandbox) binMap method; + inherit (sandbox) binMap method extraConfig; vpn = if net == "vpn" then vpn else null; allowedHomePaths = builtins.attrNames fs ++ builtins.attrNames persist.byPath ++ mediaHomePaths; allowedRootPaths = [ "/nix/store" + "/bin/sh" "/etc" #< especially for /etc/profiles/per-user/$USER/bin "/run/current-system" #< for basics like `ls`, and all this program's `suggestedPrograms` (/run/current-system/sw/bin) "/run/wrappers" #< SUID wrappers, in this case so that firejail can be re-entrant @@ -67,10 +68,10 @@ let "/run/systemd/resolve" #< to allow reading /etc/resolv.conf, which ultimately symlinks here # /run/opengl-driver is a symlink into /nix/store; needed by e.g. mpv "/run/opengl-driver" - "/run/opengl-driver-32" + "/run/opengl-driver-32" #< XXX: doesn't exist on aarch64? "/run/user" #< particularly /run/user/$id/wayland-1, pulse, etc. # "/dev/dri" #< fix non-fatal "libEGL warning: wayland-egl: could not open /dev/dri/renderD128" (geary) - ] ++ mediaRootPaths; + ] ++ mediaRootPaths ++ sandbox.extraPaths; } ); pkgSpec = with lib; types.submodule ({ config, name, ... }: { @@ -236,16 +237,24 @@ let then set `sandbox.binMap.umpv = "mpv";` to sandbox `bin/umpv` with the same rules as `bin/mpv` ''; }; - sandbox.extraFirejailConfig = mkOption { - type = types.lines; - default = ""; + sandbox.extraPaths = mkOption { + type = types.listOf types.str; + default = []; description = '' - extra lines to add to this package's /etc/firejail/{pname}.local file, which is included when running any of the package's /bin files if sandbox.method is set to "firejail". - - example: sandbox.extraFirejailConfig = ''' - whitelist ''${HOME}/.ssh - keep-dev-shm - '''; + additional absolute paths to bind into the sandbox. + ''; + }; + sandbox.extraConfig = mkOption { + type = types.listOf types.str; + default = []; + description = '' + extra arguments to pass to the sandbox wrapper. + example: [ + "--sane-sandbox-firejail-arg" + "--whitelist=''${HOME}/.ssh" + "--sane-sandbox-firejail-arg" + "--keep-dev-shm" + ] ''; }; configOption = mkOption { @@ -273,6 +282,8 @@ let else wrapPkg name config config.packageUnwrapped ; + suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [ "bubblewrap" ] + ++ lib.optionals (config.sandbox.method == "firejail") [ "firejail" ]; }; }); toPkgSpec = with lib; types.coercedTo types.package (p: { package = p; }) pkgSpec; diff --git a/modules/programs/make-sandboxed.nix b/modules/programs/make-sandboxed.nix index c01f1124..664864c3 100644 --- a/modules/programs/make-sandboxed.nix +++ b/modules/programs/make-sandboxed.nix @@ -4,7 +4,7 @@ , sane-sandboxed , writeTextFile }: -{ pkgName, package, method, vpn ? null, allowedHomePaths ? [], allowedRootPaths ? [], binMap ? {} }: +{ pkgName, package, method, vpn ? null, allowedHomePaths ? [], allowedRootPaths ? [], binMap ? {}, extraConfig ? [] }: let sane-sandboxed' = sane-sandboxed.meta.mainProgram; #< load by bin name to reduce rebuilds @@ -31,7 +31,8 @@ let "--sane-sandbox-method" method ] ++ allowPaths allowedRootPaths ++ allowHomePaths allowedHomePaths - ++ lib.optionals (vpn != null) vpnItems; + ++ lib.optionals (vpn != null) vpnItems + ++ extraConfig; # two ways i could wrap a package in a sandbox: # 1. package.overrideAttrs, with `postFixup`.