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

230
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. };
'';
nix = mkEnableOption ''
Whether to allow nix daemon connections from within sandbox.
'';
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;
}; };
mpris = mkOption { gpu = mkOption {
type = bool; type = nullOr bool;
default = false; 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 = {
else talk = [ ];
null; own = [ ];
dbusSystem = call = { };
if launcher.dbus.configSystem != null then broadcast = { };
pkgs.writeText "${name}-dbus-system.json" (builtins.toJSON launcher.dbus.configSystem) };
else in
null; {
capArgs = session_bus =
(if wayland then " --wayland" else "") if launcher.dbus.session != null then
+ (if x11 then " -X" else "") (launcher.dbus.session (extendDBusDefault launcher.id))
+ (if dbus then " --dbus" else "") else
+ (if pulse then " --pulse" else "") (extendDBusDefault launcher.id default);
+ (if launcher.dbus.mpris then " --mpris" else "") system_bus = launcher.dbus.system;
+ (if launcher.dbus.id != null then " --dbus-id ${launcher.dbus.id}" else "") };
+ (if dbusConfig != null then " --dbus-config ${dbusConfig}" else "") command = if launcher.command == null then name else launcher.command;
+ (if dbusSystem != null then " --dbus-system ${dbusSystem}" else ""); enablements =
(if wayland then 1 else 0)
+ (if x11 then 2 else 0)
+ (if dbus then 4 else 0)
+ (if pulse then 8 else 0);
conf = {
inherit (launcher) id method;
inherit user;
command = [
"/run/current-system/sw/bin/zsh"
(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;