nix: generate strict sandbox configuration
test / test (push) Successful in 22s Details

Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
Ophestra Umiker 2024-11-06 04:25:15 +09:00
parent 3dfc1fcd56
commit 4d90e73366
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
1 changed files with 179 additions and 51 deletions

216
nixos.nix
View File

@ -15,6 +15,7 @@ let
mapAttrsToList mapAttrsToList
foldlAttrs foldlAttrs
optional optional
optionals
; ;
cfg = config.environment.fortify; cfg = config.environment.fortify;
@ -39,6 +40,7 @@ in
listOf listOf
attrsOf attrsOf
nullOr nullOr
functionTo
; ;
in in
attrsOf (submodule { attrsOf (submodule {
@ -54,6 +56,14 @@ in
launchers = mkOption { launchers = mkOption {
type = attrsOf (submodule { type = attrsOf (submodule {
options = { options = {
id = mkOption {
type = nullOr str;
default = null;
description = ''
Freedesktop application ID.
'';
};
command = mkOption { command = mkOption {
type = nullOr str; type = nullOr str;
default = null; default = null;
@ -63,17 +73,29 @@ in
''; '';
}; };
method = mkOption {
type = enum [
"simple"
"sudo"
"systemd"
];
default = "systemd";
description = ''
Launch method for the sandboxed program.
'';
};
dbus = { dbus = {
config = mkOption { session = mkOption {
type = nullOr anything; type = nullOr (functionTo anything);
default = null; default = null;
description = '' description = ''
D-Bus custom configuration. D-Bus session bus custom configuration.
Setting this to null will enable built-in defaults. Setting this to null will enable built-in defaults.
''; '';
}; };
configSystem = mkOption { system = mkOption {
type = nullOr anything; type = nullOr anything;
default = null; default = null;
description = '' description = ''
@ -81,24 +103,55 @@ in
Setting this to null will disable the system bus proxy. Setting this to null will disable the system bus proxy.
''; '';
}; };
};
id = mkOption { env = mkOption {
type = nullOr str; type = nullOr (attrsOf str);
default = null; default = null;
description = '' description = ''
D-Bus application id. Environment variables to set for the initial process in the sandbox.
Setting this to null will disable own path in defaults.
Has no effect if custom configuration is set.
''; '';
}; };
mpris = mkOption { nix = mkEnableOption ''
type = bool; Whether to allow nix daemon connections from within sandbox.
default = false; '';
userns = mkEnableOption ''
Whether to allow userns within sandbox.
'';
useRealUid = mkEnableOption ''
Whether to map to fortify's real UID within the sandbox.
'';
net =
mkEnableOption ''
Whether to allow network access within sandbox.
''
// {
default = true;
};
gpu = mkOption {
type = nullOr bool;
default = null;
description = '' description = ''
Whether to enable MPRIS in D-Bus defaults. Target process GPU and driver access.
Setting this to null will enable GPU whenever X or Wayland is enabled.
''; '';
}; };
dev = mkEnableOption ''
Whether to allow access to all devices within sandbox.
'';
extraPaths = mkOption {
type = listOf anything;
default = [ ];
description = ''
Extra paths to make available inside the sandbox.
'';
}; };
capability = { capability = {
@ -143,18 +196,6 @@ in
Setting this to null will default package name to wrapper name. Setting this to null will default package name to wrapper name.
''; '';
}; };
method = mkOption {
type = enum [
"simple"
"sudo"
"systemd"
];
default = "systemd";
description = ''
Launch method for the sandboxed program.
'';
};
}; };
}); });
default = { }; default = { };
@ -222,26 +263,113 @@ in
name: launcher: name: launcher:
with launcher.capability; with launcher.capability;
let let
command = if launcher.command == null then name else launcher.command; extendDBusDefault = id: ext: {
filter = true;
talk = [ "org.freedesktop.Notifications" ] ++ ext.talk;
own =
(optionals (launcher.id != null) [
"${id}.*"
"org.mpris.MediaPlayer2.${id}.*"
])
++ ext.own;
call = {
"org.freedesktop.portal.*" = "*";
} // ext.call;
broadcast = {
"org.freedesktop.portal.*" = "@/org/freedesktop/portal/*";
} // ext.broadcast;
};
dbusConfig = dbusConfig =
if launcher.dbus.config != null then let
pkgs.writeText "${name}-dbus.json" (builtins.toJSON launcher.dbus.config) default = {
talk = [ ];
own = [ ];
call = { };
broadcast = { };
};
in
{
session_bus =
if launcher.dbus.session != null then
(launcher.dbus.session (extendDBusDefault launcher.id))
else else
null; (extendDBusDefault launcher.id default);
dbusSystem = system_bus = launcher.dbus.system;
if launcher.dbus.configSystem != null then };
pkgs.writeText "${name}-dbus-system.json" (builtins.toJSON launcher.dbus.configSystem) command = if launcher.command == null then name else launcher.command;
else enablements =
null; (if wayland then 1 else 0)
capArgs = + (if x11 then 2 else 0)
(if wayland then " --wayland" else "") + (if dbus then 4 else 0)
+ (if x11 then " -X" else "") + (if pulse then 8 else 0);
+ (if dbus then " --dbus" else "") conf = {
+ (if pulse then " --pulse" else "") inherit (launcher) id method;
+ (if launcher.dbus.mpris then " --mpris" else "") inherit user;
+ (if launcher.dbus.id != null then " --dbus-id ${launcher.dbus.id}" else "") command = [
+ (if dbusConfig != null then " --dbus-config ${dbusConfig}" else "") "/run/current-system/sw/bin/zsh"
+ (if dbusSystem != null then " --dbus-system ${dbusSystem}" else ""); (pkgs.writeShellScript "${name}-start" ("exec " + command + " $@"))
];
confinement = {
sandbox = {
inherit (launcher)
userns
net
dev
env
;
use_real_uid = launcher.useRealUid;
filesystem =
[
{ src = "/bin"; }
{ src = "/usr/bin"; }
{ src = "/nix/store"; }
{ src = "/run/current-system"; }
{
src = "/sys/block";
require = false;
}
{
src = "/sys/bus";
require = false;
}
{
src = "/sys/class";
require = false;
}
{
src = "/sys/dev";
require = false;
}
{
src = "/sys/devices";
require = false;
}
{
src = "/home/${user}";
write = true;
require = true;
}
]
++ optionals launcher.nix [
{ src = "/nix/var"; }
{ src = "/var/db/nix-channels"; }
]
++ optionals (if launcher.gpu != null then launcher.gpu else wayland || x11) [
{ src = "/run/opengl-driver"; }
{
src = "/dev/dri";
dev = true;
}
]
++ launcher.extraPaths;
auto_etc = true;
override = [ "/var/run/nscd" ];
};
inherit enablements;
inherit (dbusConfig) session_bus system_bus;
};
};
in in
pkgs.writeShellScriptBin name ( pkgs.writeShellScriptBin name (
if launcher.method == "simple" then if launcher.method == "simple" then
@ -250,7 +378,7 @@ in
'' ''
else else
'' ''
exec fortify${capArgs} --method ${launcher.method} -u ${user} $SHELL -c "exec ${command} $@" exec fortify app ${pkgs.writeText "fortify-${name}.json" (builtins.toJSON conf)} $@
'' ''
) )
) launchers; ) launchers;