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.
This commit is contained in:
Tobias Geerinckx-Rice 2023-07-23 02:00:00 +02:00
parent 4e58dfee6c
commit 71f0676a29
No known key found for this signature in database
GPG key ID: 0DB0FF884F556D79
4 changed files with 34 additions and 11 deletions

View file

@ -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

View file

@ -288,9 +288,10 @@ (define %privileged-program-directory
;; 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 @@ (define (ensure-empty-directory 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 @@ (define (make-privileged-program program setuid? setgid? uid gid)
(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 @@ (define (make-deprecated-wrapper program)
(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

View file

@ -46,6 +46,7 @@ (define-module (gnu services)
#: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 @@ (define (privileged-program->activation-gexp programs)
(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 @@ (define (privileged-program->activation-gexp programs)
#~(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)

View file

@ -25,13 +25,14 @@ (define-module (gnu system privilege)
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 @@ (define-record-type* <privileged-program>
(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)))