Subject: [bug#77383] [PATCH 2/2] gnu: speakersafetyd: Run as unprivileged user.

From: Roman Scherer <[email-masked]>
Date: Sun, 30 Mar 2025 14:26:56 +0200

* gnu/services/sound.scm (speakersafetyd): Run as unprivileged user.

Change-Id: I870bc7bfd69249da3a9c981f627e751395386bd2
---
 doc/guix.texi          |  9 +++++++
 gnu/services/sound.scm | 57 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index f6d774fd13..9a6084e994 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -27268,12 +27268,21 @@ Sound Services
 The base directory as a G-expression (@pxref{G-Expressions}) that
 contains the configuration files of the speaker models.
 
+@item @code{group} (default: @code{"speakersafetyd"}) (type: string)
+The group to run the Speaker Safety Daemon as.
+
+@item @code{log-file} (default: @code{"/var/log/speakersafetyd.log"}) (type: string)
+The path to the Speaker Safety Daemon log file.
+
 @item @code{maximum-gain-reduction} (default: @code{7}) (type: integer)
 Maximum gain reduction before panicking, useful for debugging.
 
 @item @code{speakersafetyd} (default: @code{speakersafetyd}) (type: file-like)
 The Speaker Safety Daemon package to use.
 
+@item @code{user} (default: @code{"speakersafetyd"}) (type: string)
+The user to run the Speaker Safety Daemon as.
+
 @end table
 @end deftp
 @c %end of fragment
diff --git a/gnu/services/sound.scm b/gnu/services/sound.scm
index fbaa55c553..ac87551a18 100644
--- a/gnu/services/sound.scm
+++ b/gnu/services/sound.scm
@@ -29,10 +29,12 @@ (define-module (gnu services sound)
   #:use-module (gnu system shadow)
   #:use-module (guix diagnostics)
   #:use-module (guix gexp)
+  #:use-module (guix modules)
   #:use-module (guix packages)
   #:use-module (guix records)
   #:use-module (guix store)
   #:use-module (guix ui)
+  #:use-module (gnu packages admin)
   #:use-module (gnu packages audio)
   #:use-module (gnu packages linux)
   #:use-module (gnu packages pulseaudio)
@@ -288,16 +290,53 @@ (define-configuration/no-serialization speakersafetyd-configuration
    (file-like (file-append speakersafetyd "/share/speakersafetyd"))
    "The base directory as a G-expression (@pxref{G-Expressions}) that contains
 the configuration files of the speaker models.")
+  (group
+   (string "speakersafetyd")
+   "The group to run the Speaker Safety Daemon as.")
+  (log-file
+   (string "/var/log/speakersafetyd.log")
+   "The path to the Speaker Safety Daemon log file.")
   (maximum-gain-reduction
    (integer 7)
    "Maximum gain reduction before panicking, useful for debugging.")
   (speakersafetyd
    (file-like speakersafetyd)
-   "The Speaker Safety Daemon package to use."))
+   "The Speaker Safety Daemon package to use.")
+  (user
+   (string "speakersafetyd")
+   "The user to run the Speaker Safety Daemon as."))
+
+(define speakersafetyd-accounts
+  (match-record-lambda <speakersafetyd-configuration>
+      (blackbox-directory configuration-directory group log-file maximum-gain-reduction speakersafetyd user)
+    (list (user-group
+           (name group)
+           (system? #t))
+          (user-account
+           (name user)
+           (group group)
+           (system? #t)
+           (home-directory "/var/empty")
+           (shell (file-append shadow "/sbin/nologin"))
+           (supplementary-groups '("audio"))))))
+
+(define speakersafetyd-activation
+  (match-record-lambda <speakersafetyd-configuration>
+      (blackbox-directory configuration-directory group log-file maximum-gain-reduction speakersafetyd user)
+    (with-imported-modules (source-module-closure
+                            '((gnu build activation)
+                              (guix build utils)))
+      #~(begin
+          (use-modules (gnu build activation))
+          (let ((user (getpwnam #$user)))
+            (mkdir-p/perms "/run/speakersafetyd" user #o755)
+            (mkdir-p/perms "/var/lib/speakersafetyd" user #o755)
+            ;; Blackbox files contain audio recordings and might be sensitive information
+            (mkdir-p/perms #$blackbox-directory user #o700))))))
 
 (define speakersafetyd-shepherd-service
   (match-record-lambda <speakersafetyd-configuration>
-      (blackbox-directory configuration-directory maximum-gain-reduction speakersafetyd)
+      (blackbox-directory configuration-directory group log-file maximum-gain-reduction speakersafetyd user)
     (shepherd-service
      (documentation "Run the speaker safety daemon")
      (provision '(speakersafetyd))
@@ -306,7 +345,11 @@ (define speakersafetyd-shepherd-service
                (list #$(file-append speakersafetyd "/bin/speakersafetyd")
                      "--config-path" #$configuration-directory
                      "--blackbox-path" #$blackbox-directory
-                     "--max-reduction" (number->string #$maximum-gain-reduction))))
+                     "--max-reduction" (number->string #$maximum-gain-reduction))
+               #:group #$group
+               #:log-file #$log-file
+               #:supplementary-groups '("audio")
+               #:user #$user))
      (stop #~(make-kill-destructor)))))
 
 (define speakersafetyd-service-type
@@ -324,7 +367,13 @@ (define speakersafetyd-service-type
            (compose list speakersafetyd-configuration-speakersafetyd))
           (service-extension
            profile-service-type
-           (compose list speakersafetyd-configuration-speakersafetyd))))
+           (compose list speakersafetyd-configuration-speakersafetyd))
+          (service-extension
+           account-service-type
+           speakersafetyd-accounts)
+          (service-extension
+           activation-service-type
+           speakersafetyd-activation)))
    (default-value (speakersafetyd-configuration))))
 
 ;;; sound.scm ends here
-- 
2.49.0