nixos/modules/nixos/lutris-sandboxed.nix
2026-01-28 19:47:52 +01:00

135 lines
4.6 KiB
Nix

# Lutris Sandboxed with nix-bwrapper
# Provides a sandboxed Lutris with restricted permissions
{
config,
lib,
pkgs,
inputs,
...
}:
let
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
in
{
nixpkgs.overlays = [
(final: prev: {
lutris-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.lutris.override {
extraPkgs = pkgs: [
pkgs.curl
pkgs.wget
pkgs.gnutar
pkgs.gzip
pkgs.zstd
pkgs.xz
pkgs.p7zip
pkgs.which
pkgs.file
pkgs.zenity
pkgs.vulkan-loader
pkgs.vulkan-tools
pkgs.unzip
pkgs.cabextract
pkgs.pciutils
pkgs.gamemode.lib
pkgs.xdg-utils
];
};
isFhsenv = true;
id = "net.lutris.Lutris";
env = {
WEBKIT_DISABLE_DMABUF_RENDERER = 1;
APPIMAGE_EXTRACT_AND_RUN = 1;
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = "python";
GTK_THEME = "catppuccin-mocha-blue-standard";
BROWSER = "xdg-open";
XDG_CURRENT_DESKTOP = "niri";
XDG_SESSION_TYPE = "wayland";
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
VK_ICD_FILENAMES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json:/run/opengl-driver-32/share/vulkan/icd.d/radeon_icd.i686.json";
};
};
fhsenv = {
skipExtraInstallCmds = false;
};
# Disable Flatpak emulation
flatpak.enable = false;
# Filesystem: Limited to Games directory
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
"$HOME/.local/share/Steam/compatibilitytools.d"
"$HOME/.config/gtk-3.0"
"$HOME/.config/gtk-4.0"
"$HOME/.icons"
"/data/Torrents/Games" # Repack installers
];
readWrite = [
"$HOME/Games/windows"
"$HOME/.local/share/icons"
"$HOME/.config/lutris"
"$HOME/.local/share/lutris"
"$HOME/.cache/lutris"
"$HOME/.steam"
"$HOME/.local/share/steam"
"$HOME/.local/share/umu"
"$HOME/.local/share/applications"
"$HOME/.local/share/desktop-directories"
];
};
# Bind mount systemd-resolved socket directory to fix DNS
# The sandbox mounts a tmpfs on /run, so we need to validly expose this
fhsenv.bwrap.additionalArgs = [
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
# D-Bus session proxy
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus" "$XDG_RUNTIME_DIR/bus"''
# D-Bus system proxy
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus_system" /run/dbus/system_bus_socket''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
# Bind system themes to /usr/share
"--ro-bind /run/current-system/sw/share/themes /usr/share/themes"
"--ro-bind /run/current-system/sw/share/icons /usr/share/icons"
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "net.lutris.Lutris";
enableSystemBus = true;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.Flatpak"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="net.lutris.Lutris"''
];
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.UDisks2"'' # Disk detection
];
};
};
})
];
}