programs: sandboxing: make the profiles be generic across users

this is a step toward making the profile not even be dynamically loaded, since its content is no longer dynamic :)
This commit is contained in:
Colin 2024-05-15 08:33:29 +00:00
parent ea2653b7ce
commit b649071d98

View File

@ -63,39 +63,74 @@ let
vpn = lib.findSingle (v: v.default) null null (builtins.attrValues config.sane.vpn);
sandboxProfilesFor = userName: let
allowedHomePaths = builtins.attrNames fs ++ builtins.attrNames persist.byPath ++ sandbox.extraHomePaths;
allowedRunPaths = sandbox.extraRuntimePaths;
homeDir = config.sane.users."${userName}".home;
uid = config.users.users."${userName}".uid;
xdgRuntimeDir = "/run/user/${builtins.toString uid}";
fullHomePaths = lib.optionals (userName != null) (
builtins.map
(p: path-lib.concat [ homeDir p ])
allowedHomePaths
);
fullRunPaths = lib.optionals (userName != null) (
builtins.map
(p: path-lib.concat [ xdgRuntimeDir p ])
allowedRunPaths
);
allowedPaths = [
"/nix/store"
"/bin/sh"
allowedHomePaths = builtins.attrNames fs ++ builtins.attrNames persist.byPath ++ sandbox.extraHomePaths;
allowedRunPaths = sandbox.extraRuntimePaths;
allowedPaths = [
"/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. TODO: remove!
# /run/opengl-driver is a symlink into /nix/store; needed by e.g. mpv
"/run/opengl-driver"
"/run/opengl-driver-32" #< XXX: doesn't exist on aarch64?
"/usr/bin/env"
] ++ lib.optionals (config.services.resolved.enable) [
"/run/systemd/resolve" #< to allow reading /etc/resolv.conf, which ultimately symlinks here (if using systemd-resolved)
] ++ lib.optionals (builtins.elem "system" sandbox.whitelistDbus) [ "/run/dbus/system_bus_socket" ]
++ sandbox.extraPaths
"/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. TODO: remove!
# /run/opengl-driver is a symlink into /nix/store; needed by e.g. mpv
"/run/opengl-driver"
"/run/opengl-driver-32" #< XXX: doesn't exist on aarch64?
"/usr/bin/env"
] ++ lib.optionals (config.services.resolved.enable) [
"/run/systemd/resolve" #< to allow reading /etc/resolv.conf, which ultimately symlinks here (if using systemd-resolved)
] ++ lib.optionals (builtins.elem "system" sandbox.whitelistDbus) [ "/run/dbus/system_bus_socket" ]
++ sandbox.extraPaths
;
additionalPathsForUser = user: let
fullHomePaths = builtins.map
(p: path-lib.concat [ user.home p ])
allowedHomePaths
;
in makeProfile {
fullRunPaths = builtins.map
(p: path-lib.concat [ "/run/user/${builtins.toString user.uid}" p ])
allowedRunPaths
;
in
fullHomePaths ++ fullRunPaths;
# expand user-specific paths for all users.
# this feeds into the symlink cache, so that cached link data can be available no matter which user invokes the program.
userPathsClosure = lib.flatten (
builtins.map additionalPathsForUser (builtins.attrValues config.users.users)
);
symlinkCache = {
"/bin/sh" = config.environment.binsh;
"${builtins.unsafeDiscardStringContext config.environment.binsh}" = "bash";
"/usr/bin/env" = config.environment.usrbinenv;
"${builtins.unsafeDiscardStringContext config.environment.usrbinenv}" = "coreutils";
# "/run/current-system" = "${config.system.build.toplevel}";
# XXX: /run/current-system symlink can't be cached without forcing regular mass rebuilds:
# mount it as if it were a directory instead.
"/run/current-system" = "";
} // lib.optionalAttrs config.hardware.opengl.enable {
"/run/opengl-driver" = let
gl = config.hardware.opengl;
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/opengl.nix>
package = pkgs.buildEnv {
name = "opengl-drivers";
paths = [ gl.package ] ++ gl.extraPackages;
};
in "${package}";
} // lib.optionalAttrs (config.hardware.opengl.enable && config.hardware.opengl.driSupport32Bit) {
"/run/opengl-driver-32" = let
gl = config.hardware.opengl;
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/opengl.nix>
package = pkgs.buildEnv {
name = "opengl-drivers-32bit";
paths = [ gl.package32 ] ++ gl.extraPackages32;
};
in "${package}";
} // (
symlinksToAttrs (symlinksClosure (allowedPaths ++ userPathsClosure))
);
sandboxProfiles = makeProfile {
inherit pkgName;
inherit (sandbox)
autodetectCliPaths
@ -112,41 +147,8 @@ let
vpn.dns
else
null;
inherit allowedPaths allowedHomePaths allowedRunPaths;
symlinkCache = {
"/bin/sh" = config.environment.binsh;
"${builtins.unsafeDiscardStringContext config.environment.binsh}" = "bash";
"/usr/bin/env" = config.environment.usrbinenv;
"${builtins.unsafeDiscardStringContext config.environment.usrbinenv}" = "coreutils";
# "/run/current-system" = "${config.system.build.toplevel}";
# XXX: /run/current-system symlink can't be cached without forcing regular mass rebuilds:
# mount it as if it were a directory instead.
"/run/current-system" = "";
} // lib.optionalAttrs config.hardware.opengl.enable {
"/run/opengl-driver" = let
gl = config.hardware.opengl;
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/opengl.nix>
package = pkgs.buildEnv {
name = "opengl-drivers";
paths = [ gl.package ] ++ gl.extraPackages;
};
in "${package}";
} // lib.optionalAttrs (config.hardware.opengl.enable && config.hardware.opengl.driSupport32Bit) {
"/run/opengl-driver-32" = let
gl = config.hardware.opengl;
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/opengl.nix>
package = pkgs.buildEnv {
name = "opengl-drivers-32bit";
paths = [ gl.package32 ] ++ gl.extraPackages32;
};
in "${package}";
} // (
symlinksToAttrs (symlinksClosure (allowedPaths ++ fullHomePaths ++ fullRunPaths))
);
inherit allowedPaths allowedHomePaths allowedRunPaths symlinkCache;
};
defaultProfile = sandboxProfilesFor config.sane.defaultUser;
makeSandboxedArgs = {
inherit pkgName package;
inherit (sandbox)
@ -157,13 +159,13 @@ let
in
makeSandboxed (makeSandboxedArgs // {
passthru = {
inherit sandboxProfilesFor;
inherit sandboxProfiles;
withEmbeddedSandboxer = makeSandboxed (makeSandboxedArgs // {
# embed the sandboxer AND a profile, whichever profile the package would have if installed by the default user.
# useful to iterate a package's sandbox config without redeploying.
embedSandboxer = true;
extraSandboxerArgs = [
"--sanebox-profile-dir" "${defaultProfile}/share/sanebox/profiles"
"--sanebox-profile-dir" "${sandboxProfiles}/share/sanebox/profiles"
];
});
withEmbeddedSandboxerOnly = makeSandboxed (makeSandboxedArgs // {
@ -566,7 +568,7 @@ let
# conditionally add to system PATH and env
environment = lib.optionalAttrs (p.enabled && p.enableFor.system) {
systemPackages = lib.optionals (p.package != null) (
[ p.package ] ++ lib.optional (p.sandbox.enable && p.sandbox.method != null) (p.package.passthru.sandboxProfilesFor null)
[ p.package ] ++ lib.optional (p.sandbox.enable && p.sandbox.method != null) (p.package.passthru.sandboxProfiles)
);
# sessionVariables are set by PAM, as opposed to environment.variables which goes in /etc/profile
sessionVariables = p.env;
@ -575,7 +577,7 @@ let
# conditionally add to user(s) PATH
users.users = lib.mapAttrs (userName: en: {
packages = lib.optionals (p.package != null && en && p.enabled) (
[ p.package ] ++ lib.optional (p.sandbox.enable && p.sandbox.method != null) (p.package.passthru.sandboxProfilesFor userName)
[ p.package ] ++ lib.optional (p.sandbox.enable && p.sandbox.method != null) (p.package.passthru.sandboxProfiles)
);
}) p.enableFor.user;