[bug#78179,2/4] guix: Add (guix build privileged) module.

Message ID 3ae3ac7b699eaacde6091d05ece786a536872066.1746086472.git.rutherther@ditigal.xyz
State New
Headers
Series Add wireshark-service-type with privileged wrapper |

Commit Message

Rutherther May 1, 2025, 8:29 a.m. UTC
  Wireshark refers to #$output/bin/dumpcap to start dumpcap. This means it's
problematic to make a service for it that would add dumpcap to privileged
programs.

This procedure introduces a possibility to replace a file in the output with a
script that will try to execute binary in /run/privileged/bin first, and
fallback to the original one from store. This ensures the package works on
both Guix System and foreign distros. The downside is that /run/privileged/bin
will be executed every time, so it would be impossible to test different
versions of the packages. To overcome that, GUIX_SKIP_PRIVILEGED variable is
introduced, and if set, the original dumpcap will be used.

* guix/build/privileged.scm (unwrap): Removes wrapping by wrap-program
* guix/build/privileged.scm (wrap-privileged): Make a shell script for a
program that needs privileges

Change-Id: Ieacd7f2d80c5b6ecba74d9309cb2c5a6d556aa8e
---
 guix/build/privileged.scm | 48 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 guix/build/privileged.scm
  

Patch

diff --git a/guix/build/privileged.scm b/guix/build/privileged.scm
new file mode 100644
index 0000000000..6a456e02c0
--- /dev/null
+++ b/guix/build/privileged.scm
@@ -0,0 +1,48 @@ 
+(define-module (guix build privileged)
+  #:use-module (gnu build activation)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 format)
+  #:export (wrap-privileged))
+
+;;; Move .xxx-real to xxx, if it exists.
+(define (unwrap binary)
+  (let* ((name (basename binary))
+         (folder (dirname binary))
+         (real (string-append folder "/." name "-real")))
+    (when (file-exists? real)
+      (format #t "Unwrapping ~a~%" binary)
+      (rename-file real binary))))
+
+;;;
+;;; 1. Move {output}/{original} to {output}/{target-folder}/{target-name}.
+;;; 2. Make a script at original-binary that executes /run/privileged/bin/{target-name}
+;;;    if it exists, if not, output/{target-folder}/{target-name} is executed.
+;;;
+(define* (wrap-privileged output
+                          original
+                          target-name
+                          #:key
+                          (unwrap? #t)
+                          (target-folder "privileged")
+                          (privileged-directory %privileged-program-directory))
+  "Make a shell wrapper for binary that should be ran as privileged.
+
+The wrapper script will try executing binary in /run/privileged/bin, if it exists,
+and if not, it will fall back to the original."
+  (let ((original-file (string-append output "/" original))
+        (target-file (string-append output "/" target-folder "/" target-name))
+        (privileged-file (string-append privileged-directory "/" target-name)))
+    (when unwrap?
+      (unwrap original-file))
+    (mkdir-p (dirname target-file))
+    (rename-file original-file target-file)
+    (call-with-output-file original-file
+      (lambda (port)
+        (format port "#!/usr/bin/env bash
+if [[ -z \"$GUIX_SKIP_PRIVILEGED\" && -f \"~a\" ]]; then
+  exec -a \"$0\" \"~a\" \"$@\"
+fi
+
+exec -a \"$0\" \"~a\" \"$@\"
+" privileged-file privileged-file target-file)
+        (chmod port #o555)))))