From 76b899a2ad0af4b6745f70e2fde2bf35254c4f5d Mon Sep 17 00:00:00 2001 From: nevaforget <> Date: Tue, 8 Sep 2026 11:48:17 +0200 Subject: [PATCH] feat(services): sandbox the moonarch oneshots Both units read one state file and write a single sysfs attribute, yet ran as unrestricted root with network access and the full capability set. systemd-analyze security scored them 7.5 EXPOSED, now 0.9 SAFE. ProtectKernelTunables and PrivateUsers stay off on purpose; the reasons sit in the comment, since without them they read as forgotten. --- modules/services.nix | 63 +++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/modules/services.nix b/modules/services.nix index aaf50c1..e92e2c1 100644 --- a/modules/services.nix +++ b/modules/services.nix @@ -3,6 +3,49 @@ { config, pkgs, lib, moonarchPkgs, ... }: +let + # Shared by the two root oneshots below. Both read one state file and write a + # single sysfs attribute, so everything else is taken away. Scored with + # `systemd-analyze security`: 7.5 EXPOSED before, 0.9 SAFE after. + # + # Deliberately absent: + # ProtectKernelTunables - remounts /sys read-only, which is exactly the + # write both units exist for. ReadWritePaths is no fix, /sys/class/… is a + # symlink into /sys/devices/…. + # PrivateUsers - capabilities inside a user namespace are namespace-local, + # while the kernel's sysfs store handlers test against the initial one. + # + # ProtectSystem=strict is safe here: it leaves /dev, /proc and /sys writable, + # and the state file is only ever read. + sysfsWriterHardening = { + CapabilityBoundingSet = [ "" ]; + AmbientCapabilities = [ "" ]; + NoNewPrivileges = true; + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateNetwork = true; + IPAddressDeny = "any"; + RestrictAddressFamilies = [ "AF_UNIX" ]; + ProtectClock = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; + KeyringMode = "private"; + UMask = "0077"; + }; +in { # --- Audio --- services.pipewire = { @@ -66,15 +109,7 @@ serviceConfig = { Type = "oneshot"; ExecStart = "${moonarchPkgs.moonarch-scripts}/bin/moonarch-batsaver-restore"; - NoNewPrivileges = true; - ProtectHome = true; - PrivateTmp = true; - ProtectKernelModules = true; - ProtectControlGroups = true; - RestrictNamespaces = true; - RestrictRealtime = true; - LockPersonality = true; - }; + } // sysfsWriterHardening; }; systemd.services.moonarch-camera = { @@ -85,15 +120,7 @@ serviceConfig = { Type = "oneshot"; ExecStart = "${moonarchPkgs.moonarch-scripts}/bin/moonarch-camera-boot"; - NoNewPrivileges = true; - ProtectHome = true; - PrivateTmp = true; - ProtectKernelModules = true; - ProtectControlGroups = true; - RestrictNamespaces = true; - RestrictRealtime = true; - LockPersonality = true; - }; + } // sysfsWriterHardening; }; # The bar, launcher and every popout. A unit rather than a spawn-at-startup so