From 67edf0036d0d077da963d8ac666237f19b22302b Mon Sep 17 00:00:00 2001 From: Manuel Bluhm Date: Tue, 17 Sep 2024 18:17:31 +0400 Subject: [PATCH] Improve BT functionality and hardening - change 'mutableUsers' to false (system-wide) - add bluetooth system user/group (requires immutability) - enable hardened systemd configs in audiovm - add hardened systemd config + dbus policy - add persistence to save bt device configs - add uinput kernel module + udev rules - change control socket in launcher Signed-off-by: Manuel Bluhm --- modules/common/services/bluetooth.nix | 74 +++++++++++++---- .../hardened-configs/common/bluetooth.nix | 80 +++++++++++++++++++ modules/common/users/accounts.nix | 3 +- .../virtualization/microvm/audiovm.nix | 15 ++++ modules/reference/appvms/business.nix | 9 +-- modules/reference/appvms/comms.nix | 9 +-- .../pulseaudio-remove-dont-move.patch | 2 + packages/bt-launcher/default.nix | 4 +- 8 files changed, 164 insertions(+), 32 deletions(-) create mode 100644 modules/common/systemd/hardened-configs/common/bluetooth.nix diff --git a/modules/common/services/bluetooth.nix b/modules/common/services/bluetooth.nix index fd6419060..ae75258a5 100644 --- a/modules/common/services/bluetooth.nix +++ b/modules/common/services/bluetooth.nix @@ -1,36 +1,76 @@ # Copyright 2022-2024 TII (SSRC) and the Ghaf contributors # SPDX-License-Identifier: Apache-2.0 -{ config, lib, ... }: +{ + config, + lib, + pkgs, + ... +}: let cfg = config.ghaf.services.bluetooth; inherit (lib) mkIf mkEnableOption; + bluetoothUser = "bluetooth"; in { options.ghaf.services.bluetooth = { enable = mkEnableOption "Bluetooth configurations"; }; config = mkIf cfg.enable { + + # Enable bluetooth hardware.bluetooth = { enable = true; }; - # Polkit rules for blueman - ghaf.systemd.withPolkit = true; - security.polkit = { - enable = true; - extraConfig = '' - polkit.addRule(function(action, subject) { - if ((action.id == "org.blueman.network.setup" || - action.id == "org.blueman.dhcp.client" || - action.id == "org.blueman.rfkill.setstate" || - action.id == "org.blueman.pppd.pppconnect") && - subject.user == "ghaf") { - return polkit.Result.YES; - } - }); - ''; + # Setup bluetooth user and group + users = { + users."${bluetoothUser}" = { + isSystemUser = true; + group = "${bluetoothUser}"; + }; + groups."${bluetoothUser}" = { }; }; - systemd.tmpfiles.rules = [ "f /var/lib/systemd/linger/${config.ghaf.users.accounts.user}" ]; + # Uinput kernel module + boot.kernelModules = [ "uinput" ]; + + # Rfkill udev rule + services.udev.extraRules = '' + KERNEL=="rfkill", SUBSYSTEM=="misc", GROUP="${bluetoothUser}" + KERNEL=="uinput", SUBSYSTEM=="misc", GROUP="${bluetoothUser}" + ''; + + # Dbus policy updates + services.dbus.packages = [ + (pkgs.writeTextFile { + name = "bluez-dbus-policy"; + text = '' + + + + + + + + + + + + + + + + ''; + destination = "/share/dbus-1/system.d/bluez.conf"; + }) + ]; + + # Configure bluetooth service + systemd.services.bluetooth.serviceConfig = { + User = "${bluetoothUser}"; + Group = "${bluetoothUser}"; + }; }; } diff --git a/modules/common/systemd/hardened-configs/common/bluetooth.nix b/modules/common/systemd/hardened-configs/common/bluetooth.nix new file mode 100644 index 000000000..45dd9fffc --- /dev/null +++ b/modules/common/systemd/hardened-configs/common/bluetooth.nix @@ -0,0 +1,80 @@ +# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 +{ + ProtectProc = "noaccess"; + ProcSubset = "pid"; + ProtectHome = true; + ProtectSystem = "full"; + PrivateTmp = true; + PrivateMounts = true; + UMask = 77; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + KeyringMode = "private"; + ProtectHostname = true; + ProtectClock = true; + ProtectControlGroups = true; + RestrictRealtime = true; + RemoveIPC = true; + NotifyAccess = "all"; + NoNewPrivileges = true; + RestrictSUIDSGID = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + IPAddressDeny = "any"; + RestrictAddressFamilies = [ + "AF_BLUETOOTH" + "AF_ALG" + "AF_UNIX" + ]; + ReadWritePaths = [ "/var/lib/bluetooth" ]; + DeviceAllow = [ + "/dev/rfkill" + "/dev/uinput" + ]; + RestrictNamespaces = [ + "~user" + "~pid" + "~net" + "~uts" + "~mnt" + "~cgroup" + "~ipc" + ]; + AmbientCapabilities = [ + "CAP_NET_BIND_SERVICE" + "CAP_NET_ADMIN" + "CAP_NET_RAW" + "CAP_SYS_RESOURCE" + "CAP_AUDIT_WRITE" + ]; + CapabilityBoundingSet = [ + "CAP_NET_BIND_SERVICE" + "CAP_NET_ADMIN" + "CAP_NET_RAW" + "CAP_SYS_RESOURCE" + "CAP_AUDIT_WRITE" + ]; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "~@swap" + "~@timer" + "~@pkey" + "~@debug" + "~@cpu_emulation" + "~@mount" + "~@ipc" + "~@resources" + "~@memlock" + "~@keyring" + "~@raw_io" + "~@clock" + "~@aio" + "~@setuid" + "~@module" + "~@reboot" + "~@sandbox" + "~@chown" + ]; +} diff --git a/modules/common/users/accounts.nix b/modules/common/users/accounts.nix index e3822f8d7..23cea94e4 100644 --- a/modules/common/users/accounts.nix +++ b/modules/common/users/accounts.nix @@ -34,7 +34,7 @@ in config = mkIf cfg.enable { users = { - mutableUsers = true; + mutableUsers = false; users."${cfg.user}" = { isNormalUser = true; inherit (cfg) password; @@ -50,6 +50,7 @@ in members = [ cfg.user ]; }; }; + # to build ghaf as ghaf-user with caches nix.settings.trusted-users = mkIf config.ghaf.profiles.debug.enable [ cfg.user ]; }; diff --git a/modules/microvm/virtualization/microvm/audiovm.nix b/modules/microvm/virtualization/microvm/audiovm.nix index 0e127287f..dfbea34ed 100644 --- a/modules/microvm/virtualization/microvm/audiovm.nix +++ b/modules/microvm/virtualization/microvm/audiovm.nix @@ -21,6 +21,7 @@ let audiovmBaseConfiguration = { imports = [ inputs.self.nixosModules.givc-audiovm + inputs.impermanence.nixosModules.impermanence (import ./common/vm-networking.nix { inherit config @@ -30,6 +31,7 @@ let ; internalIP = 5; }) + ./common/storagevm.nix ( { lib, pkgs, ... }: { @@ -52,9 +54,22 @@ let withResolved = true; withTimesyncd = true; withDebug = configHost.ghaf.profiles.debug.enable; + withHardenedConfigs = true; }; givc.audiovm.enable = true; services.audio.enable = true; + storagevm = { + enable = true; + name = "audiovm"; + directories = [ + { + directory = "/var/lib/bluetooth"; + user = "bluetooth"; + group = "bluetooth"; + mode = "u=rwx,g=,o="; + } + ]; + }; }; environment = { diff --git a/modules/reference/appvms/business.nix b/modules/reference/appvms/business.nix index 89fccc3e0..9138ad99d 100644 --- a/modules/reference/appvms/business.nix +++ b/modules/reference/appvms/business.nix @@ -57,13 +57,10 @@ in hardware.pulseaudio = { enable = true; extraConfig = '' - load-module module-tunnel-sink sink_name=chromium-speaker server=audio-vm:4713 format=s16le channels=2 rate=48000 - load-module module-tunnel-source source_name=chromium-mic server=audio-vm:4713 format=s16le channels=1 rate=48000 - - # Set sink and source default max volume to about 90% (0-65536) - set-sink-volume chromium-speaker 60000 - set-source-volume chromium-mic 60000 + load-module module-tunnel-sink-new sink_name=business-speaker server=audio-vm:4713 reconnect_interval_ms=1000 + load-module module-tunnel-source-new source_name=business-mic server=audio-vm:4713 reconnect_interval_ms=1000 ''; + package = pkgs.pulseaudio-ghaf; }; time.timeZone = config.time.timeZone; diff --git a/modules/reference/appvms/comms.nix b/modules/reference/appvms/comms.nix index a909f3368..806a264dc 100644 --- a/modules/reference/appvms/comms.nix +++ b/modules/reference/appvms/comms.nix @@ -43,13 +43,10 @@ in hardware.pulseaudio = { enable = true; extraConfig = '' - load-module module-tunnel-sink sink_name=element-speaker server=audio-vm:4713 format=s16le channels=2 rate=48000 - load-module module-tunnel-source source_name=element-mic server=audio-vm:4713 format=s16le channels=1 rate=48000 - - # Set sink and source default max volume to about 90% (0-65536) - set-sink-volume element-speaker 60000 - set-source-volume element-mic 60000 + load-module module-tunnel-sink-new sink_name=comms-speaker server=audio-vm:4713 reconnect_interval_ms=1000 + load-module module-tunnel-source-new source_name=comms-mic server=audio-vm:4713 reconnect_interval_ms=1000 ''; + package = pkgs.pulseaudio-ghaf; }; systemd = { diff --git a/overlays/custom-packages/pulseaudio/pulseaudio-remove-dont-move.patch b/overlays/custom-packages/pulseaudio/pulseaudio-remove-dont-move.patch index 69680833a..363c9b1a6 100644 --- a/overlays/custom-packages/pulseaudio/pulseaudio-remove-dont-move.patch +++ b/overlays/custom-packages/pulseaudio/pulseaudio-remove-dont-move.patch @@ -1,3 +1,5 @@ +# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors +# SPDX-License-Identifier: Apache-2.0 diff --git a/src/modules/module-tunnel-sink-new.c b/src/modules/module-tunnel-sink-new.c index 0b91ce266..ea41c50e2 100644 --- a/src/modules/module-tunnel-sink-new.c diff --git a/packages/bt-launcher/default.nix b/packages/bt-launcher/default.nix index 08e2fdb94..911c7adbe 100644 --- a/packages/bt-launcher/default.nix +++ b/packages/bt-launcher/default.nix @@ -14,7 +14,7 @@ writeShellApplication { export PULSE_SERVER=audio-vm:4713 export DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/ssh_session_dbus.sock export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/tmp/ssh_system_dbus.sock - ${openssh}/bin/ssh -M -S /tmp/control_socket \ + ${openssh}/bin/ssh -M -S /tmp/control_socket_bt \ -f -N -q ghaf@audio-vm \ -i /run/waypipe-ssh/id_ed25519 \ -o StrictHostKeyChecking=no \ @@ -26,7 +26,7 @@ writeShellApplication { ${blueman}/bin/blueman-applet & ${blueman}/bin/blueman-manager # Use the control socket to close the ssh tunnel. - ${openssh}/bin/ssh -q -S /tmp/control_socket -O exit ghaf@audio-vm + ${openssh}/bin/ssh -q -S /tmp/control_socket_bt -O exit ghaf@audio-vm ''; meta = {