wrapper-manager/sandboxing/bubblewrap: init launcher submodule

At the end of the day, I decided to make it in nixpkgs' runtime shell
(GNU Bash) instead of Rust because it'll be a pain in the ass.
This commit is contained in:
Gabriel Arazas 2024-08-05 18:42:12 +08:00
parent e042128be3
commit 3a4833d46d
No known key found for this signature in database
GPG Key ID: 62104B43D00AA360
6 changed files with 228 additions and 16 deletions

View File

@ -55,7 +55,7 @@ let
in
{
imports = [
#./launcher.nix
./launcher.nix
./dbus-filter.nix
./filesystem.nix
];
@ -77,27 +77,18 @@ in
config = lib.mkIf (config.sandboxing.variant == "bubblewrap") (lib.mkMerge [
{
# TODO: All of the Linux-exclusive flags could be handled by the
# launcher instead. ALSO MODULARIZE THIS CRAP!
# Ordering of the arguments here matter(?).
sandboxing.bubblewrap.extraArgs =
cfg.extraArgs
++ lib.optionals stdenv.isLinux [
"--proc" "/proc"
"--dev" "/dev"
]
++ lib.mapAttrsToList
(var: metadata:
if metadata.action == "unset"
then "--unsetenv ${var}"
else "--setenv ${var} ${metadata.value}")
if metadata.action == "unset" then
"--unsetenv ${var}"
else if lib.elem metadata.action [ "prefix" "suffix" ] then
"--setenv ${var} ${lib.escapeShellArg (lib.concatStringsSep metadata.separator metadata.value)}"
else
"--setenv ${var} ${metadata.value}")
config.env;
arg0 = lib.getExe' submoduleCfg.package "bwrap";
prependArgs = lib.mkBefore
(submoduleCfg.extraArgs
++ [ "--" config.sandboxing.wraparound.arg0 ]
++ config.sandboxing.wraparound.extraArgs);
}
(lib.mkIf submoduleCfg.enableNetwork {

View File

@ -0,0 +1,81 @@
{ config, lib, options, pkgs, ... }:
let
cfg = config.sandboxing.bubblewrap.launcher;
bubblewrapModuleFactory = { isGlobal ? false }: {
package = lib.mkOption {
type = lib.types.package;
description = ''
Package containing the specialized Bubblewrap launcher used for this
module.
'';
default = if isGlobal then pkgs.callPackage ./launcher/package.nix { } else cfg.package;
};
integrations = let
mkLauncherEnableOption = service: serviceName: lib.mkEnableOption "launcher integration for ${serviceName}" // {
default = if isGlobal then true else cfg.integrations.${service}.enable;
};
in {
pipewire.enable = mkLauncherEnableOption "pipewire" "Pipewire";
pulseaudio.enable = mkLauncherEnableOption "pulseaudio" "PulseAudio";
wayland.enable = mkLauncherEnableOption "wayland" "Wayland desktop sessions";
x11.enable = mkLauncherEnableOption "x11" "X11-based desktop sessions";
};
};
in
{
options.sandboxing.bubblewrap.launcher = bubblewrapModuleFactory { isGlobal = true; };
options.wrappers =
let
bubblewrapLauncherSubmodule = { config, lib, name, ... }: let
submoduleCfg = config.sandboxing.bubblewrap.launcher;
envSuffix = word: "WRAPPER_MANAGER_BWRAP_LAUNCHER_${word}";
in {
options.sandboxing.bubblewrap.launcher = bubblewrapModuleFactory { isGlobal = false; };
config = lib.mkIf (config.sandboxing.variant == "bubblewrap") (lib.mkMerge [
{
arg0 = lib.getExe' submoduleCfg.package "wrapper-manager-bubblewrap-launcher";
prependArgs = lib.mkBefore
(config.sandboxing.bubblewrap.extraArgs
++ [ "--" config.sandboxing.wraparound.arg0 ]
++ config.sandboxing.wraparound.extraArgs);
env = {
"${envSuffix "BWRAP"}".value = lib.getExe' config.sandboxing.bubblewrap.package "bwrap";
# We're just unsetting autoconfigure since we're configuring this
# through the module system anyways and would allow the user to
# have some more control over what can be enabled.
"${envSuffix "AUTOCONFIGURE"}".value = "";
};
}
(lib.mkIf config.sandboxing.bubblewrap.dbus.enable {
env.${envSuffix "DBUS_PROXY"}.value = lib.getExe' config.sandboxing.bubblewrap.dbus.filter.package "xdg-dbus-proxy";
env.${envSuffix "DBUS_PROXY_ARGS"}.value = lib.concatStringsSep " " config.sandboxing.bubblewrap.dbus.filter.extraArgs;
})
(lib.mkIf submoduleCfg.integrations.pulseaudio.enable {
env.${envSuffix "PULSEAUDIO"}.value = "1";
})
(lib.mkIf submoduleCfg.integrations.pipewire.enable {
env.${envSuffix "PIPEWIRE"}.value = "1";
})
(lib.mkIf submoduleCfg.integrations.x11.enable {
env.${envSuffix "X11"}.value = "1";
})
(lib.mkIf submoduleCfg.integrations.wayland.enable {
env.${envSuffix "WAYLAND"}.value = "1";
})
]);
};
in
lib.mkOption {
type = with lib.types; attrsOf (submodule bubblewrapLauncherSubmodule);
};
}

View File

@ -0,0 +1,19 @@
Copyright (c) 2024 Gabriel Arazas <foodogsquared@foodogsquared.one>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,87 @@
#!/usr/bin/env bash
# A specialized launcher intended to handle a bunch of things in runtime such
# as adding flags when in certain systems and running xdg-dbus-proxy if
# required. Take note, we don't enforce any security model whatsoever, it's
# just a launcher that adds `bwrap` arguments in runtime for certain
# situations.
#
# Take note, we have the following design constraints for this launcher:
#
# * Using only the nixpkgs runtime shell and a few common dependencies found on
# Unix-adjacent systems.
# * No additional command-line options which means no flags and command-line
# parsing. This is essentially just a Bubblewrap wrapper.
# * If we ever let the user configure things, it should be done with
# environment variables with `WRAPPER_MANAGER_BWRAP_LAUNCHER` prefix. It's very
# long but who cares.
# * Ideally, there should be no options to clear the environment in this
# launcher. Let the user do it themselves if they want.
declare -a additional_flags
: "${XDG_RUNTIME_DIR:="/run/user/$(id -u)"}"
: "${WRAPPER_MANAGER_BWRAP_LAUNCHER_BWRAP:="bwrap"}"
: "${WRAPPER_MANAGER_BWRAP_LAUNCHER_DBUS_PROXY:="xdg-dbus-proxy"}"
: "${WRAPPER_MANAGER_BWRAP_LAUNCHER_AUTOCONFIGURE:="1"}"
is_autoconfigured_or() {
local service="$1"
[ "${WRAPPER_MANAGER_BWRAP_LAUNCHER_AUTOCONFIGURE}" = "1" ] || [ "${service}" = "1" ]
}
# Bubblewrap is aggressively Linux-exclusive so we can add some things in here
# that are surely common within most Linux distros but just in case...
case "$(uname)" in
Linux*)
additional_flags+=(--proc /proc)
additional_flags+=(--dev /dev)
additional_flags+=(--dev-bind /dev/dri /dev/dri)
additional_flags+=(--tmpfs /tmp)
additional_flags+=(--ro-bind /sys/dev/char)
additional_flags+=(--ro-bind /sys/devices/pci0000:00)
# Check if we're in a NixOS system.
if [[ -f /etc/NIXOS ]]; then
additional_flags+=(--ro-bind /run/opengl-driver/ /run/opengl-driver/)
if [[ -d /run/opengl-driver-32 ]]; then
additional_flags+=(--ro-bind /run/opengl-driver-32 /run/opengl-driver-32/)
fi
fi
;;
esac
# TODO: Much of the flags added here are so far just cargo-culted lmao.
# Investigate it pls for the love of God.
# Bind Wayland if it's detected to be running on one.
if is_autoconfigured_or "${WRAPPER_MANAGER_BWRAP_LAUNCHER_WAYLAND}" && [ -S "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" ]; then
additional_flags+=(--ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}")
fi
# Bind Pipewire if it's detected.
if is_autoconfigured_or "${WRAPPER_MANAGER_BWRAP_LAUNCHER_PIPEWIRE}" && [ -S "${XDG_RUNTIME_DIR}/pipewire-0" ]; then
additional_flags+=(--ro-bind "${XDG_RUNTIME_DIR}/pipewire-0")
fi
# Bind PulseAudio if it's detected and configured.
if is_autoconfigured_or "${WRAPPER_MANAGER_BWRAP_LAUNCHER_PULSEAUDIO}" && [ -e "${XDG_RUNTIME_DIR}/pulse/pid" ]; then
additional_flags+=(--ro-bind "${XDG_RUNTIME_DIR}/pulse")
fi
# Bind X11 thingies if it's configured and detected.
if is_autoconfigured_or "${WRAPPER_MANAGER_BWRAP_LAUNCHER_X11}" && [ "${XAUTHORITY}" ]; then
additional_flags+=(--ro-bind "${XAUTHORITY}")
additional_flags+=(--ro-bind "/tmp/.X11-unix")
fi
# Fork the D-Bus proxy in case it is needed. We only need to know if its needed
# if the *DBUS_PROXY_ARGS envvar is set.
if [ -n "${WRAPPER_MANAGER_BWRAP_LAUNCHER_DBUS_PROXY_ARGS}" ]; then
(
${WRAPPER_MANAGER_BWRAP_LAUNCHER_BWRAP} "${additional_flags[@]}" \
-- "${WRAPPER_MANAGER_BWRAP_LAUNCHER_DBUS_PROXY}" "${WRAPPER_MANAGER_BWRAP_LAUNCHER_DBUS_PROXY_ARGS[@]}"
) &
fi
exec ${WRAPPER_MANAGER_BWRAP_LAUNCHER_BWRAP} "${additional_flags[@]}" "$@"

View File

@ -0,0 +1,13 @@
project('wrapper-manager-bubblewrap-launcher',
version: '0.1.0',
license: 'MIT',
meson_version: '>=0.54.0',
)
configure_file(
input: 'app.sh',
output: meson.project_name(),
install_dir: get_option('bindir'),
install_mode: 'rwxr-xr-x',
install: true
)

View File

@ -0,0 +1,21 @@
{
stdenv,
lib,
meson,
ninja
}:
stdenv.mkDerivation (finalAttrs: {
pname = "wrapper-manager-bubblewrap-launcher";
version = "0.1.0";
src = lib.cleanSource ./.;
nativeBuildInputs = [ meson ninja ];
meta = {
description = "wrapper-manager specialized launcher for Bubblewrap environments";
license = lib.licenses.mit;
mainProgram = finalAttrs.pname;
};
})