nckx pushed a commit to branch master
in repository guix.

commit 71f0676a295841e2cc662eec0d3e9b7e69726035
Author: Tobias Geerinckx-Rice <[email protected]>
AuthorDate: Sun Jul 23 02:00:00 2023 +0200

    privilege: Add POSIX capabilities(7) support.
    
    * gnu/system/privilege.scm (<privileged-program>): Add a field
    representing the program's POSIX capabilities.
    (privileged-program-capabilities): New public procedure.
    * doc/guix.texi (Privileged Programs): Document it.
    * gnu/build/activation.scm (activate-privileged-programs): Take a LIBCAP
    package argument providing setcap(8) to apply said capabilities.
    * gnu/services.scm (privileged-program->activation-gexp): Pass said
    package argument where supported.  Include privileged-program-capabilities
    in the compatibility hack.
---
 doc/guix.texi            |  7 +++++++
 gnu/build/activation.scm | 17 ++++++++++++-----
 gnu/services.scm         |  9 +++++++--
 gnu/system/privilege.scm | 12 ++++++++----
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index f882eb70e4..0e1e253b02 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41655,6 +41655,8 @@ invokation.
 @cindex privileged programs
 @cindex setuid programs
 @cindex setgid programs
+@cindex capabilities, POSIX
+@cindex setcap
 Some programs need to run with elevated privileges, even when they are
 launched by unprivileged users.  A notorious example is the
 @command{passwd} program, which users can run to change their
@@ -41720,6 +41722,11 @@ defaults to root.
 GID (integer) group name (string) for the group owner of the program,
 defaults to root.
 
+@item @code{capabilities} (default: @code{#f})
+A string representing the program's POSIX capabilities, as described by
+the @code{cap_to_text(3)} man page from the libcap package, or @code{#f}
+to make no changes.
+
 @end table
 @end deftp
 
diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm
index 77eb150477..a57ca78a86 100644
--- a/gnu/build/activation.scm
+++ b/gnu/build/activation.scm
@@ -288,9 +288,10 @@ they already exist."
   ;; Place where privileged copies of programs are stored.
   "/run/privileged/bin")
 
-(define (activate-privileged-programs programs)
+(define (activate-privileged-programs programs libcap)
   "Turn PROGRAMS, a list of file privileged-programs records, into privileged
-copies stored under %PRIVILEGED-PROGRAM-DIRECTORY."
+copies stored under %PRIVILEGED-PROGRAM-DIRECTORY, using LIBCAP's setcap(8)
+binary if needed."
   (define (ensure-empty-directory directory)
     (if (file-exists? directory)
         (for-each (compose delete-file
@@ -301,7 +302,7 @@ copies stored under %PRIVILEGED-PROGRAM-DIRECTORY."
                            string<?))
         (mkdir-p directory))    )
 
-  (define (make-privileged-program program setuid? setgid? uid gid)
+  (define (make-privileged-program program setuid? setgid? uid gid 
capabilities)
     (let ((target (string-append %privileged-program-directory
                                  "/" (basename program)))
           (mode (+ #o0555                   ; base permissions
@@ -309,7 +310,10 @@ copies stored under %PRIVILEGED-PROGRAM-DIRECTORY."
                    (if setgid? #o2000 0)))) ; setgid bit
       (copy-file program target)
       (chown target uid gid)
-      (chmod target mode)))
+      (chmod target mode)
+      (when (and capabilities libcap)
+        (system* (string-append libcap "/sbin/setcap")
+                 "-q" capabilities target))))
 
   (define (make-deprecated-wrapper program)
     ;; This will eventually become a script that warns on usage, then vanish.
@@ -331,13 +335,16 @@ copies stored under %PRIVILEGED-PROGRAM-DIRECTORY."
                          (setgid?      (privileged-program-setgid? program))
                          (user         (privileged-program-user program))
                          (group        (privileged-program-group program))
+                         (capabilities (privileged-program-capabilities 
program))
                          (uid (match user
                                 ((? string?) (passwd:uid (getpwnam user)))
                                 ((? integer?) user)))
                          (gid (match group
                                 ((? string?) (group:gid (getgrnam group)))
                                 ((? integer?) group))))
-                    (make-privileged-program program-name setuid? setgid? uid 
gid)
+                    (make-privileged-program program-name
+                                             setuid? setgid? uid gid
+                                             capabilities)
                     (make-deprecated-wrapper program-name)))
                 (lambda args
                   ;; If we fail to create a privileged program, better keep 
going
diff --git a/gnu/services.scm b/gnu/services.scm
index 553ec93a6c..610a2df395 100644
--- a/gnu/services.scm
+++ b/gnu/services.scm
@@ -46,6 +46,7 @@
   #:use-module (gnu packages base)
   #:use-module (gnu packages bash)
   #:use-module (gnu packages hurd)
+  #:use-module (gnu packages linux)
   #:use-module (gnu system privilege)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
@@ -899,12 +900,14 @@ FILES must be a list of name/file-like object pairs."
                                (setuid?      (privileged-program-setuid? 
program))
                                (setgid?      (privileged-program-setgid? 
program))
                                (user         (privileged-program-user program))
-                               (group        (privileged-program-group 
program)) )
+                               (group        (privileged-program-group 
program))
+                               (capabilities (privileged-program-capabilities 
program)))
                            #~(privileged-program
                               (setuid? #$setuid?)
                               (setgid? #$setgid?)
                               (user    #$user)
                               (group   #$group)
+                              (capabilities #$capabilities)
                               (program #$program-name))))
                        programs)))
     (with-imported-modules (source-module-closure
@@ -912,7 +915,9 @@ FILES must be a list of name/file-like object pairs."
       #~(begin
           (use-modules (gnu system privilege))
 
-          (activate-privileged-programs (list #$@programs))))))
+          (activate-privileged-programs (list #$@programs)
+                                        #$(and (supported-package? libcap)
+                                               libcap))))))
 
 (define privileged-program-service-type
   (service-type (name 'privileged-program)
diff --git a/gnu/system/privilege.scm b/gnu/system/privilege.scm
index 455a659a12..d89d5d5d1c 100644
--- a/gnu/system/privilege.scm
+++ b/gnu/system/privilege.scm
@@ -25,13 +25,14 @@
             privileged-program-setuid?
             privileged-program-setgid?
             privileged-program-user
-            privileged-program-group))
+            privileged-program-group
+            privileged-program-capabilities))
 
 ;;; Commentary:
 ;;;
 ;;; Data structures representing privileged programs: binaries with additional
-;;; permissions such as setuid/setgid.  This is meant to be used both on the
-;;; host side and at run time--e.g., in activation snippets.
+;;; permissions such as setuid/setgid, or POSIX capabilities.  This is meant to
+;;; be used both on the host side and at run time--e.g., in activation 
snippets.
 ;;;
 ;;; Code:
 
@@ -51,4 +52,7 @@
                  (default 0))
   ;; The group name or ID we want to set this to (defaults to root's).
   (group         privileged-program-group ;integer or string
-                 (default 0)))
+                 (default 0))
+  ;; POSIX capabilities in cap_from_text(3) form (defaults to #f: none).
+  (capabilities  privileged-program-capabilities ;string or #f
+                 (default #f)))

Reply via email to