fractal: restrict dbus access a bit tighter

This commit is contained in:
2025-01-06 11:25:35 +00:00
parent 0915957337
commit 65da9bd004
2 changed files with 98 additions and 34 deletions

View File

@@ -38,8 +38,15 @@ in
sandbox.net = "clearnet"; sandbox.net = "clearnet";
sandbox.whitelistAudio = true; sandbox.whitelistAudio = true;
sandbox.whitelistDbus.user = true; #< TODO: reduce # notifications sandbox.whitelistDbus.user.own = [ "org.gnome.Fractal" ];
sandbox.whitelistDbus.user.call."org.freedesktop.secrets" = "*"; #< TODO: restrict to a subset of secrets
sandbox.whitelistDri = true; # otherwise video playback buuuuurns CPU sandbox.whitelistDri = true; # otherwise video playback buuuuurns CPU
sandbox.whitelistSendNotifications = true;
sandbox.whitelistPortal = [
"FileChooser"
"NetworkMonitor" # if portals are enabled, but NetworkMonitor *isn't*, then it'll hang on launch
"OpenURI"
];
sandbox.whitelistWayland = true; sandbox.whitelistWayland = true;
sandbox.extraHomePaths = [ sandbox.extraHomePaths = [
# still needs these paths despite it using the portal's file-chooser :? # still needs these paths despite it using the portal's file-chooser :?

View File

@@ -107,14 +107,10 @@ let
null; null;
allowedDbusCall = lib.flatten ( allowedDbusCall = lib.flatten (
lib.mapAttrsToList lib.mapAttrsToList
(interface: value: lib.map (callSpec: "${interface}=${callSpec}") value.call) (interface: lib.map (methodSpec: "${interface}=${methodSpec}"))
sandbox.whitelistDbus.user sandbox.whitelistDbus.user.call
);
allowedDbusOwn = lib.flatten (
lib.mapAttrsToList
(interface: value: lib.optional value.own interface)
sandbox.whitelistDbus.user
); );
allowedDbusOwn = sandbox.whitelistDbus.user.own;
# the sandboxer knows how to work with duplicated paths, but they're still annoying => `lib.unique` # the sandboxer knows how to work with duplicated paths, but they're still annoying => `lib.unique`
allowedPaths = lib.unique allowedPaths; allowedPaths = lib.unique allowedPaths;
allowedHomePaths = lib.unique allowedHomePaths; allowedHomePaths = lib.unique allowedHomePaths;
@@ -460,36 +456,44 @@ let
pipewire-aware applications shouldn't need this. pipewire-aware applications shouldn't need this.
''; '';
}; };
sandbox.whitelistDbus.user = let sandbox.whitelistDbus.user = mkOption {
dbusInterfaceModule = types.submodule {
options = {
own = mkOption {
type = types.bool;
default = false;
description = ''
allow the sandbox to own this well-defined name.
'';
};
call = mkOption {
type = types.coercedTo types.str (s: [ s ]) (types.listOf types.str);
default = [];
description = ''
allow the sandbox to call methods on this well-defined name
so long as they this method specifier.
'';
};
};
};
in mkOption {
type = types.coercedTo type = types.coercedTo
types.bool (b: lib.optionalAttrs b { "*".own = true; }) types.bool (b: { all = b; })
(types.attrsOf dbusInterfaceModule); (types.submodule {
options = {
all = mkOption {
type = types.bool;
default = false;
description = ''
allow full, unrestricted dbus access
'';
};
own = mkOption {
type = types.listOf types.str;
default = [];
description = ''
allow the sandbox to own any well-known name in this list.
'';
};
call = mkOption {
type = types.attrsOf (types.coercedTo types.str (s: [ s ] ) (types.listOf types.str));
default = {};
description = ''
for each attribute name, allow the sandbox to call methods on that well-known bus name
so long as they satisfy the specifier encoded in the attribute value.
e.g. { "org.freedesktop.portal" = [ "org.freedesktop.portal.FileChooser.*"; ]; };
'';
};
};
})
;
default = {}; default = {};
description = '' description = ''
allow sandbox to selectively interact with user dbus services. allow sandbox to selectively interact with user dbus services.
e.g. { e.g. {
"org.gnome.Calls".own = true; own = [ "org.gnome.Calls" ];
"org.freedesktop.portal".call = "org.freedesktop.portal.FileChooser.*"; call."org.freedesktop.portal" = "org.freedesktop.portal.FileChooser.*";
}; };
special `*` path can be used to allow ALL user dbus traffic: special `*` path can be used to allow ALL user dbus traffic:
e.g. { e.g. {
@@ -516,6 +520,35 @@ let
broad and unaudited attack surface. broad and unaudited attack surface.
''; '';
}; };
sandbox.whitelistPortal = mkOption {
type = types.listOf (types.enum [
# "Account"
# "Camera"
# "Device"
"DynamicLauncher"
# "Email"
"FileChooser"
# "GameMode"
"Location"
# "MemoryMonitor"
"NetworkMonitor" # bleh!
"Notification"
"OpenURI"
# "PowerProfileMonitor"
# "Print"
# "ProxyResolver"
# "Realtime"
# "ScreenCast"
# "Screenshot"
# "Settings"
# "Trash"
# "Wallpaper"
]);
default = [];
description = ''
allow calling specific interfaces under org.freedesktop.portal
'';
};
sandbox.whitelistPwd = mkOption { sandbox.whitelistPwd = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -530,6 +563,14 @@ let
allow the program to start/stop s6 services. allow the program to start/stop s6 services.
''; '';
}; };
sandbox.whitelistSendNotifications = mkOption {
type = types.bool;
default = false;
description = ''
allow the program to send notifications to the desktop manager (like `notify-send`).
typically works via dbus.
'';
};
sandbox.whitelistSystemctl = mkOption { sandbox.whitelistSystemctl = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -660,6 +701,22 @@ let
sandbox.whitelistDbus.system = lib.mkIf config.sandbox.whitelistSystemctl true; sandbox.whitelistDbus.system = lib.mkIf config.sandbox.whitelistSystemctl true;
sandbox.whitelistDbus.user.call = lib.mkMerge ([
(lib.mkIf config.sandbox.whitelistSendNotifications {
"org.freedesktop.Notifications" = "*"; # Notify, NotificationClosed, NotificationReplied, ActionInvoked
"org.erikreider.swaync.cc" = "*"; #< probably overkill
})
] ++ lib.forEach config.sandbox.whitelistPortal (p: {
"org.freedesktop.portal.Desktop" = [
"org.freedesktop.portal.${p}.*"
# "org.freedesktop.DBus.Peer" #< seems to not be needed
# "org.freedesktop.DBus.Properties"
# "org.freedesktop.DBus.Introspectable"
];
}));
sandbox.whitelistPortal = lib.mkIf config.sandbox.whitelistSendNotifications [ "Notification" ];
sandbox.extraEnv = { sandbox.extraEnv = {
MESA_SHADER_CACHE_DIR = lib.mkIf (config.sandbox.mesaCacheDir != null) "$HOME/${config.sandbox.mesaCacheDir}"; MESA_SHADER_CACHE_DIR = lib.mkIf (config.sandbox.mesaCacheDir != null) "$HOME/${config.sandbox.mesaCacheDir}";
TMPDIR = lib.mkIf (config.sandbox.tmpDir != null) "$HOME/${config.sandbox.tmpDir}"; TMPDIR = lib.mkIf (config.sandbox.tmpDir != null) "$HOME/${config.sandbox.tmpDir}";
@@ -748,7 +805,7 @@ let
; ;
sandbox.extraRuntimePaths = sandbox.extraRuntimePaths =
lib.optionals config.sandbox.whitelistAudio [ "pipewire" "pulse" ] # this includes pipewire/pipewire-0-manager: is that ok? lib.optionals config.sandbox.whitelistAudio [ "pipewire" "pulse" ] # this includes pipewire/pipewire-0-manager: is that ok?
++ lib.optionals ((config.sandbox.whitelistDbus.user."*" or {}).own or false) [ "dbus" ] ++ lib.optionals config.sandbox.whitelistDbus.user.all [ "dbus" ]
++ lib.optionals config.sandbox.whitelistWayland [ "wl" ] # app can still communicate with wayland server w/o this, if it has net access ++ lib.optionals config.sandbox.whitelistWayland [ "wl" ] # app can still communicate with wayland server w/o this, if it has net access
++ lib.optionals config.sandbox.whitelistS6 [ "s6" ] # TODO: this allows re-writing the services themselves: don't allow that! ++ lib.optionals config.sandbox.whitelistS6 [ "s6" ] # TODO: this allows re-writing the services themselves: don't allow that!
; ;