aboutsummaryrefslogtreecommitdiff
path: root/gnu/build
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/build')
-rw-r--r--gnu/build/activation.scm87
-rw-r--r--gnu/build/file-systems.scm103
-rw-r--r--gnu/build/image.scm14
-rw-r--r--gnu/build/linux-modules.scm62
4 files changed, 194 insertions, 72 deletions
diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm
index d8c0cd22a3..a57ca78a86 100644
--- a/gnu/build/activation.scm
+++ b/gnu/build/activation.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
;;; Copyright © 2020 Christine Lemmer-Webber <cwebber@dustycloud.org>
;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
+;;; Copyright © 2022 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2024 Nicolas Graves <ngraves@ngraves.fr>
;;;
;;; This file is part of GNU Guix.
@@ -27,7 +28,7 @@
(define-module (gnu build activation)
#:use-module (gnu system accounts)
- #:use-module (gnu system setuid)
+ #:use-module (gnu system privilege)
#:use-module (gnu build accounts)
#:use-module (gnu build linux-boot)
#:use-module (guix build utils)
@@ -41,7 +42,7 @@
#:export (activate-users+groups
activate-user-home
activate-etc
- activate-setuid-programs
+ activate-privileged-programs
activate-special-files
activate-modprobe
activate-firmware
@@ -279,56 +280,80 @@ they already exist."
string<?)))
(define %setuid-directory
- ;; Place where setuid programs are stored.
+ ;; Place where setuid programs used to be stored. It exists for backwards
+ ;; compatibility & will be removed. Use %PRIVILEGED-PROGRAM-DIRECTORY instead.
"/run/setuid-programs")
-(define (activate-setuid-programs programs)
- "Turn PROGRAMS, a list of file setuid-programs record, into setuid programs
-stored under %SETUID-DIRECTORY."
- (define (make-setuid-program program setuid? setgid? uid gid)
- (let ((target (string-append %setuid-directory
+(define %privileged-program-directory
+ ;; Place where privileged copies of programs are stored.
+ "/run/privileged/bin")
+
+(define (activate-privileged-programs programs libcap)
+ "Turn PROGRAMS, a list of file privileged-programs records, into privileged
+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
+ (cut string-append directory "/" <>))
+ (scandir directory
+ (lambda (file)
+ (not (member file '("." ".."))))
+ string<?))
+ (mkdir-p directory)) )
+
+ (define (make-privileged-program program setuid? setgid? uid gid capabilities)
+ (let ((target (string-append %privileged-program-directory
"/" (basename program)))
(mode (+ #o0555 ; base permissions
(if setuid? #o4000 0) ; setuid bit
(if setgid? #o2000 0)))) ; setgid bit
(copy-file program target)
(chown target uid gid)
- (chmod target mode)))
-
- (format #t "setting up setuid programs in '~a'...~%"
- %setuid-directory)
- (if (file-exists? %setuid-directory)
- (for-each (compose delete-file
- (cut string-append %setuid-directory "/" <>))
- (scandir %setuid-directory
- (lambda (file)
- (not (member file '("." ".."))))
- string<?))
- (mkdir-p %setuid-directory))
+ (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.
+ (symlink (string-append %privileged-program-directory
+ "/" (basename program))
+ (string-append %setuid-directory
+ "/" (basename program))))
+
+ (format #t "setting up privileged programs in '~a'...~%"
+ %privileged-program-directory)
+ (ensure-empty-directory %privileged-program-directory)
+ (ensure-empty-directory %setuid-directory)
(for-each (lambda (program)
(catch 'system-error
(lambda ()
- (let* ((program-name (setuid-program-program program))
- (setuid? (setuid-program-setuid? program))
- (setgid? (setuid-program-setgid? program))
- (user (setuid-program-user program))
- (group (setuid-program-group program))
+ (let* ((program-name (privileged-program-program program))
+ (setuid? (privileged-program-setuid? 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-setuid-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 setuid program, better keep going
- ;; so that we don't leave %SETUID-DIRECTORY empty or
- ;; half-populated. This can happen if PROGRAMS contains
+ ;; If we fail to create a privileged program, better keep going
+ ;; so that we don't leave %PRIVILEGED-PROGRAM-DIRECTORY empty
+ ;; or half-populated. This can happen if PROGRAMS contains
;; incorrect file names: <https://bugs.gnu.org/38800>.
(format (current-error-port)
- "warning: failed to make ~s setuid/setgid: ~a~%"
- (setuid-program-program program)
+ "warning: failed to privilege ~s: ~a~%"
+ (privileged-program-program program)
(strerror (system-error-errno args))))))
programs))
diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm
index 78d779f398..9ceb2fda4e 100644
--- a/gnu/build/file-systems.scm
+++ b/gnu/build/file-systems.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2022 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2024 Nicolas Graves <ngraves@ngraves.fr>
+;;; Copyright © 2024 Richard Sent <richard@freakingpenguin.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -37,6 +38,8 @@
#:use-module (rnrs bytevectors)
#:use-module (ice-9 match)
#:use-module (ice-9 rdelim)
+ #:use-module (ice-9 regex)
+ #:use-module (ice-9 string-fun)
#:use-module (system foreign)
#:autoload (system repl repl) (start-repl)
#:use-module (srfi srfi-1)
@@ -1047,8 +1050,11 @@ file name or an nfs-root containing ':/')."
(match spec
((? string?)
- (if (or (string-contains spec ":/") (string=? spec "none"))
- spec ; do not resolve NFS / tmpfs devices
+ (if (or (string-contains spec ":/") ;nfs
+ (and (>= (string-length spec) 2)
+ (equal? (string-take spec 2) "//")) ;cifs
+ (string=? spec "none"))
+ spec ; do not resolve NFS / CIFS / tmpfs devices
;; Nothing to do, but wait until SPEC shows up.
(resolve identity spec identity)))
((? file-system-label?)
@@ -1078,6 +1084,7 @@ an exception in such cases but perform the nearest sane action."
((string-prefix? "f2fs" type) check-f2fs-file-system)
((string-prefix? "ntfs" type) check-ntfs-file-system)
((string-prefix? "nfs" type) (const 'pass))
+ ((string-prefix? "cifs" type) (const 'pass))
((string-prefix? "xfs" type) check-xfs-file-system)
(else #f)))
@@ -1156,6 +1163,14 @@ corresponds to the symbols listed in FLAGS."
(repair (file-system-repair fs)))
"Mount the file system described by FS, a <file-system> object, under ROOT."
+ (define* (host-to-ip host #:optional service)
+ "Return the IP address for host, which may be an IP address or a hostname."
+ (let* ((aa (match (getaddrinfo host service) ((x . _) x)))
+ (sa (addrinfo:addr aa))
+ (inet-addr (inet-ntop (sockaddr:fam sa)
+ (sockaddr:addr sa))))
+ inet-addr))
+
(define (mount-nfs source mount-point type flags options)
(let* ((idx (string-rindex source #\:))
(host-part (string-take source idx))
@@ -1163,11 +1178,7 @@ corresponds to the symbols listed in FLAGS."
(host (match (string-split host-part (string->char-set "[]"))
(("" h "") h)
((h) h)))
- (aa (match (getaddrinfo host "nfs") ((x . _) x)))
- (sa (addrinfo:addr aa))
- (inet-addr (inet-ntop (sockaddr:fam sa)
- (sockaddr:addr sa))))
-
+ (inet-addr (host-to-ip host "nfs")))
;; Mounting an NFS file system requires passing the address
;; of the server in the addr= option
(mount source mount-point type flags
@@ -1176,6 +1187,82 @@ corresponds to the symbols listed in FLAGS."
(if options
(string-append "," options)
"")))))
+
+ (define (read-cifs-credential-file file)
+ ;; Read password, user and domain options from file
+ ;;
+ ;; XXX: As of version 7.0, mount.cifs strips all lines of leading
+ ;; whitespace, parses those starting with "pass", "user" and "dom" into
+ ;; "pass=", "user=" and "domain=" options respectively and ignores
+ ;; everything else. To simplify the implementation, we pass those lines
+ ;; as is. As a consequence, the "password2" option can be specified in a
+ ;; credential file with the expected semantics (see:
+ ;; https://issues.guix.gnu.org/71594#3).
+ (with-input-from-file file
+ (lambda ()
+ (let loop
+ ((next-line (read-line))
+ (lines '()))
+ (match next-line
+ ((? eof-object?)
+ lines)
+ ((= string-trim line)
+ (loop (read-line)
+ (cond
+ ((string-prefix? "pass" line)
+ ;; mount.cifs escapes commas in the password by doubling
+ ;; them
+ (cons (string-replace-substring line "," ",,")
+ lines))
+ ((or (string-prefix? "user" line)
+ (string-prefix? "dom" line))
+ (cons line lines))
+ ;; Ignore all other lines.
+ (else
+ lines)))))))))
+
+ (define (mount-cifs source mount-point type flags options)
+ ;; Source is of form "//<server-ip-or-host>/<service>"
+ (let* ((regex-match (string-match "//([^/]+)/(.+)" source))
+ (server (match:substring regex-match 1))
+ (share (match:substring regex-match 2))
+ ;; Match ",guest,", ",guest$", "^guest,", or "^guest$," not
+ ;; e.g. user=foo,pass=notaguest
+ (guest? (string-match "(^|,)(guest)($|,)" options))
+ (credential-file (and=> (string-match "(^|,)(credentials|cred)=([^,]+)(,|$)"
+ options)
+ (cut match:substring <> 3)))
+ ;; Perform DNS resolution now instead of attempting kernel dns
+ ;; resolver upcalling. /sbin/request-key does not exist and the
+ ;; kernel hardcodes the path.
+ ;;
+ ;; (getaddrinfo) doesn't support cifs service, so omit it.
+ (inet-addr (host-to-ip server)))
+ (mount source mount-point type flags
+ (string-append "ip="
+ inet-addr
+ ;; As of Linux af1a3d2ba9 (v5.11) unc is ignored
+ ;; and source is parsed by the kernel
+ ;; directly. Pass it for compatibility.
+ ",unc="
+ ;; Match format of mount.cifs's mount syscall.
+ "\\\\" server "\\" share
+ (if guest?
+ ",user=,pass="
+ "")
+ (if options
+ ;; No need to delete "guest" from options.
+ ;; linux/fs/smb/client/fs_context.c explicitly
+ ;; ignores it. Also, avoiding excess commas
+ ;; when deleting is a pain.
+ (string-append "," options)
+ "")
+ (if credential-file
+ ;; The "credentials" option is ignored too.
+ (string-join (read-cifs-credential-file credential-file)
+ "," 'prefix)
+ "")))))
+
(let* ((type (file-system-type fs))
(source (canonicalize-device-spec (file-system-device fs)))
(target (string-append root "/"
@@ -1210,6 +1297,8 @@ corresponds to the symbols listed in FLAGS."
(cond
((string-prefix? "nfs" type)
(mount-nfs source target type flags options))
+ ((string-prefix? "cifs" type)
+ (mount-cifs source target type flags options))
((memq 'shared (file-system-flags fs))
(mount source target type flags options)
(mount "none" target #f MS_SHARED))
diff --git a/gnu/build/image.scm b/gnu/build/image.scm
index 49dc01c0d1..6ca0a428e0 100644
--- a/gnu/build/image.scm
+++ b/gnu/build/image.scm
@@ -328,18 +328,16 @@ GRUB configuration and OS-DRV as the stuff in it."
"-volume_date" "all_file_dates" "=1"
`(,@(if compression?
- '(;; ‘zisofs’ compression reduces the total image size by
- ;; ~60%.
+ '(;; ‘zisofs’ compression reduces the total image size by ~60%.
"-zisofs" "level=9:block_size=128k" ; highest compression
;; It's transparent to our Linux-Libre kernel but not to
- ;; GRUB. Don't compress the kernel, initrd, and other
- ;; files read by grub.cfg, as well as common
- ;; already-compressed file names.
+ ;; GRUB. Don't compress the kernel, initrd, and other files
+ ;; read by grub.cfg, as well as common already-compressed
+ ;; file names.
"-find" "/" "-type" "f"
;; XXX Even after "--" above, and despite documentation
- ;; claiming otherwise, "-or" is stolen by grub-mkrescue
- ;; which then chokes on it (as ‘-o …’) and dies. Don't use
- ;; "-or".
+ ;; claiming otherwise, "-or" is stolen by grub-mkrescue which
+ ;; then chokes on it (as ‘-o …’) and dies. Don't use "-or".
"-not" "-wholename" "/boot/*"
"-not" "-wholename" "/System/*"
"-not" "-name" "unicode.pf2"
diff --git a/gnu/build/linux-modules.scm b/gnu/build/linux-modules.scm
index 68c32ff873..32baf6c525 100644
--- a/gnu/build/linux-modules.scm
+++ b/gnu/build/linux-modules.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2018 Danny Milosavljevic <dannym@scratchpost.org>
;;; Copyright © 2023 Tobias Geerinckx-Rice <me@tobias.gr>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -26,6 +27,7 @@
#:use-module ((guix build utils) #:select (find-files invoke))
#:use-module (guix build union)
#:autoload (zlib) (call-with-gzip-input-port)
+ #:autoload (zstd) (call-with-zstd-input-port)
#:use-module (rnrs io ports)
#:use-module (rnrs bytevectors)
#:use-module (srfi srfi-1)
@@ -108,24 +110,29 @@ string list."
(cons (string->symbol (string-take str =))
(string-drop str (+ 1 =)))))
-;; Matches kernel modules, without compression, with GZIP compression or with
-;; XZ compression.
-(define module-regex "\\.ko(\\.gz|\\.xz)?$")
+;; Matches kernel modules, without compression, with GZIP, XZ or ZSTD
+;; compression.
+(define module-regex "\\.ko(\\.gz|\\.xz|\\.zst)?$")
(define (modinfo-section-contents file)
"Return the contents of the '.modinfo' section of FILE as a list of
key/value pairs.."
+ (define (decompress-file decompressor file)
+ (let ((port (open-file file "r0")))
+ (dynamic-wind
+ (lambda ()
+ #t)
+ (lambda ()
+ (decompressor port get-bytevector-all))
+ (lambda ()
+ (close-port port)))))
+
(define (get-bytevector file)
(cond
((string-suffix? ".ko.gz" file)
- (let ((port (open-file file "r0")))
- (dynamic-wind
- (lambda ()
- #t)
- (lambda ()
- (call-with-gzip-input-port port get-bytevector-all))
- (lambda ()
- (close-port port)))))
+ (decompress-file call-with-gzip-input-port file))
+ ((string-suffix? ".ko.zst" file)
+ (decompress-file call-with-zstd-input-port file))
(else
(call-with-input-file file get-bytevector-all))))
@@ -213,11 +220,12 @@ modules that can be postloaded, of the soft dependencies of module FILE."
(let ((suffix (match compression
('xz ".ko.xz")
('gzip ".ko.gz")
+ ('zstd ".ko.zst")
(else ".ko"))))
(string-append name suffix)))
(define (ensure-dot-ko name compression)
- "Return NAME with a '.ko[.gz|.xz]' suffix appended, unless it already has
+ "Return NAME with a '.ko[.gz|.xz|.zst]' suffix appended, unless it already has
it."
(if (string-contains name ".ko")
name
@@ -235,7 +243,7 @@ underscores."
(define (file-name->module-name file)
"Return the module name corresponding to FILE, stripping the trailing
-'.ko[.gz|.xz]' and normalizing it."
+'.ko[.gz|.xz|.zst]' and normalizing it."
(normalize-module-name (strip-extension (basename file))))
(define (find-module-file directory module)
@@ -333,11 +341,11 @@ not a file name."
(recursive? #t)
(lookup-module dot-ko)
(black-list (module-black-list)))
- "Load Linux module from FILE, the name of a '.ko[.gz|.xz]' file; return true
-on success, false otherwise. When RECURSIVE? is true, load its dependencies
-first (à la 'modprobe'.) The actual files containing modules depended on are
-obtained by calling LOOKUP-MODULE with the module name. Modules whose name
-appears in BLACK-LIST are not loaded."
+ "Load Linux module from FILE, the name of a '.ko[.gz|.xz|.zst]' file; return
+true on success, false otherwise. When RECURSIVE? is true, load its
+dependencies first (à la 'modprobe'.) The actual files containing modules
+depended on are obtained by calling LOOKUP-MODULE with the module name.
+Modules whose name appears in BLACK-LIST are not loaded."
(define (black-listed? module)
(let ((result (member module black-list)))
(when result
@@ -695,7 +703,7 @@ are required to access DEVICE."
"Guess the file name corresponding to NAME, a module name. That doesn't
always work because sometimes underscores in NAME map to hyphens (e.g.,
\"input-leds.ko\"), sometimes not (e.g., \"mac_hid.ko\"). If the module is
-compressed then COMPRESSED can be set to 'xz or 'gzip, depending on the
+compressed then COMPRESSED can be set to 'zstd, 'xz or 'gzip, depending on the
compression type."
(string-append directory "/" (ensure-dot-ko name compression)))
@@ -707,6 +715,8 @@ compression type."
(let ((names (list
(module-name->file-name/guess directory name)
(module-name->file-name/guess directory name
+ #:compression 'zstd)
+ (module-name->file-name/guess directory name
#:compression 'xz)
(module-name->file-name/guess directory name
#:compression 'gzip))))
@@ -729,8 +739,8 @@ compression type."
(define (write-module-name-database directory)
"Write a database that maps \"module names\" as they appear in the relevant
-ELF section of '.ko[.gz|.xz]' files, to actual file names. This format is
-Guix-specific. It aims to deal with inconsistent naming, in particular
+ELF section of '.ko[.gz|.xz|.zst]' files, to actual file names. This format
+is Guix-specific. It aims to deal with inconsistent naming, in particular
hyphens vs. underscores."
(define mapping
(map (lambda (file)
@@ -749,8 +759,8 @@ hyphens vs. underscores."
(pretty-print mapping port))))
(define (write-module-alias-database directory)
- "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding
-'modules.alias' file."
+ "Traverse the '.ko[.gz|.xz|.zst]' files in DIRECTORY and create the
+corresponding 'modules.alias' file."
(define aliases
(map (lambda (file)
(cons (file-name->module-name file) (module-aliases file)))
@@ -796,9 +806,9 @@ are found, return a tuple (DEVNAME TYPE MAJOR MINOR), otherwise return #f."
(char-set-complement (char-set #\-)))
(define (write-module-device-database directory)
- "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding
-'modules.devname' file. This file contains information about modules that can
-be loaded on-demand, such as file system modules."
+ "Traverse the '.ko[.gz|.xz|.zst]' files in DIRECTORY and create the
+corresponding 'modules.devname' file. This file contains information about
+modules that can be loaded on-demand, such as file system modules."
(define aliases
(filter-map (lambda (file)
(match (aliases->device-tuple (module-aliases file))