From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: paul Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 28 Jul 2024 15:26:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= X-Debbugs-Original-To: guix-patches@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.172218034214872 (code B ref -1); Sun, 28 Jul 2024 15:26:01 +0000 Received: (at submit) by debbugs.gnu.org; 28 Jul 2024 15:25:42 +0000 Received: from localhost ([127.0.0.1]:44229 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5mH-0003ro-Jl for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:25:41 -0400 Received: from lists.gnu.org ([209.51.188.17]:52464) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5mE-0003rc-OC for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:25:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sY5m2-0004V0-Uq for guix-patches@gnu.org; Sun, 28 Jul 2024 11:25:26 -0400 Received: from confino.investici.org ([2a11:7980:1::2:0]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sY5m0-00053o-JC; Sun, 28 Jul 2024 11:25:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1722180309; bh=OUwnvqhujTfQ/pGw1McFt2HPEcGsux1nVERDFA8AyTo=; h=Date:To:Cc:From:Subject:From; b=o9TPXbjZYtmR2usVZ2mGu/eh7/89bvl/k2QCI2lRjvnwNOgLSxFJkjPQjpQ7txz6B 530fdE8UKAueDNj57CiW3oivoZ6MqUW4POVZnQdNwoAsurDWLsNKebSmvLtAe+mArp LUcFrBjMQeiMntGdQGFieikHt/WRy1avXdCBHNpw= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WX5053k9wz112h; Sun, 28 Jul 2024 15:25:09 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WX50538RHz112f; Sun, 28 Jul 2024 15:25:09 +0000 (UTC) Message-ID: Date: Sun, 28 Jul 2024 17:25:09 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 Content-Language: en-US From: paul Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2a11:7980:1::2:0; envelope-from=goodoldpaul@autistici.org; helo=confino.investici.org X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.4 (-) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.4 (--) Dear guixers, I'm sending a small patch set to add a Guix System service (hopefully :) ) able to handle /etc/subuid and /etc/subgid . It should be a first step towards a structured rootless-podman-service-type that I plan to implement. Please let me know your thoughts. Ludo’ : I'm CCing you just FYI , this is not an ask for review just in some files your name is the only one in the copyright section and it may be that you are the most familiar with those, but please look at this when and if you have time. Thank you everyone for your work, giacomo From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH 2/3] account: Add /etc/subid and /etc/subgid allocation logic. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 28 Jul 2024 15:31:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172218061915444 (code B ref 72337); Sun, 28 Jul 2024 15:31:02 +0000 Received: (at 72337) by debbugs.gnu.org; 28 Jul 2024 15:30:19 +0000 Received: from localhost ([127.0.0.1]:44235 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5qk-000411-8t for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:30:19 -0400 Received: from confino.investici.org ([93.190.126.19]:20453) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5qi-00040s-HS for 72337@debbugs.gnu.org; Sun, 28 Jul 2024 11:30:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1722180604; bh=fnoegWIFjnuS7mQqES8XFN0q6+mWfKZDt6xrwN84Cvc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uJiMOEd00zp1980vrbka1lfB0a7dVZKwve7Un3yb3jXbjoqoVt23LDEgJTqhg4Fmj TTSqSdhdaQxOvFbV0ZYobbsG17OEYIbIlUgJhn5EizVJIE85WUz2WuBdJD2DwiVodU L/Kix0rbqZ5iHkHB/MBojBuA0/doF5oElyq+FM8w= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WX55m11TFz112j; Sun, 28 Jul 2024 15:30:04 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WX55m0BsFz112f; Sun, 28 Jul 2024 15:30:03 +0000 (UTC) From: Giacomo Leidi Date: Sun, 28 Jul 2024 17:29:25 +0200 Message-ID: <56cc1f5f7544fe85aeedab1afc05b2f8ea33a7d6.1722180566.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <1901209e4998ad29192b6f73b1e2828bc5d6f90e.1722180566.git.goodoldpaul@autistici.org> References: <1901209e4998ad29192b6f73b1e2828bc5d6f90e.1722180566.git.goodoldpaul@autistici.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) * gnu/build/accounts.scm (list-set): New variable; (%sub-id-min): new variable; (%sub-id-max): new variable; (%sub-id-count): new variable; (sub-id?): new variable; (subid-range-fits?): new variable; (subid-range-fits-between?): new variable; (insert-subid-range): new variable; (reserve-subids): new variable; (range->entry): new variable; (entry->range): new variable; (allocate-subids): new variable; (subuid+subgid-databases): new variable. * gnu/system/accounts.scm (subid-range-end): New variable; (subid-range-has-start?): new variable; (subid-range-less): new variable. * test/accounts.scm: Test them. Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d --- gnu/build/accounts.scm | 229 +++++++++++++++++++++++++++++++++++++++- gnu/system/accounts.scm | 30 ++++++ tests/accounts.scm | 108 +++++++++++++++++++ 3 files changed, 366 insertions(+), 1 deletion(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index ea8c69f205..3cbbacfaee 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -74,8 +74,12 @@ (define-module (gnu build accounts) %id-max %system-id-min %system-id-max + %sub-id-min + %sub-id-max + %sub-id-count - user+group-databases)) + user+group-databases + subuid+subgid-databases)) ;;; Commentary: ;;; @@ -91,6 +95,18 @@ (define-module (gnu build accounts) ;;; ;;; Code: + +;;; +;;; General utilities. +;;; + +(define (list-set lst el k) + (if (>= k (length lst)) + `(,@lst ,el) + `(,@(list-head lst k) + ,el + ,@(list-tail lst k)))) + ;;; ;;; Machinery to define user and group databases. @@ -342,6 +358,12 @@ (define %id-max 60000) (define %system-id-min 100) (define %system-id-max 999) +;; According to Shadow's libmisc/find_new_sub_uids.c and +;; libmisc/find_new_sub_gids.c. +(define %sub-id-min 100000) +(define %sub-id-max 600100000) +(define %sub-id-count 65536) + (define (system-id? id) (and (> id %system-id-min) (<= id %system-id-max))) @@ -350,6 +372,10 @@ (define (user-id? id) (and (>= id %id-min) (< id %id-max))) +(define (sub-id? id) + (and (>= id %sub-id-min) + (< id %sub-id-max))) + (define* (allocate-id assignment #:key system?) "Return two values: a newly allocated ID, and an updated record based on ASSIGNMENT. If SYSTEM? is true, return a system ID." @@ -405,6 +431,156 @@ (define* (reserve-ids allocation ids #:key (skip? #t)) (allocation-ids allocation) ids)))) +(define (subid-range-fits? r interval-start interval-end) + (and (<= interval-start + (subid-range-start r)) + (<= (subid-range-end r) + interval-end))) + +(define (subid-range-fits-between? r a b) + (subid-range-fits? r + (+ (subid-range-start a) 1) + (- (subid-range-end b) 1))) + +(define (insert-subid-range range lst) + (define* (actualize r #:key (start %sub-id-min)) + (if (subid-range-has-start? r) + r + (subid-range + (inherit r) + (start start)))) + (define lst-length (length lst)) + (define range-name (subid-range-name range)) + (define range-start (subid-range-start range)) + (define has-start? (subid-range-has-start? range)) + (define range-end (subid-range-end range)) + + (when has-start? + (unless (and (sub-id? range-start) + (sub-id? range-end)) + (raise + (string-append "Subid range of " range-name + " from " range-start " to " range-end + " spans over illegal subids. Max allowed is " + %sub-id-max ", min is " %sub-id-min ".")))) + + (if (<= lst-length 1) + (if (= lst-length 0) + (list (actualize range)) + (if (subid-range-less range (first lst)) + (list-set lst (actualize range) 0) + (list-set lst + (actualize + range + #:start (and (subid-range-has-start? (first lst)) + (+ (subid-range-end (first lst)) 1))) + 1))) + (let loop ((i 0)) + (define next-i (+ i 1)) + (define ith-range + (list-ref lst i)) + (define ith-start + (subid-range-start ith-range)) + (define ith-has-start? + (subid-range-has-start? ith-range)) + (define ith-name + (subid-range-name ith-range)) + + (if (and + (= next-i lst-length) + (subid-range-less ith-range range)) + (let ((actual-range + (actualize + range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))))) + (list-set lst + actual-range + lst-length)) + (let* ((next-range + (list-ref lst next-i)) + (next-has-start? + (subid-range-has-start? next-range))) + (cond + + ((and has-start? (= range-start ith-start)) + (raise + (string-append "Subid range of " range-name + " has same start " + (number->string range-start) + " of the one " + "from " ith-name "."))) + + ((and (= i 0) + (subid-range-less range ith-range) + (or + (and + has-start? ith-has-start? + (subid-range-fits? (actualize range) + %sub-id-min + (- (subid-range-start + (actualize ith-range)) + 1))) + (not (and has-start? ith-has-start?)))) + (list-set lst (actualize range) 0)) + + ((subid-range-less range ith-range) + (raise + (string-append "Subid range of " range-name + " overlaps with the one of " + ith-name "."))) + + ((and (subid-range-less ith-range range) + (subid-range-less range next-range)) + (if (or (not (and has-start? + ith-has-start? + next-has-start?)) + + (and has-start? + ith-has-start? + next-has-start? + (subid-range-fits-between? range + ith-range + next-range))) + (list-set lst + (actualize range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))) + next-i) + (if (>= i lst-length) + (if (and (subid-range-less next-range range) + (let ((actual-next + (actualize next-range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))))) + (or (not (subid-range-has-start? actual-next)) + (subid-range-fits? + (actualize range + #:start (and next-has-start? + (+ (subid-range-end next-range) 1))) + (+ (subid-range-end actual-next) 1) + %sub-id-max)))) + (list-set lst range lst-length) + (raise + (string-append "Couldn't fit " range-name ", reached end of list."))) + (loop next-i)))) + + ((or + (not has-start?) + (subid-range-less next-range range)) + (loop next-i)) + + (else + (raise (string-append "Couldn't fit " range-name ", this should never happen."))))))))) + +(define* (reserve-subids allocation ranges) + "Mark the subid ranges listed in RANGES as reserved in ALLOCATION. +ALLOCATION is supposed to be sorted by SUBID-RANGE-LESS." + (fold insert-subid-range + allocation + (sort-list ranges + subid-range-less))) + (define (allocated? allocation id) "Return true if ID is already allocated as part of ALLOCATION." (->bool (vhash-assv id (allocation-ids allocation)))) @@ -540,6 +716,31 @@ (define* (allocate-passwd users groups #:optional (current-passwd '())) uids users))) +(define (range->entry range) + (subid-entry + (name (subid-range-name range)) + (start (subid-range-start range)) + (count (subid-range-count range)))) + +(define (entry->range entry) + (subid-range + (name (subid-entry-name entry)) + (start (subid-entry-start entry)) + (count (subid-entry-count entry)))) + +(define* (allocate-subids ranges #:optional (current-ranges '())) + "Return a list of subids entries for RANGES, a list of . Members +for each group are taken from MEMBERS, a vhash that maps ranges names to member +names. IDs found in CURRENT-RANGES, a list of subid entries, are reused." + (define subids + ;; Mark all the currently used IDs and the explicitly requested IDs as + ;; reserved. + (reserve-subids (reserve-subids (list) + current-ranges) + ranges)) + + (map range->entry subids)) + (define* (days-since-epoch #:optional (current-time current-time)) "Return the number of days elapsed since the 1st of January, 1970." (let* ((now (current-time time-utc)) @@ -615,3 +816,29 @@ (define* (user+group-databases users groups #:current-time current-time)) (values group-entries passwd-entries shadow-entries)) + +(define* (subuid+subgid-databases subuids subgids + #:key + (current-subuids + (map entry->range + (empty-if-not-found read-subuid))) + (current-subgids + (map entry->range + (empty-if-not-found read-subgid)))) + "Return two values: the list of subgid entries, and the list of subuid entries +corresponding to SUBUIDS and SUBGIDS. +Preserve stateful bits from CURRENT-SUBUIDS and CURRENT-SUBGIDS." + + (define (range-eqv? a b) + (string=? (subid-range-name a) + (subid-range-name b))) + + (define subuid-entries + (allocate-subids + (lset-difference range-eqv? subuids current-subuids) current-subuids)) + + (define subgid-entries + (allocate-subids + (lset-difference range-eqv? subgids current-subgids) current-subgids)) + + (values subuid-entries subgid-entries)) diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 9a006c188d..1b88ca301f 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -45,6 +45,9 @@ (define-module (gnu system accounts) subid-range-name subid-range-start subid-range-count + subid-range-end + subid-range-has-start? + subid-range-less sexp->user-account sexp->user-group @@ -102,6 +105,33 @@ (define-record-type* ; find_new_sub_uids.c (default 65536))) +(define (subid-range-end range) + "Returns the last subid referenced in RANGE." + (and + (subid-range-has-start? range) + (+ (subid-range-start range) + (subid-range-count range) + -1))) + +(define (subid-range-has-start? range) + "Returns #t when RANGE's start is a number." + (number? (subid-range-start range))) + +(define (subid-range-less a b) + "Returns #t when subid range A either starts before, or is more specific +than B. When it is not possible to determine whether a range is more specific +w.r.t. another range their names are compared alphabetically." + (define start-a (subid-range-start a)) + (define start-b (subid-range-start b)) + (cond ((and (not start-a) (not start-b)) + (string< (subid-range-name a) + (subid-range-name b))) + ((and start-a start-b) + (< start-a start-b)) + (else + (and start-a + (not start-b))))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 4944c22f49..2fbebfaf56 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -193,6 +193,7 @@ (define %subgid-sample (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) +(define allocate-subids (@@ (gnu build accounts) allocate-subids)) (test-equal "allocate-groups" ;; Allocate GIDs in a stateless fashion. @@ -257,6 +258,69 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (list (group-entry (name "d") (gid (- %id-max 2)))))) +(test-equal "allocate-subids" + ;; Allocate sub IDs in a stateless fashion. + (list (subid-entry (name "root") (start %sub-id-min) (count 100)) + (subid-entry (name "t") (start 100100) (count 899)) + (subid-entry (name "x") (start 100999) (count 200))) + (allocate-subids (list + (subid-range (name "x") (count 200)) + (subid-range (name "t") (count 899))) + (list (subid-range (name "root") (count 100))))) + +(test-equal "allocate-subids with requested IDs ranges" + ;; Make sure the requested sub ID for "t" and "x" are honored. + (list (subid-entry (name "x") (start %sub-id-min) (count 200)) + (subid-entry (name "t") (start 1000000) (count 899)) + (subid-entry (name "l") (start 1000899) (count 100)) + (subid-entry (name "root") (start 1000999) (count 100))) + (allocate-subids (list + (subid-range (name "root") (count 100)) + (subid-range (name "l") (count 100))) + (list + (subid-range (name "x") (start %sub-id-min) (count 200)) + (subid-range (name "t") (start 1000000) (count 899))))) + +(test-equal "allocate-subids with interleaving" + ;; Make sure the requested sub ID for "m" is honored. + (list (subid-entry (name "x") (start %sub-id-min) (count 200)) + (subid-entry (name "t") (start 1000000) (count 899)) + (subid-entry (name "i") (start 1100000) (count 1)) + (subid-entry (name "root") (start 1100001) (count 100)) + (subid-entry (name "m") (start 1200000) (count 27))) + (allocate-subids (list (subid-range (name "m") (start 1200000) (count 27))) + (list + (subid-range (name "x") (start %sub-id-min) (count 200)) + (subid-range (name "t") (start 1000000) (count 899)) + (subid-range (name "i") (start 1100000) (count 1)) + (subid-range (name "root") (count 100))))) + +(let ((inputs+currents + (list + ;; Try impossible before + (list + (list (subid-range (name "m") (start 100100) (count 27))) + (list + (subid-range (name "x") (start %sub-id-min) (count 150)))) + ;; Try impossible after + (list + (list (subid-range (name "m") (start %sub-id-min) (count 30))) + (list + (subid-range (name "x") (start (+ 29 %sub-id-min)) (count 150)))) + ;; Try impossible between + (list + (list (subid-range (name "m") (start 100200) (count 500))) + (list + (subid-range (name "root") (start %sub-id-min) (count 100)) + (subid-range (name "x") (start (+ %sub-id-min 500)) (count 100))))))) + (test-error "allocate-subids with interleaving, impossible interleaving" + "error" + ;; Make sure it's impossible to explicitly request impossible allocations + (for-each + (lambda (lst) + (allocate-subids (first lst) (second lst))) + inputs+currents))) + (test-equal "allocate-passwd" ;; Allocate UIDs in a stateless fashion. (list (password-entry (name "alice") (uid %id-min) (gid 1000) @@ -376,4 +440,48 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (make-time type 0 (* 24 3600 100))))) list)) +(test-equal "subuid+subgid-databases" + ;; The whole process. + (list (list (subid-entry (name "root") + (start %sub-id-min) + (count 100)) + (subid-entry (name "alice") + (start (+ %sub-id-min 100)) + (count 200)) + (subid-entry (name "bob") + (start (+ %sub-id-min 100 200)) + (count 200))) + (list + (subid-entry (name "root") + (start %sub-id-min) + (count 200)) + (subid-entry (name "alice") + (start (+ %sub-id-min 200)) + (count 400)) + (subid-entry (name "charlie") + (start (+ %sub-id-min 200 400)) + (count 300)))) + (call-with-values + (lambda () + (subuid+subgid-databases + (list (subid-range (name "root") + (start %sub-id-min) + (count 100)) + (subid-range (name "alice") + (start (+ %sub-id-min 100)) + (count 200)) + (subid-range (name "bob") + (count 200))) + (list + (subid-range (name "alice") + (count 400)) + (subid-range (name "charlie") + (count 300))) + #:current-subgids + (list (subid-range (name "root") + (start %sub-id-min) + (count 200))) + #:current-subuids '())) + list)) + (test-end "accounts") -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH 1/3] accounts: Add /etc/subuid and /etc/subgid support. References: In-Reply-To: Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 28 Jul 2024 15:31:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172218062315461 (code B ref 72337); Sun, 28 Jul 2024 15:31:02 +0000 Received: (at 72337) by debbugs.gnu.org; 28 Jul 2024 15:30:23 +0000 Received: from localhost ([127.0.0.1]:44237 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5qo-00041J-BC for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:30:22 -0400 Received: from confino.investici.org ([93.190.126.19]:47669) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5qi-00040r-HT for 72337@debbugs.gnu.org; Sun, 28 Jul 2024 11:30:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1722180603; bh=57uLy6k2r3iCl10Cv++Iv100kCJ0wJGKOHfjuP5LCkI=; h=From:To:Cc:Subject:Date:From; b=TLMD40PqUJDqTcSOJD9S/KmlhqIKkHMlFKPhZX+1a+1tklDs3cBbufpibGXluJqwC BQuABy4e8pLzwYEIKXcl2MYbOf0FzcUrutVYmSUkKW0nTazCdSPa/hJL9yQnh2rbEC LlcIqJr5I1+LTKudpC9DYkmFcVMiVJC/bn+Rpwn0= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WX55l641Jz112h; Sun, 28 Jul 2024 15:30:03 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WX55l5JqJz112f; Sun, 28 Jul 2024 15:30:03 +0000 (UTC) From: Giacomo Leidi Date: Sun, 28 Jul 2024 17:29:24 +0200 Message-ID: <1901209e4998ad29192b6f73b1e2828bc5d6f90e.1722180566.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a new record type, and serializers and deserializers for it in (gnu build accounts). Each instance of this record represents one line in either /etc/subuid or /etc/subgid. Since Shadow uses the same representation for both files, it should be ok if we do it as well. This commit adds also , a user facing representation of . It is supposed to be usable directly in OS configurations. * gnu/build/accounts.scm (subid-entry): New record; (write-subgid): add serializer for subgids; (write-subuid): add serializer for subuids; (read-subgid): add serializer for subgids; (read-subuid): add serializer for subuids. * gnu/system/accounts.scm (subid-range): New record. * test/accounts.scm: Test them. Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c --- gnu/build/accounts.scm | 37 ++++++++++++++++++++++++--- gnu/system/accounts.scm | 17 +++++++++++++ tests/accounts.scm | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index fa6f454b5e..ea8c69f205 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019, 2021, 2023 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -51,13 +52,23 @@ (define-module (gnu build accounts) group-entry-gid group-entry-members + subid-entry + subid-entry? + subid-entry-name + subid-entry-start + subid-entry-count + %password-lock-file write-group write-passwd write-shadow + write-subgid + write-subuid read-group read-passwd read-shadow + read-subgid + read-subuid %id-min %id-max @@ -68,11 +79,12 @@ (define-module (gnu build accounts) ;;; Commentary: ;;; -;;; This modules provides functionality equivalent to the C library's +;;; This module provides functionality equivalent to the C library's ;;; , , and routines, as well as a subset of the ;;; functionality of the Shadow command-line tools. It can parse and write -;;; /etc/passwd, /etc/shadow, and /etc/group. It can also take care of UID -;;; and GID allocation in a way similar to what 'useradd' does. +;;; /etc/passwd, /etc/shadow, /etc/group, /etc/subuid and /etc/subgid. It can +;;; also take care of UID and GID allocation in a way similar to what 'useradd' +;;; does. The same goes for sub UID and sub GID allocation. ;;; ;;; The benefit is twofold: less code is involved, and the ID allocation ;;; strategy and state preservation is made explicit. @@ -225,6 +237,17 @@ (define-database-entry ; (serialization list->comma-separated comma-separated->list) (default '()))) +(define-database-entry ; + subid-entry make-subid-entry + subid-entry? + (serialization #\: subid-entry->string string->subid-entry) + + (name subid-entry-name) + (start subid-entry-start + (serialization number->string string->number)) + (count subid-entry-count + (serialization number->string string->number))) + (define %password-lock-file ;; The password database lock file used by libc's 'lckpwdf'. Users should ;; grab this lock with 'with-file-lock' when they access the databases. @@ -265,6 +288,10 @@ (define write-shadow (database-writer "/etc/shadow" #o600 shadow-entry->string)) (define write-group (database-writer "/etc/group" #o644 group-entry->string)) +(define write-subuid + (database-writer "/etc/subuid" #o644 subid-entry->string)) +(define write-subgid + (database-writer "/etc/subgid" #o644 subid-entry->string)) (define (database-reader file string->entry) (lambda* (#:optional (file-or-port file)) @@ -287,6 +314,10 @@ (define read-shadow (database-reader "/etc/shadow" string->shadow-entry)) (define read-group (database-reader "/etc/group" string->group-entry)) +(define read-subuid + (database-reader "/etc/subuid" string->subid-entry)) +(define read-subgid + (database-reader "/etc/subgid" string->subid-entry)) ;;; diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 586cff1842..9a006c188d 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -39,6 +40,12 @@ (define-module (gnu system accounts) user-group-id user-group-system? + subid-range + subid-range? + subid-range-name + subid-range-start + subid-range-count + sexp->user-account sexp->user-group @@ -85,6 +92,16 @@ (define-record-type* (system? user-group-system? ; Boolean (default #f))) +(define-record-type* + subid-range make-subid-range + subid-range? + (name subid-range-name) + (start subid-range-start (default #f)) ; number + (count subid-range-count ; number + ; from find_new_sub_gids.c and + ; find_new_sub_uids.c + (default 65536))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 78136390bb..4944c22f49 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -41,6 +42,16 @@ (define %shadow-sample charlie:" (crypt "hey!" "$6$abc") ":17169:::::: nobody:!:0::::::\n")) +(define %subuid-sample + "\ +root:100000:300 +ada:100300:300\n") + +(define %subgid-sample + "\ +root:100000:600 +ada:100600:300\n") + (test-begin "accounts") @@ -135,6 +146,50 @@ (define %shadow-sample read-shadow) port)))) +(test-equal "write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (list (subid-entry + (name "root") + (start 100000) + (count 300)) + (subid-entry + (name "ada") + (start 100300) + (count 300))) + port)))) + +(test-equal "read-subuid + write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (call-with-input-string %subuid-sample + read-subuid) + port)))) + +(test-equal "write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (list (subid-entry + (name "root") + (start 100000) + (count 600)) + (subid-entry + (name "ada") + (start 100600) + (count 300))) + port)))) + +(test-equal "read-subgid + write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (call-with-input-string %subgid-sample + read-subgid) + port)))) + (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) base-commit: 8c6e724686ac37ff7955b97d9bfd03176b14d82a -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH 3/3] system: Add /etc/subuid and /etc/subgid support. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: pelzflorian@pelzflorian.de, ludo@gnu.org, matt@excalamus.com, maxim.cournoyer@gmail.com, guix-patches@gnu.org Resent-Date: Sun, 28 Jul 2024 15:31:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi , Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Matthew Trzcinski , Maxim Cournoyer X-Debbugs-Original-Xcc: Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Matthew Trzcinski , Maxim Cournoyer Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172218062815480 (code B ref 72337); Sun, 28 Jul 2024 15:31:03 +0000 Received: (at 72337) by debbugs.gnu.org; 28 Jul 2024 15:30:28 +0000 Received: from localhost ([127.0.0.1]:44240 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5qs-00041a-W0 for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:30:28 -0400 Received: from confino.investici.org ([93.190.126.19]:56797) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5qp-00041R-Q5 for 72337@debbugs.gnu.org; Sun, 28 Jul 2024 11:30:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1722180604; bh=oLTegUcVJfuhvYpKCRVt4khbkZ45x/yMeGCr8B/bx3A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VuxE4p9iV45vsTYnZWBM/5msezNOs15+UUep3psLz/WA/JKSOd5Kqt3VUIneFnNjJ NP0+9BaybKBMH223BNYuvGLsPylGo7cRpA3iFZoNNZhHrkqiWzf1XiuQP/7raZ94ho 7DLE9MIAnDRN7BAWgvBCjJl1XimQlhfgV+2acDSg= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WX55m3Pzwz113C; Sun, 28 Jul 2024 15:30:04 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WX55m2VWDz112f; Sun, 28 Jul 2024 15:30:04 +0000 (UTC) From: Giacomo Leidi Date: Sun, 28 Jul 2024 17:29:26 +0200 Message-ID: <6b97096800ebf51a666ab2ee93fd2fdec3c2c65c.1722180566.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <1901209e4998ad29192b6f73b1e2828bc5d6f90e.1722180566.git.goodoldpaul@autistici.org> References: <1901209e4998ad29192b6f73b1e2828bc5d6f90e.1722180566.git.goodoldpaul@autistici.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a Guix System service to handle allocation of subuid and subgid requests. Users that don't care can just add themselves as a subid-range and don't need to specify anything but their user name. Users that care about specific ranges, such as possibly LXD, can specify a start and a count. * doc/guix.texi: Document the new service. * gnu/build/activation.scm (activate-subuids+subgids): New variable. * gnu/local.mk: Add gnu/tests/shadow.scm. * gnu/system/accounts.scm (sexp->subid-range): New variable. * gnu/system/shadow.scm (%root-subid): New variable; (subids-configuration): new record; (subid-range->gexp): new variable; (assert-valid-subids): new variable; (delete-duplicate-ranges): new variable; (subids-activation): new variable; (subids-extension): new record; (append-subid-ranges): new variable; (subids-extension-merge): new variable; (subids-service-type): new variable. * gnu/tests/shadow.scm (subids): New system test. Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 --- doc/guix.texi | 171 ++++++++++++++++++++++++++++++++ gnu/build/activation.scm | 19 ++++ gnu/local.mk | 1 + gnu/system/accounts.scm | 10 ++ gnu/system/shadow.scm | 207 ++++++++++++++++++++++++++++++++++++++- gnu/tests/shadow.scm | 128 ++++++++++++++++++++++++ 6 files changed, 534 insertions(+), 2 deletions(-) create mode 100644 gnu/tests/shadow.scm diff --git a/doc/guix.texi b/doc/guix.texi index 9ba96af459..d0b2a5284c 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -41582,6 +41582,177 @@ Miscellaneous Services @end deftp +@c %end of fragment + +@cindex Subids +@subsubheading Subid Service + +The @code{(gnu system shadow)} module exposes the +@code{subids-service-type}, its configuration record +@code{subids-configuration} and its extension record +@code{subids-extension}. + +With @code{subids-service-type}, subuids and subgids ranges can be reserved for +users that desire so: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Users (definitely other services), usually, are supposed to extend the service +instead of adding subids directly to @code{subids-configuration}, unless the +want to change the default behavior for root. With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, possibly +starting at the minimum possible subid. Otherwise the root subuids and subgids +ranges are fitted wherever possible. + +The above configuration will yield the following: + +@example +# cat /etc/subgid +root:100000:65536 +alice:165536:65536 +# cat /etc/subuid +root:100000:700 +bob:100700:65536 +alice:166236:65536 +@end example + +@c %start of fragment + +@deftp {Data Type} subids-configuration + +With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, possibly +starting at the minimum possible subid. To disable the default behavior and +provide your own definition for the root subid ranges you can set to @code{#f} +the @code{add-root?} field: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (service subids-service-type + (subids-configuration + (add-root? #f) + (subgids + (subid-range (name "root") + (start 120000) + (count 100))) + (subuids + (subid-range (name "root") + (start 120000) + (count 100))))) + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Available @code{subids-configuration} fields are: + +@table @asis +@item @code{add-root?} (default: @code{#t}) (type: boolean) +Whether to automatically configure subuids and subgids for root. + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subgid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subuid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subids-extension + +Available @code{subids-extension} fields are: + +@table @asis + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subgids}. Entries with the same name are deduplicated +upon merging. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subuids}. Entries with the same name are deduplicated +upon merging. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subid-range + +The @code{subid-range} record is defined at @code{(gnu system accounts)}. +Available fields are: + +@table @asis + +@item @code{name} (type: string) +The name of the user or group that will own this range. + +@item @code{start} (default: @code{#f}) (type: integer) +The first requested subid. When false the first available subid with enough +contiguous subids will be assigned. + +@item @code{count} (default: @code{#f}) (type: integer) +The number of total allocated subids. When #f the default of 65536 will be +assumed . + +@end table + +@end deftp + @c %end of fragment @node Setuid Programs diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index d8c0cd22a3..943d72694f 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -9,6 +9,7 @@ ;;; Copyright © 2020 Christine Lemmer-Webber ;;; Copyright © 2021 Brice Waegeneire ;;; Copyright © 2024 Nicolas Graves +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -39,6 +40,7 @@ (define-module (gnu build activation) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) #:export (activate-users+groups + activate-subuids+subgids activate-user-home activate-etc activate-setuid-programs @@ -202,6 +204,23 @@ (define (activate-users+groups users groups) (chmod directory #o555)) (duplicates (map user-account-home-directory system-accounts)))) +(define (activate-subuids+subgids subuids subgids) + "Make sure SUBUIDS (a list of subid range records) and SUBGIDS (a list of +subid range records) are all available." + + ;; Take same lock as Shadow while we read + ;; and write the databases. This ensures there's no race condition with + ;; other tools that might be accessing it at the same time. + (with-file-lock "/etc/subgid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subgid subgid))) + + (with-file-lock "/etc/subuid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subuid subuid)))) + (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless they already exist." diff --git a/gnu/local.mk b/gnu/local.mk index ef1e82eb04..3019747328 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -835,6 +835,7 @@ GNU_SYSTEM_MODULES = \ %D%/tests/samba.scm \ %D%/tests/security.scm \ %D%/tests/security-token.scm \ + %D%/tests/shadow.scm \ %D%/tests/singularity.scm \ %D%/tests/ssh.scm \ %D%/tests/telephony.scm \ diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 1b88ca301f..f63d7f96bd 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -51,6 +51,7 @@ (define-module (gnu system accounts) sexp->user-account sexp->user-group + sexp->subid-range default-shell)) @@ -159,3 +160,12 @@ (define (sexp->user-account sexp) (create-home-directory? create-home-directory?) (shell shell) (password password) (system? system?))))) + +(define (sexp->subid-range sexp) + "Take SEXP, a tuple as returned by 'subid-range->gexp', and turn it into a +subid-range record." + (match sexp + ((name start count) + (subid-range (name name) + (start start) + (count count))))) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index d9f13271d8..84b5de660b 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen ;;; Copyright © 2020, 2023 Efraim Flashner ;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -77,7 +78,20 @@ (define-module (gnu system shadow) %base-user-accounts account-service-type - account-service)) + account-service + + subids-configuration + subids-configuration? + subids-configuration-add-root? + subids-configuration-subgids + subids-configuration-subuids + + subids-extension + subids-extension? + subids-extension-subgids + subids-extension-subuids + + subids-service-type)) ;;; Commentary: ;;; @@ -380,7 +394,7 @@ (define (assert-valid-users/groups users groups) ;;; -;;; Service. +;;; Accounts Service. ;;; (define (user-group->gexp group) @@ -521,4 +535,193 @@ (define (account-service accounts+groups skeletons) (service account-service-type (append skeletons accounts+groups))) + +;;; +;;; Subids Service. +;;; + +(define %sub-id-min + (@@ (gnu build accounts) %sub-id-min)) +(define %sub-id-max + (@@ (gnu build accounts) %sub-id-max)) +(define %sub-id-count + (@@ (gnu build accounts) %sub-id-count)) + +(define* (%root-subid #:optional (start %sub-id-min) (count %sub-id-count)) + (subid-range + (name "root") + (start start) + (count count))) + +(define-record-type* + subids-configuration make-subids-configuration + subids-configuration? + this-subids-configuration + + (add-root? subids-configuration-add-root? ; boolean + (default #t)) + (subgids subids-configuration-subgids ; list of + (default '())) + (subuids subids-configuration-subuids ; list of + (default '()))) + +(define (subid-range->gexp range) + "Turn RANGE, a object, into a list-valued gexp suitable for +'activate-subuids+subgids'." + (define count (subid-range-count range)) + #~`(#$(subid-range-name range) + #$(subid-range-start range) + #$(if (and (number? count) + (> count 0)) + count + %sub-id-count))) + +(define (assert-valid-subids ranges) + (cond ((>= (fold + 0 (map subid-range-count ranges)) + (- %sub-id-max %sub-id-min -1)) + (raise + (string-append + "The configured ranges are more than the " + (- %sub-id-max %sub-id-min -1) " max allowed."))) + ((any (lambda (r) + (define start (subid-range-start r)) + (and start + (< start %sub-id-min))) + ranges) + (raise + (string-append + "One subid-range starts before the minimum allowed sub id " + %sub-id-min "."))) + ((any (lambda (r) + (define end (subid-range-end r)) + (and end + (> end %sub-id-max))) + ranges) + (raise + (string-append + "One subid-range ends after the maximum allowed sub id " + %sub-id-max "."))) + ((any (compose null? subid-range-name) + ranges) + (raise + "One subid-range has a null name.")) + ((any (compose string-null? subid-range-name) + ranges) + (raise + "One subid-range has a name equal to the empty string.")) + (else #t))) + +(define (delete-duplicate-ranges ranges) + (delete-duplicates ranges + (lambda args + (apply string=? (map subid-range-name ranges))))) + +(define (subids-activation config) + "Return a gexp that activates SUBUIDS+SUBGIDS, a list of +objects." + (define (add-root-when-missing ranges) + (define sorted-ranges + (sort-list ranges subid-range-less)) + (define root-missing? + (not + (find (lambda (r) + (string=? "root" + (subid-range-name r))) + sorted-ranges))) + (define first-start + (and (> (length sorted-ranges) 0) + (subid-range-start (first sorted-ranges)))) + (define first-has-start? + (number? first-start)) + (define root-start + (if first-has-start? + (and + (> first-start %sub-id-min) + %sub-id-min) + %sub-id-min)) + (define root-count + (if first-has-start? + (- first-start %sub-id-min) + %sub-id-count)) + (if (and root-missing? + (subids-configuration-add-root? config)) + (append (list (%root-subid root-start root-count)) + sorted-ranges) + sorted-ranges)) + + (define subuids + (delete-duplicate-ranges (subids-configuration-subuids config))) + + (define subuids-specs + (map subid-range->gexp (add-root-when-missing subuids))) + + (define subgids + (delete-duplicate-ranges (subids-configuration-subgids config))) + + (define subgids-specs + (map subid-range->gexp (add-root-when-missing subgids))) + + (assert-valid-subids subgids) + (assert-valid-subids subuids) + + ;; Add subuids and subgids. + (with-imported-modules (source-module-closure '((gnu system accounts))) + #~(begin + (use-modules (gnu system accounts)) + + (activate-subuids+subgids (map sexp->subid-range (list #$@subuids-specs)) + (map sexp->subid-range (list #$@subgids-specs)))))) + +(define-record-type* + subids-extension make-subids-extension + subids-extension? + this-subids-extension + + (subgids subids-extension-subgids ; list of + (default '())) + (subuids subids-extension-subuids ; list of + (default '()))) + +(define append-subid-ranges + (lambda args + (delete-duplicate-ranges + (apply append args)))) + +(define (subids-extension-merge a b) + (subids-extension + (subgids (append-subid-ranges + (subids-extension-subgids a) + (subids-extension-subgids b))) + (subuids (append-subid-ranges + (subids-extension-subuids a) + (subids-extension-subuids b))))) + +(define subids-service-type + (service-type (name 'subids) + ;; Concatenate lists. + (compose (lambda (args) + (fold subids-extension-merge + (subids-extension) + args))) + (extend + (lambda (config extension) + (subids-configuration + (inherit config) + (subgids + (append-subid-ranges + (subids-configuration-subgids config) + (subids-extension-subgids extension))) + (subuids + (append-subid-ranges + (subids-configuration-subuids config) + (subids-extension-subuids extension)))))) + (extensions + (list (service-extension activation-service-type + subids-activation))) + (default-value + (subids-configuration)) + (description + "Ensure the specified sub UIDs and sub GIDs exist in +/etc/subuid and /etc/subgid."))) + ;;; shadow.scm ends here diff --git a/gnu/tests/shadow.scm b/gnu/tests/shadow.scm new file mode 100644 index 0000000000..1e755b5438 --- /dev/null +++ b/gnu/tests/shadow.scm @@ -0,0 +1,128 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Giacomo Leidi +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu tests shadow) + #:use-module (gnu packages base) + #:use-module (gnu tests) + #:use-module (gnu services) + #:use-module (gnu system) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (gnu system vm) + #:use-module (guix gexp) + #:export (%test-subids)) + + +(define %subids-os + (simple-operating-system + (simple-service + 'simple-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range + (name "alice")) + (subid-range + (name "bob") + (start 100700)))) + (subuids + (list + (subid-range + (name "alice")))))))) + +(define (run-subids-test) + "Run IMAGE as an OCI backed Shepherd service, inside OS." + + (define os + (marionette-operating-system + (operating-system-with-gc-roots + %subids-os + (list)) + #:imported-modules '((gnu services herd) + (guix combinators)))) + + (define vm + (virtual-machine + (operating-system os) + (volatile? #f) + (memory-size 1024) + (disk-image-size (* 3000 (expt 2 20))) + (port-forwardings '()))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) (srfi srfi-64) + (gnu build marionette)) + + (define marionette + ;; Relax timeout to accommodate older systems and + ;; allow for pulling the image. + (make-marionette (list #$vm) #:timeout 60)) + + (test-runner-current (system-test-runner #$output)) + (test-begin "subids") + + (test-equal "/etc/subid and /etc/subgid are created and their content is sound" + '("root:100000:700\nbob:100700:65536\nalice:166236:65536" + "root:100000:65536\nalice:165536:65536") + (marionette-eval + `(begin + (use-modules (ice-9 popen) + (ice-9 match) + (ice-9 rdelim)) + + (define (read-lines file-or-port) + (define (loop-lines port) + (let loop ((lines '())) + (match (read-line port) + ((? eof-object?) + (reverse lines)) + (line + (loop (cons line lines)))))) + + (if (port? file-or-port) + (loop-lines file-or-port) + (call-with-input-file file-or-port + loop-lines))) + + (define slurp + (lambda args + (let* ((port (apply open-pipe* OPEN_READ args)) + (output (read-lines port)) + (status (close-pipe port))) + output))) + (let* ((response1 (slurp + ,(string-append #$coreutils "/bin/cat") + "/etc/subgid")) + (response2 (slurp + ,(string-append #$coreutils "/bin/cat") + "/etc/subuid"))) + (list (string-join response1 "\n") (string-join response2 "\n")))) + marionette)) + + (test-end)))) + + (gexp->derivation "subids-test" test)) + +(define %test-subids + (system-test + (name "subids") + (description "Test sub UIDs and sub GIDs provisioning service.") + (value (run-subids-test)))) -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support References: In-Reply-To: Resent-From: paul Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 19 Aug 2024 21:33:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17241031784661 (code B ref 72337); Mon, 19 Aug 2024 21:33:01 +0000 Received: (at 72337) by debbugs.gnu.org; 19 Aug 2024 21:32:58 +0000 Received: from localhost ([127.0.0.1]:59365 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sg9zm-0001D6-4j for submit@debbugs.gnu.org; Mon, 19 Aug 2024 17:32:58 -0400 Received: from confino.investici.org ([93.190.126.19]:43603) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sg9zj-0001Cs-Eg for 72337@debbugs.gnu.org; Mon, 19 Aug 2024 17:32:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724103123; bh=7YtydEw4Pw6zPKt7btiT6ODOvSAP3RSrOEL3eOZw1VI=; h=Date:To:From:Subject:From; b=EymmuWq2Y4PsyHGB2zGXq7vQwM2XfTom7YVRX7cMBZvTqOBSelFwuIdNZOLsRWvM+ jLNIjpccAFCkgdYDVb9DjjYUBMFKU+U9UY/yJx8TuhT49greQ7GogbIwdU6NgJEguL VIyTmQK2uZVMK3KaqjqrBlV7Hic/WEkbrEMDUY0Q= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4Wnm5H3xFpz10xG for <72337@debbugs.gnu.org>; Mon, 19 Aug 2024 21:32:03 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4Wnm5H3YRNz10wR for <72337@debbugs.gnu.org>; Mon, 19 Aug 2024 21:32:03 +0000 (UTC) Message-ID: <230d9bce-25b6-40ab-fa67-14053ba0ef21@autistici.org> Date: Mon, 19 Aug 2024 23:32:02 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 Content-Language: en-US From: paul Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Score: 1.8 (+) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Dear Guixers, I'm sending a patchset rebased on current master. I can confirm tests still work. Thank you for your work, Content analysis details: (1.8 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [93.190.126.19 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 2.5 FAKE_REPLY_A1 No description available. X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 0.8 (/) Dear Guixers, I'm sending a patchset rebased on current master. I can confirm tests still work. Thank you for your work, giacomo From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v2 2/3] account: Add /etc/subid and /etc/subgid allocation logic. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 19 Aug 2024 22:10:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17241053438382 (code B ref 72337); Mon, 19 Aug 2024 22:10:01 +0000 Received: (at 72337) by debbugs.gnu.org; 19 Aug 2024 22:09:03 +0000 Received: from localhost ([127.0.0.1]:59377 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgAYf-0002Ao-FV for submit@debbugs.gnu.org; Mon, 19 Aug 2024 18:09:02 -0400 Received: from confino.investici.org ([93.190.126.19]:39659) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgAYb-0002AX-Se for 72337@debbugs.gnu.org; Mon, 19 Aug 2024 18:08:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724105293; bh=fnoegWIFjnuS7mQqES8XFN0q6+mWfKZDt6xrwN84Cvc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZmQYPU1JvQ8oWWtjupa4d79b0E/J48IzEmEDZ3UVOJsl3FTwOUJS1fDEIgwBtrmSD 32MGvek1x1dJb2i0k6gO3qUA35fKwuVY/ig3J1D6cg3V8K9rWbQbRAZgQAopxC20G5 xkarEuelP1CXIS06a9L4odeu7VeIJpJ8KvX7Lxq8= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4Wnmv16cYpz10xV; Mon, 19 Aug 2024 22:08:13 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4Wnmv15tntz10xJ; Mon, 19 Aug 2024 22:08:13 +0000 (UTC) From: Giacomo Leidi Date: Tue, 20 Aug 2024 00:08:03 +0200 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) * gnu/build/accounts.scm (list-set): New variable; (%sub-id-min): new variable; (%sub-id-max): new variable; (%sub-id-count): new variable; (sub-id?): new variable; (subid-range-fits?): new variable; (subid-range-fits-between?): new variable; (insert-subid-range): new variable; (reserve-subids): new variable; (range->entry): new variable; (entry->range): new variable; (allocate-subids): new variable; (subuid+subgid-databases): new variable. * gnu/system/accounts.scm (subid-range-end): New variable; (subid-range-has-start?): new variable; (subid-range-less): new variable. * test/accounts.scm: Test them. Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d --- gnu/build/accounts.scm | 229 +++++++++++++++++++++++++++++++++++++++- gnu/system/accounts.scm | 30 ++++++ tests/accounts.scm | 108 +++++++++++++++++++ 3 files changed, 366 insertions(+), 1 deletion(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index ea8c69f205..3cbbacfaee 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -74,8 +74,12 @@ (define-module (gnu build accounts) %id-max %system-id-min %system-id-max + %sub-id-min + %sub-id-max + %sub-id-count - user+group-databases)) + user+group-databases + subuid+subgid-databases)) ;;; Commentary: ;;; @@ -91,6 +95,18 @@ (define-module (gnu build accounts) ;;; ;;; Code: + +;;; +;;; General utilities. +;;; + +(define (list-set lst el k) + (if (>= k (length lst)) + `(,@lst ,el) + `(,@(list-head lst k) + ,el + ,@(list-tail lst k)))) + ;;; ;;; Machinery to define user and group databases. @@ -342,6 +358,12 @@ (define %id-max 60000) (define %system-id-min 100) (define %system-id-max 999) +;; According to Shadow's libmisc/find_new_sub_uids.c and +;; libmisc/find_new_sub_gids.c. +(define %sub-id-min 100000) +(define %sub-id-max 600100000) +(define %sub-id-count 65536) + (define (system-id? id) (and (> id %system-id-min) (<= id %system-id-max))) @@ -350,6 +372,10 @@ (define (user-id? id) (and (>= id %id-min) (< id %id-max))) +(define (sub-id? id) + (and (>= id %sub-id-min) + (< id %sub-id-max))) + (define* (allocate-id assignment #:key system?) "Return two values: a newly allocated ID, and an updated record based on ASSIGNMENT. If SYSTEM? is true, return a system ID." @@ -405,6 +431,156 @@ (define* (reserve-ids allocation ids #:key (skip? #t)) (allocation-ids allocation) ids)))) +(define (subid-range-fits? r interval-start interval-end) + (and (<= interval-start + (subid-range-start r)) + (<= (subid-range-end r) + interval-end))) + +(define (subid-range-fits-between? r a b) + (subid-range-fits? r + (+ (subid-range-start a) 1) + (- (subid-range-end b) 1))) + +(define (insert-subid-range range lst) + (define* (actualize r #:key (start %sub-id-min)) + (if (subid-range-has-start? r) + r + (subid-range + (inherit r) + (start start)))) + (define lst-length (length lst)) + (define range-name (subid-range-name range)) + (define range-start (subid-range-start range)) + (define has-start? (subid-range-has-start? range)) + (define range-end (subid-range-end range)) + + (when has-start? + (unless (and (sub-id? range-start) + (sub-id? range-end)) + (raise + (string-append "Subid range of " range-name + " from " range-start " to " range-end + " spans over illegal subids. Max allowed is " + %sub-id-max ", min is " %sub-id-min ".")))) + + (if (<= lst-length 1) + (if (= lst-length 0) + (list (actualize range)) + (if (subid-range-less range (first lst)) + (list-set lst (actualize range) 0) + (list-set lst + (actualize + range + #:start (and (subid-range-has-start? (first lst)) + (+ (subid-range-end (first lst)) 1))) + 1))) + (let loop ((i 0)) + (define next-i (+ i 1)) + (define ith-range + (list-ref lst i)) + (define ith-start + (subid-range-start ith-range)) + (define ith-has-start? + (subid-range-has-start? ith-range)) + (define ith-name + (subid-range-name ith-range)) + + (if (and + (= next-i lst-length) + (subid-range-less ith-range range)) + (let ((actual-range + (actualize + range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))))) + (list-set lst + actual-range + lst-length)) + (let* ((next-range + (list-ref lst next-i)) + (next-has-start? + (subid-range-has-start? next-range))) + (cond + + ((and has-start? (= range-start ith-start)) + (raise + (string-append "Subid range of " range-name + " has same start " + (number->string range-start) + " of the one " + "from " ith-name "."))) + + ((and (= i 0) + (subid-range-less range ith-range) + (or + (and + has-start? ith-has-start? + (subid-range-fits? (actualize range) + %sub-id-min + (- (subid-range-start + (actualize ith-range)) + 1))) + (not (and has-start? ith-has-start?)))) + (list-set lst (actualize range) 0)) + + ((subid-range-less range ith-range) + (raise + (string-append "Subid range of " range-name + " overlaps with the one of " + ith-name "."))) + + ((and (subid-range-less ith-range range) + (subid-range-less range next-range)) + (if (or (not (and has-start? + ith-has-start? + next-has-start?)) + + (and has-start? + ith-has-start? + next-has-start? + (subid-range-fits-between? range + ith-range + next-range))) + (list-set lst + (actualize range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))) + next-i) + (if (>= i lst-length) + (if (and (subid-range-less next-range range) + (let ((actual-next + (actualize next-range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))))) + (or (not (subid-range-has-start? actual-next)) + (subid-range-fits? + (actualize range + #:start (and next-has-start? + (+ (subid-range-end next-range) 1))) + (+ (subid-range-end actual-next) 1) + %sub-id-max)))) + (list-set lst range lst-length) + (raise + (string-append "Couldn't fit " range-name ", reached end of list."))) + (loop next-i)))) + + ((or + (not has-start?) + (subid-range-less next-range range)) + (loop next-i)) + + (else + (raise (string-append "Couldn't fit " range-name ", this should never happen."))))))))) + +(define* (reserve-subids allocation ranges) + "Mark the subid ranges listed in RANGES as reserved in ALLOCATION. +ALLOCATION is supposed to be sorted by SUBID-RANGE-LESS." + (fold insert-subid-range + allocation + (sort-list ranges + subid-range-less))) + (define (allocated? allocation id) "Return true if ID is already allocated as part of ALLOCATION." (->bool (vhash-assv id (allocation-ids allocation)))) @@ -540,6 +716,31 @@ (define* (allocate-passwd users groups #:optional (current-passwd '())) uids users))) +(define (range->entry range) + (subid-entry + (name (subid-range-name range)) + (start (subid-range-start range)) + (count (subid-range-count range)))) + +(define (entry->range entry) + (subid-range + (name (subid-entry-name entry)) + (start (subid-entry-start entry)) + (count (subid-entry-count entry)))) + +(define* (allocate-subids ranges #:optional (current-ranges '())) + "Return a list of subids entries for RANGES, a list of . Members +for each group are taken from MEMBERS, a vhash that maps ranges names to member +names. IDs found in CURRENT-RANGES, a list of subid entries, are reused." + (define subids + ;; Mark all the currently used IDs and the explicitly requested IDs as + ;; reserved. + (reserve-subids (reserve-subids (list) + current-ranges) + ranges)) + + (map range->entry subids)) + (define* (days-since-epoch #:optional (current-time current-time)) "Return the number of days elapsed since the 1st of January, 1970." (let* ((now (current-time time-utc)) @@ -615,3 +816,29 @@ (define* (user+group-databases users groups #:current-time current-time)) (values group-entries passwd-entries shadow-entries)) + +(define* (subuid+subgid-databases subuids subgids + #:key + (current-subuids + (map entry->range + (empty-if-not-found read-subuid))) + (current-subgids + (map entry->range + (empty-if-not-found read-subgid)))) + "Return two values: the list of subgid entries, and the list of subuid entries +corresponding to SUBUIDS and SUBGIDS. +Preserve stateful bits from CURRENT-SUBUIDS and CURRENT-SUBGIDS." + + (define (range-eqv? a b) + (string=? (subid-range-name a) + (subid-range-name b))) + + (define subuid-entries + (allocate-subids + (lset-difference range-eqv? subuids current-subuids) current-subuids)) + + (define subgid-entries + (allocate-subids + (lset-difference range-eqv? subgids current-subgids) current-subgids)) + + (values subuid-entries subgid-entries)) diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 9a006c188d..1b88ca301f 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -45,6 +45,9 @@ (define-module (gnu system accounts) subid-range-name subid-range-start subid-range-count + subid-range-end + subid-range-has-start? + subid-range-less sexp->user-account sexp->user-group @@ -102,6 +105,33 @@ (define-record-type* ; find_new_sub_uids.c (default 65536))) +(define (subid-range-end range) + "Returns the last subid referenced in RANGE." + (and + (subid-range-has-start? range) + (+ (subid-range-start range) + (subid-range-count range) + -1))) + +(define (subid-range-has-start? range) + "Returns #t when RANGE's start is a number." + (number? (subid-range-start range))) + +(define (subid-range-less a b) + "Returns #t when subid range A either starts before, or is more specific +than B. When it is not possible to determine whether a range is more specific +w.r.t. another range their names are compared alphabetically." + (define start-a (subid-range-start a)) + (define start-b (subid-range-start b)) + (cond ((and (not start-a) (not start-b)) + (string< (subid-range-name a) + (subid-range-name b))) + ((and start-a start-b) + (< start-a start-b)) + (else + (and start-a + (not start-b))))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 4944c22f49..2fbebfaf56 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -193,6 +193,7 @@ (define %subgid-sample (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) +(define allocate-subids (@@ (gnu build accounts) allocate-subids)) (test-equal "allocate-groups" ;; Allocate GIDs in a stateless fashion. @@ -257,6 +258,69 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (list (group-entry (name "d") (gid (- %id-max 2)))))) +(test-equal "allocate-subids" + ;; Allocate sub IDs in a stateless fashion. + (list (subid-entry (name "root") (start %sub-id-min) (count 100)) + (subid-entry (name "t") (start 100100) (count 899)) + (subid-entry (name "x") (start 100999) (count 200))) + (allocate-subids (list + (subid-range (name "x") (count 200)) + (subid-range (name "t") (count 899))) + (list (subid-range (name "root") (count 100))))) + +(test-equal "allocate-subids with requested IDs ranges" + ;; Make sure the requested sub ID for "t" and "x" are honored. + (list (subid-entry (name "x") (start %sub-id-min) (count 200)) + (subid-entry (name "t") (start 1000000) (count 899)) + (subid-entry (name "l") (start 1000899) (count 100)) + (subid-entry (name "root") (start 1000999) (count 100))) + (allocate-subids (list + (subid-range (name "root") (count 100)) + (subid-range (name "l") (count 100))) + (list + (subid-range (name "x") (start %sub-id-min) (count 200)) + (subid-range (name "t") (start 1000000) (count 899))))) + +(test-equal "allocate-subids with interleaving" + ;; Make sure the requested sub ID for "m" is honored. + (list (subid-entry (name "x") (start %sub-id-min) (count 200)) + (subid-entry (name "t") (start 1000000) (count 899)) + (subid-entry (name "i") (start 1100000) (count 1)) + (subid-entry (name "root") (start 1100001) (count 100)) + (subid-entry (name "m") (start 1200000) (count 27))) + (allocate-subids (list (subid-range (name "m") (start 1200000) (count 27))) + (list + (subid-range (name "x") (start %sub-id-min) (count 200)) + (subid-range (name "t") (start 1000000) (count 899)) + (subid-range (name "i") (start 1100000) (count 1)) + (subid-range (name "root") (count 100))))) + +(let ((inputs+currents + (list + ;; Try impossible before + (list + (list (subid-range (name "m") (start 100100) (count 27))) + (list + (subid-range (name "x") (start %sub-id-min) (count 150)))) + ;; Try impossible after + (list + (list (subid-range (name "m") (start %sub-id-min) (count 30))) + (list + (subid-range (name "x") (start (+ 29 %sub-id-min)) (count 150)))) + ;; Try impossible between + (list + (list (subid-range (name "m") (start 100200) (count 500))) + (list + (subid-range (name "root") (start %sub-id-min) (count 100)) + (subid-range (name "x") (start (+ %sub-id-min 500)) (count 100))))))) + (test-error "allocate-subids with interleaving, impossible interleaving" + "error" + ;; Make sure it's impossible to explicitly request impossible allocations + (for-each + (lambda (lst) + (allocate-subids (first lst) (second lst))) + inputs+currents))) + (test-equal "allocate-passwd" ;; Allocate UIDs in a stateless fashion. (list (password-entry (name "alice") (uid %id-min) (gid 1000) @@ -376,4 +440,48 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (make-time type 0 (* 24 3600 100))))) list)) +(test-equal "subuid+subgid-databases" + ;; The whole process. + (list (list (subid-entry (name "root") + (start %sub-id-min) + (count 100)) + (subid-entry (name "alice") + (start (+ %sub-id-min 100)) + (count 200)) + (subid-entry (name "bob") + (start (+ %sub-id-min 100 200)) + (count 200))) + (list + (subid-entry (name "root") + (start %sub-id-min) + (count 200)) + (subid-entry (name "alice") + (start (+ %sub-id-min 200)) + (count 400)) + (subid-entry (name "charlie") + (start (+ %sub-id-min 200 400)) + (count 300)))) + (call-with-values + (lambda () + (subuid+subgid-databases + (list (subid-range (name "root") + (start %sub-id-min) + (count 100)) + (subid-range (name "alice") + (start (+ %sub-id-min 100)) + (count 200)) + (subid-range (name "bob") + (count 200))) + (list + (subid-range (name "alice") + (count 400)) + (subid-range (name "charlie") + (count 300))) + #:current-subgids + (list (subid-range (name "root") + (start %sub-id-min) + (count 200))) + #:current-subuids '())) + list)) + (test-end "accounts") -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v2 3/3] system: Add /etc/subuid and /etc/subgid support. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: pelzflorian@pelzflorian.de, ludo@gnu.org, matt@excalamus.com, maxim.cournoyer@gmail.com, guix-patches@gnu.org Resent-Date: Mon, 19 Aug 2024 22:10:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi , Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Matthew Trzcinski , Maxim Cournoyer X-Debbugs-Original-Xcc: Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Matthew Trzcinski , Maxim Cournoyer Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17241053448390 (code B ref 72337); Mon, 19 Aug 2024 22:10:02 +0000 Received: (at 72337) by debbugs.gnu.org; 19 Aug 2024 22:09:04 +0000 Received: from localhost ([127.0.0.1]:59379 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgAYg-0002B9-RA for submit@debbugs.gnu.org; Mon, 19 Aug 2024 18:09:04 -0400 Received: from confino.investici.org ([93.190.126.19]:47689) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgAYb-0002AY-Q9 for 72337@debbugs.gnu.org; Mon, 19 Aug 2024 18:09:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724105294; bh=ndEXKRd0APTpY5iqXi9enQX2zXapj+aOQRejvoIf0Ho=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LwIKOiGe0gVsrS7eRZIJJP+GAZMafXi+F4HhwtG160ENYC8ecdF48c306tIlKoCQV t9A2fxKWgWe+5tAND+icO7d7x4tSbkMJv3WlSM9qbS3v+wfIBcLZLzmFFuMRFm2jBL t/p566ZJR3lAfkAZ6rwfumr/tAfYGYOqstrxu8/c= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4Wnmv225WNz10xb; Mon, 19 Aug 2024 22:08:14 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4Wnmv211ydz10xJ; Mon, 19 Aug 2024 22:08:14 +0000 (UTC) From: Giacomo Leidi Date: Tue, 20 Aug 2024 00:08:04 +0200 Message-ID: <38d9e6a0d242dac361bb62ad6b48b7d0ac7901ae.1724105284.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a Guix System service to handle allocation of subuid and subgid requests. Users that don't care can just add themselves as a subid-range and don't need to specify anything but their user name. Users that care about specific ranges, such as possibly LXD, can specify a start and a count. * doc/guix.texi: Document the new service. * gnu/build/activation.scm (activate-subuids+subgids): New variable. * gnu/local.mk: Add gnu/tests/shadow.scm. * gnu/system/accounts.scm (sexp->subid-range): New variable. * gnu/system/shadow.scm (%root-subid): New variable; (subids-configuration): new record; (subid-range->gexp): new variable; (assert-valid-subids): new variable; (delete-duplicate-ranges): new variable; (subids-activation): new variable; (subids-extension): new record; (append-subid-ranges): new variable; (subids-extension-merge): new variable; (subids-service-type): new variable. * gnu/tests/shadow.scm (subids): New system test. Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 --- doc/guix.texi | 171 ++++++++++++++++++++++++++++++++ gnu/build/activation.scm | 19 ++++ gnu/local.mk | 1 + gnu/system/accounts.scm | 10 ++ gnu/system/shadow.scm | 207 ++++++++++++++++++++++++++++++++++++++- gnu/tests/shadow.scm | 128 ++++++++++++++++++++++++ 6 files changed, 534 insertions(+), 2 deletions(-) create mode 100644 gnu/tests/shadow.scm diff --git a/doc/guix.texi b/doc/guix.texi index 0e1e253b02..a799342769 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -41647,6 +41647,177 @@ Miscellaneous Services @end deftp +@c %end of fragment + +@cindex Subids +@subsubheading Subid Service + +The @code{(gnu system shadow)} module exposes the +@code{subids-service-type}, its configuration record +@code{subids-configuration} and its extension record +@code{subids-extension}. + +With @code{subids-service-type}, subuids and subgids ranges can be reserved for +users that desire so: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Users (definitely other services), usually, are supposed to extend the service +instead of adding subids directly to @code{subids-configuration}, unless the +want to change the default behavior for root. With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, possibly +starting at the minimum possible subid. Otherwise the root subuids and subgids +ranges are fitted wherever possible. + +The above configuration will yield the following: + +@example +# cat /etc/subgid +root:100000:65536 +alice:165536:65536 +# cat /etc/subuid +root:100000:700 +bob:100700:65536 +alice:166236:65536 +@end example + +@c %start of fragment + +@deftp {Data Type} subids-configuration + +With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, possibly +starting at the minimum possible subid. To disable the default behavior and +provide your own definition for the root subid ranges you can set to @code{#f} +the @code{add-root?} field: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (service subids-service-type + (subids-configuration + (add-root? #f) + (subgids + (subid-range (name "root") + (start 120000) + (count 100))) + (subuids + (subid-range (name "root") + (start 120000) + (count 100))))) + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Available @code{subids-configuration} fields are: + +@table @asis +@item @code{add-root?} (default: @code{#t}) (type: boolean) +Whether to automatically configure subuids and subgids for root. + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subgid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subuid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subids-extension + +Available @code{subids-extension} fields are: + +@table @asis + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subgids}. Entries with the same name are deduplicated +upon merging. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subuids}. Entries with the same name are deduplicated +upon merging. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subid-range + +The @code{subid-range} record is defined at @code{(gnu system accounts)}. +Available fields are: + +@table @asis + +@item @code{name} (type: string) +The name of the user or group that will own this range. + +@item @code{start} (default: @code{#f}) (type: integer) +The first requested subid. When false the first available subid with enough +contiguous subids will be assigned. + +@item @code{count} (default: @code{#f}) (type: integer) +The number of total allocated subids. When #f the default of 65536 will be +assumed . + +@end table + +@end deftp + @c %end of fragment @node Privileged Programs diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index a57ca78a86..91662fe0fd 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -10,6 +10,7 @@ ;;; Copyright © 2021 Brice Waegeneire ;;; Copyright © 2022 Tobias Geerinckx-Rice ;;; Copyright © 2024 Nicolas Graves +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -40,6 +41,7 @@ (define-module (gnu build activation) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) #:export (activate-users+groups + activate-subuids+subgids activate-user-home activate-etc activate-privileged-programs @@ -203,6 +205,23 @@ (define (activate-users+groups users groups) (chmod directory #o555)) (duplicates (map user-account-home-directory system-accounts)))) +(define (activate-subuids+subgids subuids subgids) + "Make sure SUBUIDS (a list of subid range records) and SUBGIDS (a list of +subid range records) are all available." + + ;; Take same lock as Shadow while we read + ;; and write the databases. This ensures there's no race condition with + ;; other tools that might be accessing it at the same time. + (with-file-lock "/etc/subgid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subgid subgid))) + + (with-file-lock "/etc/subuid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subuid subuid)))) + (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless they already exist." diff --git a/gnu/local.mk b/gnu/local.mk index 3b0a3858f7..88467e3d42 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -839,6 +839,7 @@ GNU_SYSTEM_MODULES = \ %D%/tests/samba.scm \ %D%/tests/security.scm \ %D%/tests/security-token.scm \ + %D%/tests/shadow.scm \ %D%/tests/singularity.scm \ %D%/tests/ssh.scm \ %D%/tests/telephony.scm \ diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 1b88ca301f..f63d7f96bd 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -51,6 +51,7 @@ (define-module (gnu system accounts) sexp->user-account sexp->user-group + sexp->subid-range default-shell)) @@ -159,3 +160,12 @@ (define (sexp->user-account sexp) (create-home-directory? create-home-directory?) (shell shell) (password password) (system? system?))))) + +(define (sexp->subid-range sexp) + "Take SEXP, a tuple as returned by 'subid-range->gexp', and turn it into a +subid-range record." + (match sexp + ((name start count) + (subid-range (name name) + (start start) + (count count))))) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index d9f13271d8..84b5de660b 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen ;;; Copyright © 2020, 2023 Efraim Flashner ;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -77,7 +78,20 @@ (define-module (gnu system shadow) %base-user-accounts account-service-type - account-service)) + account-service + + subids-configuration + subids-configuration? + subids-configuration-add-root? + subids-configuration-subgids + subids-configuration-subuids + + subids-extension + subids-extension? + subids-extension-subgids + subids-extension-subuids + + subids-service-type)) ;;; Commentary: ;;; @@ -380,7 +394,7 @@ (define (assert-valid-users/groups users groups) ;;; -;;; Service. +;;; Accounts Service. ;;; (define (user-group->gexp group) @@ -521,4 +535,193 @@ (define (account-service accounts+groups skeletons) (service account-service-type (append skeletons accounts+groups))) + +;;; +;;; Subids Service. +;;; + +(define %sub-id-min + (@@ (gnu build accounts) %sub-id-min)) +(define %sub-id-max + (@@ (gnu build accounts) %sub-id-max)) +(define %sub-id-count + (@@ (gnu build accounts) %sub-id-count)) + +(define* (%root-subid #:optional (start %sub-id-min) (count %sub-id-count)) + (subid-range + (name "root") + (start start) + (count count))) + +(define-record-type* + subids-configuration make-subids-configuration + subids-configuration? + this-subids-configuration + + (add-root? subids-configuration-add-root? ; boolean + (default #t)) + (subgids subids-configuration-subgids ; list of + (default '())) + (subuids subids-configuration-subuids ; list of + (default '()))) + +(define (subid-range->gexp range) + "Turn RANGE, a object, into a list-valued gexp suitable for +'activate-subuids+subgids'." + (define count (subid-range-count range)) + #~`(#$(subid-range-name range) + #$(subid-range-start range) + #$(if (and (number? count) + (> count 0)) + count + %sub-id-count))) + +(define (assert-valid-subids ranges) + (cond ((>= (fold + 0 (map subid-range-count ranges)) + (- %sub-id-max %sub-id-min -1)) + (raise + (string-append + "The configured ranges are more than the " + (- %sub-id-max %sub-id-min -1) " max allowed."))) + ((any (lambda (r) + (define start (subid-range-start r)) + (and start + (< start %sub-id-min))) + ranges) + (raise + (string-append + "One subid-range starts before the minimum allowed sub id " + %sub-id-min "."))) + ((any (lambda (r) + (define end (subid-range-end r)) + (and end + (> end %sub-id-max))) + ranges) + (raise + (string-append + "One subid-range ends after the maximum allowed sub id " + %sub-id-max "."))) + ((any (compose null? subid-range-name) + ranges) + (raise + "One subid-range has a null name.")) + ((any (compose string-null? subid-range-name) + ranges) + (raise + "One subid-range has a name equal to the empty string.")) + (else #t))) + +(define (delete-duplicate-ranges ranges) + (delete-duplicates ranges + (lambda args + (apply string=? (map subid-range-name ranges))))) + +(define (subids-activation config) + "Return a gexp that activates SUBUIDS+SUBGIDS, a list of +objects." + (define (add-root-when-missing ranges) + (define sorted-ranges + (sort-list ranges subid-range-less)) + (define root-missing? + (not + (find (lambda (r) + (string=? "root" + (subid-range-name r))) + sorted-ranges))) + (define first-start + (and (> (length sorted-ranges) 0) + (subid-range-start (first sorted-ranges)))) + (define first-has-start? + (number? first-start)) + (define root-start + (if first-has-start? + (and + (> first-start %sub-id-min) + %sub-id-min) + %sub-id-min)) + (define root-count + (if first-has-start? + (- first-start %sub-id-min) + %sub-id-count)) + (if (and root-missing? + (subids-configuration-add-root? config)) + (append (list (%root-subid root-start root-count)) + sorted-ranges) + sorted-ranges)) + + (define subuids + (delete-duplicate-ranges (subids-configuration-subuids config))) + + (define subuids-specs + (map subid-range->gexp (add-root-when-missing subuids))) + + (define subgids + (delete-duplicate-ranges (subids-configuration-subgids config))) + + (define subgids-specs + (map subid-range->gexp (add-root-when-missing subgids))) + + (assert-valid-subids subgids) + (assert-valid-subids subuids) + + ;; Add subuids and subgids. + (with-imported-modules (source-module-closure '((gnu system accounts))) + #~(begin + (use-modules (gnu system accounts)) + + (activate-subuids+subgids (map sexp->subid-range (list #$@subuids-specs)) + (map sexp->subid-range (list #$@subgids-specs)))))) + +(define-record-type* + subids-extension make-subids-extension + subids-extension? + this-subids-extension + + (subgids subids-extension-subgids ; list of + (default '())) + (subuids subids-extension-subuids ; list of + (default '()))) + +(define append-subid-ranges + (lambda args + (delete-duplicate-ranges + (apply append args)))) + +(define (subids-extension-merge a b) + (subids-extension + (subgids (append-subid-ranges + (subids-extension-subgids a) + (subids-extension-subgids b))) + (subuids (append-subid-ranges + (subids-extension-subuids a) + (subids-extension-subuids b))))) + +(define subids-service-type + (service-type (name 'subids) + ;; Concatenate lists. + (compose (lambda (args) + (fold subids-extension-merge + (subids-extension) + args))) + (extend + (lambda (config extension) + (subids-configuration + (inherit config) + (subgids + (append-subid-ranges + (subids-configuration-subgids config) + (subids-extension-subgids extension))) + (subuids + (append-subid-ranges + (subids-configuration-subuids config) + (subids-extension-subuids extension)))))) + (extensions + (list (service-extension activation-service-type + subids-activation))) + (default-value + (subids-configuration)) + (description + "Ensure the specified sub UIDs and sub GIDs exist in +/etc/subuid and /etc/subgid."))) + ;;; shadow.scm ends here diff --git a/gnu/tests/shadow.scm b/gnu/tests/shadow.scm new file mode 100644 index 0000000000..1e755b5438 --- /dev/null +++ b/gnu/tests/shadow.scm @@ -0,0 +1,128 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Giacomo Leidi +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu tests shadow) + #:use-module (gnu packages base) + #:use-module (gnu tests) + #:use-module (gnu services) + #:use-module (gnu system) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (gnu system vm) + #:use-module (guix gexp) + #:export (%test-subids)) + + +(define %subids-os + (simple-operating-system + (simple-service + 'simple-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range + (name "alice")) + (subid-range + (name "bob") + (start 100700)))) + (subuids + (list + (subid-range + (name "alice")))))))) + +(define (run-subids-test) + "Run IMAGE as an OCI backed Shepherd service, inside OS." + + (define os + (marionette-operating-system + (operating-system-with-gc-roots + %subids-os + (list)) + #:imported-modules '((gnu services herd) + (guix combinators)))) + + (define vm + (virtual-machine + (operating-system os) + (volatile? #f) + (memory-size 1024) + (disk-image-size (* 3000 (expt 2 20))) + (port-forwardings '()))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) (srfi srfi-64) + (gnu build marionette)) + + (define marionette + ;; Relax timeout to accommodate older systems and + ;; allow for pulling the image. + (make-marionette (list #$vm) #:timeout 60)) + + (test-runner-current (system-test-runner #$output)) + (test-begin "subids") + + (test-equal "/etc/subid and /etc/subgid are created and their content is sound" + '("root:100000:700\nbob:100700:65536\nalice:166236:65536" + "root:100000:65536\nalice:165536:65536") + (marionette-eval + `(begin + (use-modules (ice-9 popen) + (ice-9 match) + (ice-9 rdelim)) + + (define (read-lines file-or-port) + (define (loop-lines port) + (let loop ((lines '())) + (match (read-line port) + ((? eof-object?) + (reverse lines)) + (line + (loop (cons line lines)))))) + + (if (port? file-or-port) + (loop-lines file-or-port) + (call-with-input-file file-or-port + loop-lines))) + + (define slurp + (lambda args + (let* ((port (apply open-pipe* OPEN_READ args)) + (output (read-lines port)) + (status (close-pipe port))) + output))) + (let* ((response1 (slurp + ,(string-append #$coreutils "/bin/cat") + "/etc/subgid")) + (response2 (slurp + ,(string-append #$coreutils "/bin/cat") + "/etc/subuid"))) + (list (string-join response1 "\n") (string-join response2 "\n")))) + marionette)) + + (test-end)))) + + (gexp->derivation "subids-test" test)) + +(define %test-subids + (system-test + (name "subids") + (description "Test sub UIDs and sub GIDs provisioning service.") + (value (run-subids-test)))) -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v2 1/3] accounts: Add /etc/subuid and /etc/subgid support. References: In-Reply-To: Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 19 Aug 2024 22:10:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17241053478404 (code B ref 72337); Mon, 19 Aug 2024 22:10:02 +0000 Received: (at 72337) by debbugs.gnu.org; 19 Aug 2024 22:09:07 +0000 Received: from localhost ([127.0.0.1]:59382 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgAYk-0002BU-FE for submit@debbugs.gnu.org; Mon, 19 Aug 2024 18:09:07 -0400 Received: from confino.investici.org ([93.190.126.19]:43091) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgAYi-0002BF-2x for 72337@debbugs.gnu.org; Mon, 19 Aug 2024 18:09:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724105293; bh=/CpPWDx7HwQALqpfdG3azWXP5XxyeNDYiiPlqyW8amo=; h=From:To:Cc:Subject:Date:From; b=cnTB1vlntSiRNrobXy/Cu9F5Rc4DVCs0yOkBr1Bi7+/X4lKgFH9xGRu8Q1KcbVgPe qZJei2GmKLd8A6rX/yET/l0T4fwzDJti3441fWC9lG0vzqLd/Cgzi9pMb3eStkUKvM yUS8S7Ic7fDadhuMYhdcmQfFOjTgwHzUjI6fGXGs= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4Wnmv14cbnz10xW; Mon, 19 Aug 2024 22:08:13 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4Wnmv13rPFz10xJ; Mon, 19 Aug 2024 22:08:13 +0000 (UTC) From: Giacomo Leidi Date: Tue, 20 Aug 2024 00:08:02 +0200 Message-ID: X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a new record type, and serializers and deserializers for it in (gnu build accounts). Each instance of this record represents one line in either /etc/subuid or /etc/subgid. Since Shadow uses the same representation for both files, it should be ok if we do it as well. This commit adds also , a user facing representation of . It is supposed to be usable directly in OS configurations. * gnu/build/accounts.scm (subid-entry): New record; (write-subgid): add serializer for subgids; (write-subuid): add serializer for subuids; (read-subgid): add serializer for subgids; (read-subuid): add serializer for subuids. * gnu/system/accounts.scm (subid-range): New record. * test/accounts.scm: Test them. Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c --- gnu/build/accounts.scm | 37 ++++++++++++++++++++++++--- gnu/system/accounts.scm | 17 +++++++++++++ tests/accounts.scm | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index fa6f454b5e..ea8c69f205 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019, 2021, 2023 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -51,13 +52,23 @@ (define-module (gnu build accounts) group-entry-gid group-entry-members + subid-entry + subid-entry? + subid-entry-name + subid-entry-start + subid-entry-count + %password-lock-file write-group write-passwd write-shadow + write-subgid + write-subuid read-group read-passwd read-shadow + read-subgid + read-subuid %id-min %id-max @@ -68,11 +79,12 @@ (define-module (gnu build accounts) ;;; Commentary: ;;; -;;; This modules provides functionality equivalent to the C library's +;;; This module provides functionality equivalent to the C library's ;;; , , and routines, as well as a subset of the ;;; functionality of the Shadow command-line tools. It can parse and write -;;; /etc/passwd, /etc/shadow, and /etc/group. It can also take care of UID -;;; and GID allocation in a way similar to what 'useradd' does. +;;; /etc/passwd, /etc/shadow, /etc/group, /etc/subuid and /etc/subgid. It can +;;; also take care of UID and GID allocation in a way similar to what 'useradd' +;;; does. The same goes for sub UID and sub GID allocation. ;;; ;;; The benefit is twofold: less code is involved, and the ID allocation ;;; strategy and state preservation is made explicit. @@ -225,6 +237,17 @@ (define-database-entry ; (serialization list->comma-separated comma-separated->list) (default '()))) +(define-database-entry ; + subid-entry make-subid-entry + subid-entry? + (serialization #\: subid-entry->string string->subid-entry) + + (name subid-entry-name) + (start subid-entry-start + (serialization number->string string->number)) + (count subid-entry-count + (serialization number->string string->number))) + (define %password-lock-file ;; The password database lock file used by libc's 'lckpwdf'. Users should ;; grab this lock with 'with-file-lock' when they access the databases. @@ -265,6 +288,10 @@ (define write-shadow (database-writer "/etc/shadow" #o600 shadow-entry->string)) (define write-group (database-writer "/etc/group" #o644 group-entry->string)) +(define write-subuid + (database-writer "/etc/subuid" #o644 subid-entry->string)) +(define write-subgid + (database-writer "/etc/subgid" #o644 subid-entry->string)) (define (database-reader file string->entry) (lambda* (#:optional (file-or-port file)) @@ -287,6 +314,10 @@ (define read-shadow (database-reader "/etc/shadow" string->shadow-entry)) (define read-group (database-reader "/etc/group" string->group-entry)) +(define read-subuid + (database-reader "/etc/subuid" string->subid-entry)) +(define read-subgid + (database-reader "/etc/subgid" string->subid-entry)) ;;; diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 586cff1842..9a006c188d 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -39,6 +40,12 @@ (define-module (gnu system accounts) user-group-id user-group-system? + subid-range + subid-range? + subid-range-name + subid-range-start + subid-range-count + sexp->user-account sexp->user-group @@ -85,6 +92,16 @@ (define-record-type* (system? user-group-system? ; Boolean (default #f))) +(define-record-type* + subid-range make-subid-range + subid-range? + (name subid-range-name) + (start subid-range-start (default #f)) ; number + (count subid-range-count ; number + ; from find_new_sub_gids.c and + ; find_new_sub_uids.c + (default 65536))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 78136390bb..4944c22f49 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -41,6 +42,16 @@ (define %shadow-sample charlie:" (crypt "hey!" "$6$abc") ":17169:::::: nobody:!:0::::::\n")) +(define %subuid-sample + "\ +root:100000:300 +ada:100300:300\n") + +(define %subgid-sample + "\ +root:100000:600 +ada:100600:300\n") + (test-begin "accounts") @@ -135,6 +146,50 @@ (define %shadow-sample read-shadow) port)))) +(test-equal "write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (list (subid-entry + (name "root") + (start 100000) + (count 300)) + (subid-entry + (name "ada") + (start 100300) + (count 300))) + port)))) + +(test-equal "read-subuid + write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (call-with-input-string %subuid-sample + read-subuid) + port)))) + +(test-equal "write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (list (subid-entry + (name "root") + (start 100000) + (count 600)) + (subid-entry + (name "ada") + (start 100600) + (count 300))) + port)))) + +(test-equal "read-subgid + write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (call-with-input-string %subgid-sample + read-subgid) + port)))) + (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) base-commit: 00245fdcd4909d7e6b20fe88f5d089717115adc1 -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: paul Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 20 Aug 2024 22:14:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172419202831686 (code B ref 72337); Tue, 20 Aug 2024 22:14:02 +0000 Received: (at 72337) by debbugs.gnu.org; 20 Aug 2024 22:13:48 +0000 Received: from localhost ([127.0.0.1]:33763 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX6p-0008F0-VF for submit@debbugs.gnu.org; Tue, 20 Aug 2024 18:13:48 -0400 Received: from confino.investici.org ([93.190.126.19]:41585) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX6m-0008Ep-Na for 72337@debbugs.gnu.org; Tue, 20 Aug 2024 18:13:46 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724191979; bh=B0caruZA/6/7J7FXUOANELi899Ev2+5ho8XLwcU9xwE=; h=Date:Subject:From:To:References:In-Reply-To:From; b=mZp3otoXK96Ck1l28i9hdYv4+N46n3BCh77scS6Y7C3Y+SDiXvMNV85iBgJ8BDpY0 CXOVnzHPXocJ3vFiMY8XDItbq7Aze/muyJpQOyfskqUqzJ3ORDuCz1fABUGDaxZreS Go3y1OYUqb8NAUv9P2FOOoSIjVCXUCA5wctanNfU= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WpNy31BLMz10yR for <72337@debbugs.gnu.org>; Tue, 20 Aug 2024 22:12:59 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WpNy30pDQz10y9 for <72337@debbugs.gnu.org>; Tue, 20 Aug 2024 22:12:59 +0000 (UTC) Message-ID: Date: Wed, 21 Aug 2024 00:12:58 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 From: paul References: <230d9bce-25b6-40ab-fa67-14053ba0ef21@autistici.org> Content-Language: en-US In-Reply-To: <230d9bce-25b6-40ab-fa67-14053ba0ef21@autistici.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Score: -1.9 (-) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.9 (--) Dear Guixers, I'm sending a v3. This patchset brings a small fix where numbers where not converted to strings in error messages string-append calls. Thank you for your time, giacomo From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v3 2/3] account: Add /etc/subid and /etc/subgid allocation logic. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 20 Aug 2024 22:17:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172419217231971 (code B ref 72337); Tue, 20 Aug 2024 22:17:01 +0000 Received: (at 72337) by debbugs.gnu.org; 20 Aug 2024 22:16:12 +0000 Received: from localhost ([127.0.0.1]:33768 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX99-0008JY-GE for submit@debbugs.gnu.org; Tue, 20 Aug 2024 18:16:12 -0400 Received: from confino.investici.org ([93.190.126.19]:34397) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX96-0008JJ-Iu for 72337@debbugs.gnu.org; Tue, 20 Aug 2024 18:16:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724192124; bh=mmQeesRV6D6P4nbumrIBueApqmgDK80Wr2Ht/XeHvDQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OYss59cdfkcEz6nnMltJPqBD+w45Fs+LY9MTAsSNrd2kbErc36Q8AbBjbFSn5xnhV tyZoSLJh2fWW+JIAq8piKZqAtGfjy5NCu0LC5yb9S6Efuz8/hlxDZQaWXM7AI2vLWJ Z0U5yLLQ7qmC6iO0llsgFCd9ZJ/vyw/rujTL+ec0= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WpP0r3GJGz10yX; Tue, 20 Aug 2024 22:15:24 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WpP0r2WQZz10y9; Tue, 20 Aug 2024 22:15:24 +0000 (UTC) From: Giacomo Leidi Date: Wed, 21 Aug 2024 00:14:56 +0200 Message-ID: <5b955b5c53e8e2c7c3173c87ca17758505e960ae.1724192097.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) * gnu/build/accounts.scm (list-set): New variable; (%sub-id-min): new variable; (%sub-id-max): new variable; (%sub-id-count): new variable; (sub-id?): new variable; (subid-range-fits?): new variable; (subid-range-fits-between?): new variable; (insert-subid-range): new variable; (reserve-subids): new variable; (range->entry): new variable; (entry->range): new variable; (allocate-subids): new variable; (subuid+subgid-databases): new variable. * gnu/system/accounts.scm (subid-range-end): New variable; (subid-range-has-start?): new variable; (subid-range-less): new variable. * test/accounts.scm: Test them. Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d --- gnu/build/accounts.scm | 231 +++++++++++++++++++++++++++++++++++++++- gnu/system/accounts.scm | 30 ++++++ tests/accounts.scm | 108 +++++++++++++++++++ 3 files changed, 368 insertions(+), 1 deletion(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index ea8c69f205..780cb5f7ff 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -74,8 +74,12 @@ (define-module (gnu build accounts) %id-max %system-id-min %system-id-max + %sub-id-min + %sub-id-max + %sub-id-count - user+group-databases)) + user+group-databases + subuid+subgid-databases)) ;;; Commentary: ;;; @@ -91,6 +95,18 @@ (define-module (gnu build accounts) ;;; ;;; Code: + +;;; +;;; General utilities. +;;; + +(define (list-set lst el k) + (if (>= k (length lst)) + `(,@lst ,el) + `(,@(list-head lst k) + ,el + ,@(list-tail lst k)))) + ;;; ;;; Machinery to define user and group databases. @@ -342,6 +358,12 @@ (define %id-max 60000) (define %system-id-min 100) (define %system-id-max 999) +;; According to Shadow's libmisc/find_new_sub_uids.c and +;; libmisc/find_new_sub_gids.c. +(define %sub-id-min 100000) +(define %sub-id-max 600100000) +(define %sub-id-count 65536) + (define (system-id? id) (and (> id %system-id-min) (<= id %system-id-max))) @@ -350,6 +372,10 @@ (define (user-id? id) (and (>= id %id-min) (< id %id-max))) +(define (sub-id? id) + (and (>= id %sub-id-min) + (< id %sub-id-max))) + (define* (allocate-id assignment #:key system?) "Return two values: a newly allocated ID, and an updated record based on ASSIGNMENT. If SYSTEM? is true, return a system ID." @@ -405,6 +431,158 @@ (define* (reserve-ids allocation ids #:key (skip? #t)) (allocation-ids allocation) ids)))) +(define (subid-range-fits? r interval-start interval-end) + (and (<= interval-start + (subid-range-start r)) + (<= (subid-range-end r) + interval-end))) + +(define (subid-range-fits-between? r a b) + (subid-range-fits? r + (+ (subid-range-start a) 1) + (- (subid-range-end b) 1))) + +(define (insert-subid-range range lst) + (define* (actualize r #:key (start %sub-id-min)) + (if (subid-range-has-start? r) + r + (subid-range + (inherit r) + (start start)))) + (define lst-length (length lst)) + (define range-name (subid-range-name range)) + (define range-start (subid-range-start range)) + (define has-start? (subid-range-has-start? range)) + (define range-end (subid-range-end range)) + + (when has-start? + (unless (and (sub-id? range-start) + (sub-id? range-end)) + (raise + (string-append "Subid range of " range-name + " from " (number->string range-start) " to " + (number->string range-end) + " spans over illegal subids. Max allowed is " + (number->string %sub-id-max) ", min is " + (number->string %sub-id-min) ".")))) + + (if (<= lst-length 1) + (if (= lst-length 0) + (list (actualize range)) + (if (subid-range-less range (first lst)) + (list-set lst (actualize range) 0) + (list-set lst + (actualize + range + #:start (and (subid-range-has-start? (first lst)) + (+ (subid-range-end (first lst)) 1))) + 1))) + (let loop ((i 0)) + (define next-i (+ i 1)) + (define ith-range + (list-ref lst i)) + (define ith-start + (subid-range-start ith-range)) + (define ith-has-start? + (subid-range-has-start? ith-range)) + (define ith-name + (subid-range-name ith-range)) + + (if (and + (= next-i lst-length) + (subid-range-less ith-range range)) + (let ((actual-range + (actualize + range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))))) + (list-set lst + actual-range + lst-length)) + (let* ((next-range + (list-ref lst next-i)) + (next-has-start? + (subid-range-has-start? next-range))) + (cond + + ((and has-start? (= range-start ith-start)) + (raise + (string-append "Subid range of " range-name + " has same start " + (number->string range-start) + " of the one " + "from " ith-name "."))) + + ((and (= i 0) + (subid-range-less range ith-range) + (or + (and + has-start? ith-has-start? + (subid-range-fits? (actualize range) + %sub-id-min + (- (subid-range-start + (actualize ith-range)) + 1))) + (not (and has-start? ith-has-start?)))) + (list-set lst (actualize range) 0)) + + ((subid-range-less range ith-range) + (raise + (string-append "Subid range of " range-name + " overlaps with the one of " + ith-name "."))) + + ((and (subid-range-less ith-range range) + (subid-range-less range next-range)) + (if (or (not (and has-start? + ith-has-start? + next-has-start?)) + + (and has-start? + ith-has-start? + next-has-start? + (subid-range-fits-between? range + ith-range + next-range))) + (list-set lst + (actualize range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))) + next-i) + (if (>= i lst-length) + (if (and (subid-range-less next-range range) + (let ((actual-next + (actualize next-range + #:start (and ith-has-start? + (+ (subid-range-end ith-range) 1))))) + (or (not (subid-range-has-start? actual-next)) + (subid-range-fits? + (actualize range + #:start (and next-has-start? + (+ (subid-range-end next-range) 1))) + (+ (subid-range-end actual-next) 1) + %sub-id-max)))) + (list-set lst range lst-length) + (raise + (string-append "Couldn't fit " range-name ", reached end of list."))) + (loop next-i)))) + + ((or + (not has-start?) + (subid-range-less next-range range)) + (loop next-i)) + + (else + (raise (string-append "Couldn't fit " range-name ", this should never happen."))))))))) + +(define* (reserve-subids allocation ranges) + "Mark the subid ranges listed in RANGES as reserved in ALLOCATION. +ALLOCATION is supposed to be sorted by SUBID-RANGE-LESS." + (fold insert-subid-range + allocation + (sort-list ranges + subid-range-less))) + (define (allocated? allocation id) "Return true if ID is already allocated as part of ALLOCATION." (->bool (vhash-assv id (allocation-ids allocation)))) @@ -540,6 +718,31 @@ (define* (allocate-passwd users groups #:optional (current-passwd '())) uids users))) +(define (range->entry range) + (subid-entry + (name (subid-range-name range)) + (start (subid-range-start range)) + (count (subid-range-count range)))) + +(define (entry->range entry) + (subid-range + (name (subid-entry-name entry)) + (start (subid-entry-start entry)) + (count (subid-entry-count entry)))) + +(define* (allocate-subids ranges #:optional (current-ranges '())) + "Return a list of subids entries for RANGES, a list of . Members +for each group are taken from MEMBERS, a vhash that maps ranges names to member +names. IDs found in CURRENT-RANGES, a list of subid entries, are reused." + (define subids + ;; Mark all the currently used IDs and the explicitly requested IDs as + ;; reserved. + (reserve-subids (reserve-subids (list) + current-ranges) + ranges)) + + (map range->entry subids)) + (define* (days-since-epoch #:optional (current-time current-time)) "Return the number of days elapsed since the 1st of January, 1970." (let* ((now (current-time time-utc)) @@ -615,3 +818,29 @@ (define* (user+group-databases users groups #:current-time current-time)) (values group-entries passwd-entries shadow-entries)) + +(define* (subuid+subgid-databases subuids subgids + #:key + (current-subuids + (map entry->range + (empty-if-not-found read-subuid))) + (current-subgids + (map entry->range + (empty-if-not-found read-subgid)))) + "Return two values: the list of subgid entries, and the list of subuid entries +corresponding to SUBUIDS and SUBGIDS. +Preserve stateful bits from CURRENT-SUBUIDS and CURRENT-SUBGIDS." + + (define (range-eqv? a b) + (string=? (subid-range-name a) + (subid-range-name b))) + + (define subuid-entries + (allocate-subids + (lset-difference range-eqv? subuids current-subuids) current-subuids)) + + (define subgid-entries + (allocate-subids + (lset-difference range-eqv? subgids current-subgids) current-subgids)) + + (values subuid-entries subgid-entries)) diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 9a006c188d..1b88ca301f 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -45,6 +45,9 @@ (define-module (gnu system accounts) subid-range-name subid-range-start subid-range-count + subid-range-end + subid-range-has-start? + subid-range-less sexp->user-account sexp->user-group @@ -102,6 +105,33 @@ (define-record-type* ; find_new_sub_uids.c (default 65536))) +(define (subid-range-end range) + "Returns the last subid referenced in RANGE." + (and + (subid-range-has-start? range) + (+ (subid-range-start range) + (subid-range-count range) + -1))) + +(define (subid-range-has-start? range) + "Returns #t when RANGE's start is a number." + (number? (subid-range-start range))) + +(define (subid-range-less a b) + "Returns #t when subid range A either starts before, or is more specific +than B. When it is not possible to determine whether a range is more specific +w.r.t. another range their names are compared alphabetically." + (define start-a (subid-range-start a)) + (define start-b (subid-range-start b)) + (cond ((and (not start-a) (not start-b)) + (string< (subid-range-name a) + (subid-range-name b))) + ((and start-a start-b) + (< start-a start-b)) + (else + (and start-a + (not start-b))))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 4944c22f49..2fbebfaf56 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -193,6 +193,7 @@ (define %subgid-sample (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) +(define allocate-subids (@@ (gnu build accounts) allocate-subids)) (test-equal "allocate-groups" ;; Allocate GIDs in a stateless fashion. @@ -257,6 +258,69 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (list (group-entry (name "d") (gid (- %id-max 2)))))) +(test-equal "allocate-subids" + ;; Allocate sub IDs in a stateless fashion. + (list (subid-entry (name "root") (start %sub-id-min) (count 100)) + (subid-entry (name "t") (start 100100) (count 899)) + (subid-entry (name "x") (start 100999) (count 200))) + (allocate-subids (list + (subid-range (name "x") (count 200)) + (subid-range (name "t") (count 899))) + (list (subid-range (name "root") (count 100))))) + +(test-equal "allocate-subids with requested IDs ranges" + ;; Make sure the requested sub ID for "t" and "x" are honored. + (list (subid-entry (name "x") (start %sub-id-min) (count 200)) + (subid-entry (name "t") (start 1000000) (count 899)) + (subid-entry (name "l") (start 1000899) (count 100)) + (subid-entry (name "root") (start 1000999) (count 100))) + (allocate-subids (list + (subid-range (name "root") (count 100)) + (subid-range (name "l") (count 100))) + (list + (subid-range (name "x") (start %sub-id-min) (count 200)) + (subid-range (name "t") (start 1000000) (count 899))))) + +(test-equal "allocate-subids with interleaving" + ;; Make sure the requested sub ID for "m" is honored. + (list (subid-entry (name "x") (start %sub-id-min) (count 200)) + (subid-entry (name "t") (start 1000000) (count 899)) + (subid-entry (name "i") (start 1100000) (count 1)) + (subid-entry (name "root") (start 1100001) (count 100)) + (subid-entry (name "m") (start 1200000) (count 27))) + (allocate-subids (list (subid-range (name "m") (start 1200000) (count 27))) + (list + (subid-range (name "x") (start %sub-id-min) (count 200)) + (subid-range (name "t") (start 1000000) (count 899)) + (subid-range (name "i") (start 1100000) (count 1)) + (subid-range (name "root") (count 100))))) + +(let ((inputs+currents + (list + ;; Try impossible before + (list + (list (subid-range (name "m") (start 100100) (count 27))) + (list + (subid-range (name "x") (start %sub-id-min) (count 150)))) + ;; Try impossible after + (list + (list (subid-range (name "m") (start %sub-id-min) (count 30))) + (list + (subid-range (name "x") (start (+ 29 %sub-id-min)) (count 150)))) + ;; Try impossible between + (list + (list (subid-range (name "m") (start 100200) (count 500))) + (list + (subid-range (name "root") (start %sub-id-min) (count 100)) + (subid-range (name "x") (start (+ %sub-id-min 500)) (count 100))))))) + (test-error "allocate-subids with interleaving, impossible interleaving" + "error" + ;; Make sure it's impossible to explicitly request impossible allocations + (for-each + (lambda (lst) + (allocate-subids (first lst) (second lst))) + inputs+currents))) + (test-equal "allocate-passwd" ;; Allocate UIDs in a stateless fashion. (list (password-entry (name "alice") (uid %id-min) (gid 1000) @@ -376,4 +440,48 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (make-time type 0 (* 24 3600 100))))) list)) +(test-equal "subuid+subgid-databases" + ;; The whole process. + (list (list (subid-entry (name "root") + (start %sub-id-min) + (count 100)) + (subid-entry (name "alice") + (start (+ %sub-id-min 100)) + (count 200)) + (subid-entry (name "bob") + (start (+ %sub-id-min 100 200)) + (count 200))) + (list + (subid-entry (name "root") + (start %sub-id-min) + (count 200)) + (subid-entry (name "alice") + (start (+ %sub-id-min 200)) + (count 400)) + (subid-entry (name "charlie") + (start (+ %sub-id-min 200 400)) + (count 300)))) + (call-with-values + (lambda () + (subuid+subgid-databases + (list (subid-range (name "root") + (start %sub-id-min) + (count 100)) + (subid-range (name "alice") + (start (+ %sub-id-min 100)) + (count 200)) + (subid-range (name "bob") + (count 200))) + (list + (subid-range (name "alice") + (count 400)) + (subid-range (name "charlie") + (count 300))) + #:current-subgids + (list (subid-range (name "root") + (start %sub-id-min) + (count 200))) + #:current-subuids '())) + list)) + (test-end "accounts") -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v3 3/3] system: Add /etc/subuid and /etc/subgid support. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: pelzflorian@pelzflorian.de, ludo@gnu.org, matt@excalamus.com, maxim.cournoyer@gmail.com, guix-patches@gnu.org Resent-Date: Tue, 20 Aug 2024 22:17:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi , Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Matthew Trzcinski , Maxim Cournoyer X-Debbugs-Original-Xcc: Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Matthew Trzcinski , Maxim Cournoyer Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172419217331978 (code B ref 72337); Tue, 20 Aug 2024 22:17:02 +0000 Received: (at 72337) by debbugs.gnu.org; 20 Aug 2024 22:16:13 +0000 Received: from localhost ([127.0.0.1]:33770 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX9A-0008Jc-F9 for submit@debbugs.gnu.org; Tue, 20 Aug 2024 18:16:13 -0400 Received: from confino.investici.org ([93.190.126.19]:29193) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX96-0008JK-UE for 72337@debbugs.gnu.org; Tue, 20 Aug 2024 18:16:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724192124; bh=yq1Pxckplmkyu1Wkh/+j0m4MvOq8ERF7HMXWDdlJ+Jg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nArwaX3aRKKZsHMoMTTwj33/HL96D6dCzlyRzZhflX7O+H8grM+b+lFIIQcDdDN1t BpKbinZrqEGr5+j7k57TSh7he8qvy7zKUavGV9E7oepXTb+Y3OEejb4ik7PkD7kAyo O0xicsHXoZ3IWoSdp1rikc6T3FhrCDUdQ9FcKnC4= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WpP0r5f2Zz10yY; Tue, 20 Aug 2024 22:15:24 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WpP0r4lbSz10y9; Tue, 20 Aug 2024 22:15:24 +0000 (UTC) From: Giacomo Leidi Date: Wed, 21 Aug 2024 00:14:57 +0200 Message-ID: <8b0b9421e1347e0f0d6ce88c8eb66a5b6296cc0c.1724192097.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a Guix System service to handle allocation of subuid and subgid requests. Users that don't care can just add themselves as a subid-range and don't need to specify anything but their user name. Users that care about specific ranges, such as possibly LXD, can specify a start and a count. * doc/guix.texi: Document the new service. * gnu/build/activation.scm (activate-subuids+subgids): New variable. * gnu/local.mk: Add gnu/tests/shadow.scm. * gnu/system/accounts.scm (sexp->subid-range): New variable. * gnu/system/shadow.scm (%root-subid): New variable; (subids-configuration): new record; (subid-range->gexp): new variable; (assert-valid-subids): new variable; (delete-duplicate-ranges): new variable; (subids-activation): new variable; (subids-extension): new record; (append-subid-ranges): new variable; (subids-extension-merge): new variable; (subids-service-type): new variable. * gnu/tests/shadow.scm (subids): New system test. Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 --- doc/guix.texi | 171 ++++++++++++++++++++++++++++++++ gnu/build/activation.scm | 19 ++++ gnu/local.mk | 1 + gnu/system/accounts.scm | 10 ++ gnu/system/shadow.scm | 208 ++++++++++++++++++++++++++++++++++++++- gnu/tests/shadow.scm | 128 ++++++++++++++++++++++++ 6 files changed, 535 insertions(+), 2 deletions(-) create mode 100644 gnu/tests/shadow.scm diff --git a/doc/guix.texi b/doc/guix.texi index 0e1e253b02..a799342769 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -41647,6 +41647,177 @@ Miscellaneous Services @end deftp +@c %end of fragment + +@cindex Subids +@subsubheading Subid Service + +The @code{(gnu system shadow)} module exposes the +@code{subids-service-type}, its configuration record +@code{subids-configuration} and its extension record +@code{subids-extension}. + +With @code{subids-service-type}, subuids and subgids ranges can be reserved for +users that desire so: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Users (definitely other services), usually, are supposed to extend the service +instead of adding subids directly to @code{subids-configuration}, unless the +want to change the default behavior for root. With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, possibly +starting at the minimum possible subid. Otherwise the root subuids and subgids +ranges are fitted wherever possible. + +The above configuration will yield the following: + +@example +# cat /etc/subgid +root:100000:65536 +alice:165536:65536 +# cat /etc/subuid +root:100000:700 +bob:100700:65536 +alice:166236:65536 +@end example + +@c %start of fragment + +@deftp {Data Type} subids-configuration + +With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, possibly +starting at the minimum possible subid. To disable the default behavior and +provide your own definition for the root subid ranges you can set to @code{#f} +the @code{add-root?} field: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (service subids-service-type + (subids-configuration + (add-root? #f) + (subgids + (subid-range (name "root") + (start 120000) + (count 100))) + (subuids + (subid-range (name "root") + (start 120000) + (count 100))))) + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Available @code{subids-configuration} fields are: + +@table @asis +@item @code{add-root?} (default: @code{#t}) (type: boolean) +Whether to automatically configure subuids and subgids for root. + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subgid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subuid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subids-extension + +Available @code{subids-extension} fields are: + +@table @asis + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subgids}. Entries with the same name are deduplicated +upon merging. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subuids}. Entries with the same name are deduplicated +upon merging. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subid-range + +The @code{subid-range} record is defined at @code{(gnu system accounts)}. +Available fields are: + +@table @asis + +@item @code{name} (type: string) +The name of the user or group that will own this range. + +@item @code{start} (default: @code{#f}) (type: integer) +The first requested subid. When false the first available subid with enough +contiguous subids will be assigned. + +@item @code{count} (default: @code{#f}) (type: integer) +The number of total allocated subids. When #f the default of 65536 will be +assumed . + +@end table + +@end deftp + @c %end of fragment @node Privileged Programs diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index a57ca78a86..91662fe0fd 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -10,6 +10,7 @@ ;;; Copyright © 2021 Brice Waegeneire ;;; Copyright © 2022 Tobias Geerinckx-Rice ;;; Copyright © 2024 Nicolas Graves +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -40,6 +41,7 @@ (define-module (gnu build activation) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) #:export (activate-users+groups + activate-subuids+subgids activate-user-home activate-etc activate-privileged-programs @@ -203,6 +205,23 @@ (define (activate-users+groups users groups) (chmod directory #o555)) (duplicates (map user-account-home-directory system-accounts)))) +(define (activate-subuids+subgids subuids subgids) + "Make sure SUBUIDS (a list of subid range records) and SUBGIDS (a list of +subid range records) are all available." + + ;; Take same lock as Shadow while we read + ;; and write the databases. This ensures there's no race condition with + ;; other tools that might be accessing it at the same time. + (with-file-lock "/etc/subgid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subgid subgid))) + + (with-file-lock "/etc/subuid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subuid subuid)))) + (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless they already exist." diff --git a/gnu/local.mk b/gnu/local.mk index 3b0a3858f7..88467e3d42 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -839,6 +839,7 @@ GNU_SYSTEM_MODULES = \ %D%/tests/samba.scm \ %D%/tests/security.scm \ %D%/tests/security-token.scm \ + %D%/tests/shadow.scm \ %D%/tests/singularity.scm \ %D%/tests/ssh.scm \ %D%/tests/telephony.scm \ diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 1b88ca301f..f63d7f96bd 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -51,6 +51,7 @@ (define-module (gnu system accounts) sexp->user-account sexp->user-group + sexp->subid-range default-shell)) @@ -159,3 +160,12 @@ (define (sexp->user-account sexp) (create-home-directory? create-home-directory?) (shell shell) (password password) (system? system?))))) + +(define (sexp->subid-range sexp) + "Take SEXP, a tuple as returned by 'subid-range->gexp', and turn it into a +subid-range record." + (match sexp + ((name start count) + (subid-range (name name) + (start start) + (count count))))) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index d9f13271d8..f0129afe8e 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen ;;; Copyright © 2020, 2023 Efraim Flashner ;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -77,7 +78,20 @@ (define-module (gnu system shadow) %base-user-accounts account-service-type - account-service)) + account-service + + subids-configuration + subids-configuration? + subids-configuration-add-root? + subids-configuration-subgids + subids-configuration-subuids + + subids-extension + subids-extension? + subids-extension-subgids + subids-extension-subuids + + subids-service-type)) ;;; Commentary: ;;; @@ -380,7 +394,7 @@ (define (assert-valid-users/groups users groups) ;;; -;;; Service. +;;; Accounts Service. ;;; (define (user-group->gexp group) @@ -521,4 +535,194 @@ (define (account-service accounts+groups skeletons) (service account-service-type (append skeletons accounts+groups))) + +;;; +;;; Subids Service. +;;; + +(define %sub-id-min + (@@ (gnu build accounts) %sub-id-min)) +(define %sub-id-max + (@@ (gnu build accounts) %sub-id-max)) +(define %sub-id-count + (@@ (gnu build accounts) %sub-id-count)) + +(define* (%root-subid #:optional (start %sub-id-min) (count %sub-id-count)) + (subid-range + (name "root") + (start start) + (count count))) + +(define-record-type* + subids-configuration make-subids-configuration + subids-configuration? + this-subids-configuration + + (add-root? subids-configuration-add-root? ; boolean + (default #t)) + (subgids subids-configuration-subgids ; list of + (default '())) + (subuids subids-configuration-subuids ; list of + (default '()))) + +(define (subid-range->gexp range) + "Turn RANGE, a object, into a list-valued gexp suitable for +'activate-subuids+subgids'." + (define count (subid-range-count range)) + #~`(#$(subid-range-name range) + #$(subid-range-start range) + #$(if (and (number? count) + (> count 0)) + count + %sub-id-count))) + +(define (assert-valid-subids ranges) + (cond ((>= (fold + 0 (map subid-range-count ranges)) + (- %sub-id-max %sub-id-min -1)) + (raise + (string-append + "The configured ranges are more than the " + (number->string + (- %sub-id-max %sub-id-min -1)) " max allowed."))) + ((any (lambda (r) + (define start (subid-range-start r)) + (and start + (< start %sub-id-min))) + ranges) + (raise + (string-append + "One subid-range starts before the minimum allowed sub id " + (number->string %sub-id-min) "."))) + ((any (lambda (r) + (define end (subid-range-end r)) + (and end + (> end %sub-id-max))) + ranges) + (raise + (string-append + "One subid-range ends after the maximum allowed sub id " + (number->string %sub-id-max) "."))) + ((any (compose null? subid-range-name) + ranges) + (raise + "One subid-range has a null name.")) + ((any (compose string-null? subid-range-name) + ranges) + (raise + "One subid-range has a name equal to the empty string.")) + (else #t))) + +(define (delete-duplicate-ranges ranges) + (delete-duplicates ranges + (lambda args + (apply string=? (map subid-range-name ranges))))) + +(define (subids-activation config) + "Return a gexp that activates SUBUIDS+SUBGIDS, a list of +objects." + (define (add-root-when-missing ranges) + (define sorted-ranges + (sort-list ranges subid-range-less)) + (define root-missing? + (not + (find (lambda (r) + (string=? "root" + (subid-range-name r))) + sorted-ranges))) + (define first-start + (and (> (length sorted-ranges) 0) + (subid-range-start (first sorted-ranges)))) + (define first-has-start? + (number? first-start)) + (define root-start + (if first-has-start? + (and + (> first-start %sub-id-min) + %sub-id-min) + %sub-id-min)) + (define root-count + (if first-has-start? + (- first-start %sub-id-min) + %sub-id-count)) + (if (and root-missing? + (subids-configuration-add-root? config)) + (append (list (%root-subid root-start root-count)) + sorted-ranges) + sorted-ranges)) + + (define subuids + (delete-duplicate-ranges (subids-configuration-subuids config))) + + (define subuids-specs + (map subid-range->gexp (add-root-when-missing subuids))) + + (define subgids + (delete-duplicate-ranges (subids-configuration-subgids config))) + + (define subgids-specs + (map subid-range->gexp (add-root-when-missing subgids))) + + (assert-valid-subids subgids) + (assert-valid-subids subuids) + + ;; Add subuids and subgids. + (with-imported-modules (source-module-closure '((gnu system accounts))) + #~(begin + (use-modules (gnu system accounts)) + + (activate-subuids+subgids (map sexp->subid-range (list #$@subuids-specs)) + (map sexp->subid-range (list #$@subgids-specs)))))) + +(define-record-type* + subids-extension make-subids-extension + subids-extension? + this-subids-extension + + (subgids subids-extension-subgids ; list of + (default '())) + (subuids subids-extension-subuids ; list of + (default '()))) + +(define append-subid-ranges + (lambda args + (delete-duplicate-ranges + (apply append args)))) + +(define (subids-extension-merge a b) + (subids-extension + (subgids (append-subid-ranges + (subids-extension-subgids a) + (subids-extension-subgids b))) + (subuids (append-subid-ranges + (subids-extension-subuids a) + (subids-extension-subuids b))))) + +(define subids-service-type + (service-type (name 'subids) + ;; Concatenate lists. + (compose (lambda (args) + (fold subids-extension-merge + (subids-extension) + args))) + (extend + (lambda (config extension) + (subids-configuration + (inherit config) + (subgids + (append-subid-ranges + (subids-configuration-subgids config) + (subids-extension-subgids extension))) + (subuids + (append-subid-ranges + (subids-configuration-subuids config) + (subids-extension-subuids extension)))))) + (extensions + (list (service-extension activation-service-type + subids-activation))) + (default-value + (subids-configuration)) + (description + "Ensure the specified sub UIDs and sub GIDs exist in +/etc/subuid and /etc/subgid."))) + ;;; shadow.scm ends here diff --git a/gnu/tests/shadow.scm b/gnu/tests/shadow.scm new file mode 100644 index 0000000000..1e755b5438 --- /dev/null +++ b/gnu/tests/shadow.scm @@ -0,0 +1,128 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Giacomo Leidi +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu tests shadow) + #:use-module (gnu packages base) + #:use-module (gnu tests) + #:use-module (gnu services) + #:use-module (gnu system) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (gnu system vm) + #:use-module (guix gexp) + #:export (%test-subids)) + + +(define %subids-os + (simple-operating-system + (simple-service + 'simple-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range + (name "alice")) + (subid-range + (name "bob") + (start 100700)))) + (subuids + (list + (subid-range + (name "alice")))))))) + +(define (run-subids-test) + "Run IMAGE as an OCI backed Shepherd service, inside OS." + + (define os + (marionette-operating-system + (operating-system-with-gc-roots + %subids-os + (list)) + #:imported-modules '((gnu services herd) + (guix combinators)))) + + (define vm + (virtual-machine + (operating-system os) + (volatile? #f) + (memory-size 1024) + (disk-image-size (* 3000 (expt 2 20))) + (port-forwardings '()))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) (srfi srfi-64) + (gnu build marionette)) + + (define marionette + ;; Relax timeout to accommodate older systems and + ;; allow for pulling the image. + (make-marionette (list #$vm) #:timeout 60)) + + (test-runner-current (system-test-runner #$output)) + (test-begin "subids") + + (test-equal "/etc/subid and /etc/subgid are created and their content is sound" + '("root:100000:700\nbob:100700:65536\nalice:166236:65536" + "root:100000:65536\nalice:165536:65536") + (marionette-eval + `(begin + (use-modules (ice-9 popen) + (ice-9 match) + (ice-9 rdelim)) + + (define (read-lines file-or-port) + (define (loop-lines port) + (let loop ((lines '())) + (match (read-line port) + ((? eof-object?) + (reverse lines)) + (line + (loop (cons line lines)))))) + + (if (port? file-or-port) + (loop-lines file-or-port) + (call-with-input-file file-or-port + loop-lines))) + + (define slurp + (lambda args + (let* ((port (apply open-pipe* OPEN_READ args)) + (output (read-lines port)) + (status (close-pipe port))) + output))) + (let* ((response1 (slurp + ,(string-append #$coreutils "/bin/cat") + "/etc/subgid")) + (response2 (slurp + ,(string-append #$coreutils "/bin/cat") + "/etc/subuid"))) + (list (string-join response1 "\n") (string-join response2 "\n")))) + marionette)) + + (test-end)))) + + (gexp->derivation "subids-test" test)) + +(define %test-subids + (system-test + (name "subids") + (description "Test sub UIDs and sub GIDs provisioning service.") + (value (run-subids-test)))) -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v3 1/3] accounts: Add /etc/subuid and /etc/subgid support. References: In-Reply-To: Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 20 Aug 2024 22:17:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172419217831997 (code B ref 72337); Tue, 20 Aug 2024 22:17:02 +0000 Received: (at 72337) by debbugs.gnu.org; 20 Aug 2024 22:16:18 +0000 Received: from localhost ([127.0.0.1]:33773 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX9F-0008K1-QE for submit@debbugs.gnu.org; Tue, 20 Aug 2024 18:16:18 -0400 Received: from confino.investici.org ([93.190.126.19]:36729) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgX9D-0008Jq-I1 for 72337@debbugs.gnu.org; Tue, 20 Aug 2024 18:16:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1724192124; bh=/CpPWDx7HwQALqpfdG3azWXP5XxyeNDYiiPlqyW8amo=; h=From:To:Cc:Subject:Date:From; b=pPcIYDd3SDvy4Q0SBvTv/IeSbsbzwUuLUosMfcWfupoiflDxKOPJ8lAysWLx6+KIF kAzfMq8zZHEZxYouWK2wHTX5Riuivo0DcQQDVZ2lakwbN5Nxkg2/OtYzN1EaL8mZBv pihetJHQ2Z7nsxJSUFG5FDYIsopTqVTGA0dUlzTw= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WpP0r1Ccsz10yR; Tue, 20 Aug 2024 22:15:24 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WpP0r0Tmvz10y9; Tue, 20 Aug 2024 22:15:24 +0000 (UTC) From: Giacomo Leidi Date: Wed, 21 Aug 2024 00:14:55 +0200 Message-ID: X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a new record type, and serializers and deserializers for it in (gnu build accounts). Each instance of this record represents one line in either /etc/subuid or /etc/subgid. Since Shadow uses the same representation for both files, it should be ok if we do it as well. This commit adds also , a user facing representation of . It is supposed to be usable directly in OS configurations. * gnu/build/accounts.scm (subid-entry): New record; (write-subgid): add serializer for subgids; (write-subuid): add serializer for subuids; (read-subgid): add serializer for subgids; (read-subuid): add serializer for subuids. * gnu/system/accounts.scm (subid-range): New record. * test/accounts.scm: Test them. Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c --- gnu/build/accounts.scm | 37 ++++++++++++++++++++++++--- gnu/system/accounts.scm | 17 +++++++++++++ tests/accounts.scm | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index fa6f454b5e..ea8c69f205 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019, 2021, 2023 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -51,13 +52,23 @@ (define-module (gnu build accounts) group-entry-gid group-entry-members + subid-entry + subid-entry? + subid-entry-name + subid-entry-start + subid-entry-count + %password-lock-file write-group write-passwd write-shadow + write-subgid + write-subuid read-group read-passwd read-shadow + read-subgid + read-subuid %id-min %id-max @@ -68,11 +79,12 @@ (define-module (gnu build accounts) ;;; Commentary: ;;; -;;; This modules provides functionality equivalent to the C library's +;;; This module provides functionality equivalent to the C library's ;;; , , and routines, as well as a subset of the ;;; functionality of the Shadow command-line tools. It can parse and write -;;; /etc/passwd, /etc/shadow, and /etc/group. It can also take care of UID -;;; and GID allocation in a way similar to what 'useradd' does. +;;; /etc/passwd, /etc/shadow, /etc/group, /etc/subuid and /etc/subgid. It can +;;; also take care of UID and GID allocation in a way similar to what 'useradd' +;;; does. The same goes for sub UID and sub GID allocation. ;;; ;;; The benefit is twofold: less code is involved, and the ID allocation ;;; strategy and state preservation is made explicit. @@ -225,6 +237,17 @@ (define-database-entry ; (serialization list->comma-separated comma-separated->list) (default '()))) +(define-database-entry ; + subid-entry make-subid-entry + subid-entry? + (serialization #\: subid-entry->string string->subid-entry) + + (name subid-entry-name) + (start subid-entry-start + (serialization number->string string->number)) + (count subid-entry-count + (serialization number->string string->number))) + (define %password-lock-file ;; The password database lock file used by libc's 'lckpwdf'. Users should ;; grab this lock with 'with-file-lock' when they access the databases. @@ -265,6 +288,10 @@ (define write-shadow (database-writer "/etc/shadow" #o600 shadow-entry->string)) (define write-group (database-writer "/etc/group" #o644 group-entry->string)) +(define write-subuid + (database-writer "/etc/subuid" #o644 subid-entry->string)) +(define write-subgid + (database-writer "/etc/subgid" #o644 subid-entry->string)) (define (database-reader file string->entry) (lambda* (#:optional (file-or-port file)) @@ -287,6 +314,10 @@ (define read-shadow (database-reader "/etc/shadow" string->shadow-entry)) (define read-group (database-reader "/etc/group" string->group-entry)) +(define read-subuid + (database-reader "/etc/subuid" string->subid-entry)) +(define read-subgid + (database-reader "/etc/subgid" string->subid-entry)) ;;; diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 586cff1842..9a006c188d 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -39,6 +40,12 @@ (define-module (gnu system accounts) user-group-id user-group-system? + subid-range + subid-range? + subid-range-name + subid-range-start + subid-range-count + sexp->user-account sexp->user-group @@ -85,6 +92,16 @@ (define-record-type* (system? user-group-system? ; Boolean (default #f))) +(define-record-type* + subid-range make-subid-range + subid-range? + (name subid-range-name) + (start subid-range-start (default #f)) ; number + (count subid-range-count ; number + ; from find_new_sub_gids.c and + ; find_new_sub_uids.c + (default 65536))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 78136390bb..4944c22f49 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -41,6 +42,16 @@ (define %shadow-sample charlie:" (crypt "hey!" "$6$abc") ":17169:::::: nobody:!:0::::::\n")) +(define %subuid-sample + "\ +root:100000:300 +ada:100300:300\n") + +(define %subgid-sample + "\ +root:100000:600 +ada:100600:300\n") + (test-begin "accounts") @@ -135,6 +146,50 @@ (define %shadow-sample read-shadow) port)))) +(test-equal "write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (list (subid-entry + (name "root") + (start 100000) + (count 300)) + (subid-entry + (name "ada") + (start 100300) + (count 300))) + port)))) + +(test-equal "read-subuid + write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (call-with-input-string %subuid-sample + read-subuid) + port)))) + +(test-equal "write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (list (subid-entry + (name "root") + (start 100000) + (count 600)) + (subid-entry + (name "ada") + (start 100600) + (count 300))) + port)))) + +(test-equal "read-subgid + write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (call-with-input-string %subgid-sample + read-subgid) + port)))) + (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) base-commit: 00245fdcd4909d7e6b20fe88f5d089717115adc1 -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 04 Sep 2024 20:36:07 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Giacomo Leidi Cc: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172548214020508 (code B ref 72337); Wed, 04 Sep 2024 20:36:07 +0000 Received: (at 72337) by debbugs.gnu.org; 4 Sep 2024 20:35:40 +0000 Received: from localhost ([127.0.0.1]:35483 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slwj5-0005Ki-Vp for submit@debbugs.gnu.org; Wed, 04 Sep 2024 16:35:40 -0400 Received: from eggs.gnu.org ([209.51.188.92]:50080) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slwj4-0005KU-NK for 72337@debbugs.gnu.org; Wed, 04 Sep 2024 16:35:39 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1slwhw-0002BW-2z; Wed, 04 Sep 2024 16:34:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=/999yhpxu3M9EcZ6EHB5irXEs6FP5Aj7QUeBQEn9/co=; b=CeuC5r/TSx3cLcAYQ/R2 LavhAE3jrdAjtVAF/Z+ztL4gSef90KNZdhMxJqwMxMzmjozOIoZcjsLa6X5wMoMW/gA0rrhSh8ztW NzxANpUYOuc8PKfpZ3xuP3lomBSaySqLRGK4Lcmd3cdEbl/4seyJKpM88FoHfbVZ1GrbxT3WHvDvY Ud9eW70gH+G1H8WywEZl5ftI//haaZ0QYSg2do8w5jzaA7RhHVqxB+1CnkAVWgRMzR7WageuWcn8g zmLu/PUq7aVyfaeLm7r4xlGpyrdKJsxTsfH+6UAsH54QYi5tRN6dTe5YrzIuQhplBRT/isxG8rGcJ wWx+XRo6Z3clzA==; From: Ludovic =?UTF-8?Q?Court=C3=A8s?= In-Reply-To: (Giacomo Leidi's message of "Wed, 21 Aug 2024 00:14:55 +0200") References: Date: Wed, 04 Sep 2024 22:34:25 +0200 Message-ID: <87jzfrb1ke.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Hello, Giacomo Leidi skribis: > This commit adds a new record type, and serializers > and deserializers for it in (gnu build accounts). Each instance of this > record represents one line in either /etc/subuid or /etc/subgid. Since > Shadow uses the same representation for both files, it should be ok if > we do it as well. > > This commit adds also , a user facing representation of > . It is supposed to be usable directly in OS configurations. > > * gnu/build/accounts.scm (subid-entry): New record; > (write-subgid): add serializer for subgids; > (write-subuid): add serializer for subuids; > (read-subgid): add serializer for subgids; > (read-subuid): add serializer for subuids. > * gnu/system/accounts.scm (subid-range): New record. > * test/accounts.scm: Test them. > > Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c LGTM! From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 04 Sep 2024 21:03:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Giacomo Leidi Cc: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172548373527380 (code B ref 72337); Wed, 04 Sep 2024 21:03:02 +0000 Received: (at 72337) by debbugs.gnu.org; 4 Sep 2024 21:02:15 +0000 Received: from localhost ([127.0.0.1]:35548 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slx8o-00077X-N0 for submit@debbugs.gnu.org; Wed, 04 Sep 2024 17:02:15 -0400 Received: from eggs.gnu.org ([209.51.188.92]:48880) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slx8l-00077J-7N for 72337@debbugs.gnu.org; Wed, 04 Sep 2024 17:02:13 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1slx7c-0001Z6-Rb; Wed, 04 Sep 2024 17:01:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=fkZg/yg0G2Lljyl5PvOzeCz1zg5HLW6NrgwhHxKqEC0=; b=JJTNTiFXKV+PNKoW1DoL wpZMq5Dn8b4qg25DZ78bc8iOTrU/sOLwp9PCfNpHTkscPBbubz/dvXsyBZD2dwYkwAnFxza5JzCgz C/h8BrW4u/iXDZIjTlxSQJpyMb0fw2LRVwCcnuMVpu1Kl1RhbaQecX7lToqOh9FD3ZTuHIwIbxiDG 6a4zyRMEHbLE8efbL5wM3JevQdwO5AIl4iSLxq6/Ne3sWK+WdHJjmYEanWXjl4zFflOSknz2yoe8Z iSgFHY35EP1DLNguw7+c70DbsPLlQVu2a9z1AQdgyXxaIcgDS804xEJ7c2GZ+i4zlSYIOobiSfpEf GW1b9LeApY+WKQ==; From: Ludovic =?UTF-8?Q?Court=C3=A8s?= In-Reply-To: <5b955b5c53e8e2c7c3173c87ca17758505e960ae.1724192097.git.goodoldpaul@autistici.org> (Giacomo Leidi's message of "Wed, 21 Aug 2024 00:14:56 +0200") References: <5b955b5c53e8e2c7c3173c87ca17758505e960ae.1724192097.git.goodoldpaul@autistici.org> Date: Wed, 04 Sep 2024 23:00:58 +0200 Message-ID: <878qw7b0c5.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Giacomo Leidi skribis: > * gnu/build/accounts.scm (list-set): New variable; > (%sub-id-min): new variable; > (%sub-id-max): new variable; > (%sub-id-count): new variable; > (sub-id?): new variable; > (subid-range-fits?): new variable; > (subid-range-fits-between?): new variable; > (insert-subid-range): new variable; > (reserve-subids): new variable; > (range->entry): new variable; > (entry->range): new variable; > (allocate-subids): new variable; > (subuid+subgid-databases): new variable. > > * gnu/system/accounts.scm (subid-range-end): New variable; > (subid-range-has-start?): new variable; > (subid-range-less): new variable. > > * test/accounts.scm: Test them. > > Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d Woow, neat! It didn=E2=80=99t occur to me that we=E2=80=99d need a proper = subid allocation mechanism as well. > +(define (list-set lst el k) > + (if (>=3D k (length lst)) > + `(,@lst ,el) > + `(,@(list-head lst k) > + ,el > + ,@(list-tail lst k)))) =E2=80=98length=E2=80=99, =E2=80=98list-ref=E2=80=99, and thus =E2=80=98lis= t-set=E2=80=99 are linear in the size of the list so it=E2=80=99s something we should avoid, unless we know that the lis= ts we=E2=80=99re dealing with are always going to be small. > +;; According to Shadow's libmisc/find_new_sub_uids.c and > +;; libmisc/find_new_sub_gids.c. > +(define %sub-id-min 100000) > +(define %sub-id-max 600100000) > +(define %sub-id-count 65536) [...] > +(define (sub-id? id) > + (and (>=3D id %sub-id-min) > + (< id %sub-id-max))) s/sub-/subordinate-/ > +(define (subid-range-fits? r interval-start interval-end) > + (and (<=3D interval-start > + (subid-range-start r)) > + (<=3D (subid-range-end r) > + interval-end))) Maybe: (within-subordinate-id-range? start end range) ? Also, shouldn=E2=80=99t the first <=3D be >=3D ? Please add docstrings for top-level procedures. > +(define (subid-range-fits-between? r a b) > + (subid-range-fits? r > + (+ (subid-range-start a) 1) > + (- (subid-range-end b) 1))) Maybe: (containing-subordinate-id-range? range a b) ? > +(define (insert-subid-range range lst) We definitely need a docstring, I=E2=80=99m not sure what this is supposed = to do. :-) > + (unless (and (sub-id? range-start) > + (sub-id? range-end)) > + (raise > + (string-append "Subid range of " range-name > + " from " (number->string range-start) " to " > + (number->string range-end) > + " spans over illegal subids. Max allowed is " > + (number->string %sub-id-max) ", min is " > + (number->string %sub-id-min) ".")))) There are two issues: first we need =E2=80=98raise=E2=80=99 from (srfi srfi= -34), not from (guile), since the latter has nothing to do with exceptions. Second, =E2=80=98raise=E2=80=99 takes a SRFI-35 =E2=80=9Cerror condition=E2= =80=9D (essentially a record), not a string. But my suggestion here would be to define specific error conditions, like: (define-condition-type &subordinate-id-error &error) (define-condition-type &subordinate-id-range-error &subordinate-id-error (id subordinate-id-range-error-id)) The latter is what we=E2=80=99d use here. This procedure uses lists a lot, which should probably be avoided as I wrote above. Perhaps a vlist would do, or perhaps a vhash, or a vector. The procedure is also very long; I wonder if it could be further split and/or share code with the existing allocation-related code. > + (test-error "allocate-subids with interleaving, impossible interleavin= g" > + "error" > + ;; Make sure it's impossible to explicitly request impossi= ble allocations Instead of =E2=80=98test-error=E2=80=99, which is currently kinda broken II= RC, I=E2=80=99d suggest a more explicit approach: (test-assert =E2=80=A6 (guard (c ((whatever-error? c) #t)) =E2=80=A6 #f)) Thanks, Ludo=E2=80=99. From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 04 Sep 2024 21:22:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Giacomo Leidi Cc: 72337@debbugs.gnu.org, Maxim Cournoyer , Florian Pelz , Matthew Trzcinski Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172548490531409 (code B ref 72337); Wed, 04 Sep 2024 21:22:01 +0000 Received: (at 72337) by debbugs.gnu.org; 4 Sep 2024 21:21:45 +0000 Received: from localhost ([127.0.0.1]:35563 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slxRg-0008AW-JO for submit@debbugs.gnu.org; Wed, 04 Sep 2024 17:21:44 -0400 Received: from eggs.gnu.org ([209.51.188.92]:32860) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slxRe-0008AD-Ec for 72337@debbugs.gnu.org; Wed, 04 Sep 2024 17:21:43 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1slxQU-0006uz-E2; Wed, 04 Sep 2024 17:20:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=xFW/WOzaXjdwOOqCkbvH+WnOVs5jt5TQKFEINHF0/OU=; b=diMmpdmJ2fGetTtyqLWM xbvhUIY0asZGluKFG6RXyivIRxnt2aDjde73tgnNIZ5Xdg5j4odc5VQWvRbsDjW8wmhAAPW8D04sS Gn60c0ciCqC7OXPOALP8x9evVX6zAE9q5VaeAGqtRDi7b0Ul4fVWdlRFct/FH+p3DPjBtMaTpSSRA L8+RhlLLodvrgVmDnZ3WPeV6d3yXsJ7PYw/oKNuvAJn+1YP4GopgBa2UiE0zZjU/PSzRngRdQqoXo 3fBca3coUksy579aTUVPJfPTpz8oXQLh3PQpSJWRNcHxPxLPCooVTokM6a0ccK03AaF4i+a293ach 5f7Pnswk8Thb0g==; From: Ludovic =?UTF-8?Q?Court=C3=A8s?= In-Reply-To: <8b0b9421e1347e0f0d6ce88c8eb66a5b6296cc0c.1724192097.git.goodoldpaul@autistici.org> (Giacomo Leidi's message of "Wed, 21 Aug 2024 00:14:57 +0200") References: <8b0b9421e1347e0f0d6ce88c8eb66a5b6296cc0c.1724192097.git.goodoldpaul@autistici.org> Date: Wed, 04 Sep 2024 23:20:06 +0200 Message-ID: <87zfon9kvt.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Giacomo Leidi skribis: > This commit adds a Guix System service to handle allocation of subuid > and subgid requests. Users that don't care can just add themselves as a > subid-range and don't need to specify anything but their user name. > Users that care about specific ranges, such as possibly LXD, can specify > a start and a count. > > * doc/guix.texi: Document the new service. > * gnu/build/activation.scm (activate-subuids+subgids): New variable. > * gnu/local.mk: Add gnu/tests/shadow.scm. > * gnu/system/accounts.scm (sexp->subid-range): New variable. > * gnu/system/shadow.scm (%root-subid): New variable; > (subids-configuration): new record; > (subid-range->gexp): new variable; > (assert-valid-subids): new variable; > (delete-duplicate-ranges): new variable; > (subids-activation): new variable; > (subids-extension): new record; > (append-subid-ranges): new variable; > (subids-extension-merge): new variable; > (subids-service-type): new variable. > * gnu/tests/shadow.scm (subids): New system test. > > Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 Nice. > +The @code{(gnu system shadow)} module exposes the > +@code{subids-service-type}, its configuration record > +@code{subids-configuration} and its extension record > +@code{subids-extension}. I think this section should start by defining briefly what a =E2=80=9Csubordinate ID=E2=80=9D is, with a cross-reference to a primary so= urce for that (unfortunately glibc=E2=80=99s manual has nothing about it, so that=E2=80= =99d be Linux man pages I guess), and by giving an idea of what it=E2=80=99s used for. It should use =E2=80=9Csubuid=E2=80=9D and =E2=80=9Csubgid=E2=80=9D only af= ter it has introduced them as abbreviations of =E2=80=9Csubordinate UID=E2=80=9D. > +for the root account to both @code{/etc/subuid} and @code{/etc/subgid}, = possibly s/@code/@file/ > +(define %sub-id-min > + (@@ (gnu build accounts) %sub-id-min)) > +(define %sub-id-max > + (@@ (gnu build accounts) %sub-id-max)) > +(define %sub-id-count > + (@@ (gnu build accounts) %sub-id-count)) Use single =E2=80=98@=E2=80=99 or, better yet, #:use-module the thing. > +(define (assert-valid-subids ranges) > + (cond ((>=3D (fold + 0 (map subid-range-count ranges)) > + (- %sub-id-max %sub-id-min -1)) > + (raise > + (string-append > + "The configured ranges are more than the " > + (number->string > + (- %sub-id-max %sub-id-min -1)) " max allowed."))) Same comment as before regarding =E2=80=98raise=E2=80=99. In this case, you could do: (raise (formatted-message (G_ =E2=80=A6) =E2=80= =A6)). This is done elsewhere in the code. > + (define slurp > + (lambda args > + (let* ((port (apply open-pipe* OPEN_READ args)) > + (output (read-lines port)) > + (status (close-pipe port))) > + output))) > + (let* ((response1 (slurp > + ,(string-append #$coreutils "/bin/cat= ") > + "/etc/subgid")) > + (response2 (slurp > + ,(string-append #$coreutils "/bin/cat= ") > + "/etc/subuid"))) > + (list (string-join response1 "\n") (string-join respon= se2 "\n")))) Instead of running =E2=80=98cat=E2=80=99, I would suggest using: (call-with-input-file "/etc/subuid" get-string-all) or similar; it=E2=80=99s much simpler. Also, it would be nice if the test could actually exercise subordinate IDs, with =E2=80=98newuidmap=E2=80=99 or some such. Is that within reach? Thanks, Ludo=E2=80=99. From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: paul Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 07 Sep 2024 20:45:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 72337@debbugs.gnu.org, Maxim Cournoyer , Florian Pelz , Matthew Trzcinski Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172574187512292 (code B ref 72337); Sat, 07 Sep 2024 20:45:01 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Sep 2024 20:44:35 +0000 Received: from localhost ([127.0.0.1]:57674 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2IM-0003CC-Mz for submit@debbugs.gnu.org; Sat, 07 Sep 2024 16:44:35 -0400 Received: from confino.investici.org ([93.190.126.19]:24785) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2II-0003By-KJ for 72337@debbugs.gnu.org; Sat, 07 Sep 2024 16:44:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1725741860; bh=EC8DchDVsktw5cDAKxB42cyKhkwPv/LORbCqbMNimMg=; h=Date:Subject:To:Cc:References:From:In-Reply-To:From; b=oZWma57xFv4NA38YH/q3GE00EniW+O0f8qC+aBZ8ukAYcHoGPAFeRhrJ5WOASGcxD NkdIEdhP6T+RUV70vxosjjj43CDj1TNYPpeUOFH3x1ccXXbuDqAds+Cir5kVyqw9Gs jbZLWAXp3/bsGntOGOqcPScHutLYhF7USQv6YtS0= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4X1Q7S36zKz11Fl; Sat, 7 Sep 2024 20:44:20 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4X1Q7S1q7xz112F; Sat, 7 Sep 2024 20:44:20 +0000 (UTC) Message-ID: <80b94cc3-bcb3-e5ab-1f2a-2731129874af@autistici.org> Date: Sat, 7 Sep 2024 22:44:19 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 Content-Language: en-US References: <8b0b9421e1347e0f0d6ce88c8eb66a5b6296cc0c.1724192097.git.goodoldpaul@autistici.org> <87zfon9kvt.fsf_-_@gnu.org> From: paul In-Reply-To: <87zfon9kvt.fsf_-_@gnu.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Score: -2.6 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.6 (---) Hi Ludo’ , I'm sending an updated v4 patchset that should address most your comments. One point I'm not sure about is still how to use newuidmap. I've added a smoke test checking the content of /proc/self/uid_map inside a podman unshare command. I'm not sure that is sufficient but for a full Guile implementation I would wait for another issue if you agree. I still have to find a reliable smoke test. This is something I've been trying, without success so far :( . (use-modules (ice-9 popen)              ;(ice-9 rdelim)              ) (define pid (primitive-fork)) (if (= 0 pid)     (let ((port (pk 'port (open-output-pipe "bash"))))       (sleep 1)       (display "whoami\n" port)       (display "cat /proc/self/uid_map\n" port)       (display "cat /proc/self/gid_map\n" port)       (if (not (eqv? 0 (status:exit-val (close-pipe port))))           (error "Cannot run command")))     (begin       (system* "newuidmap" (number->string pid) "paul" "165536" "65536"))) Thank you for all your help in polishing this service, giacomo From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v4 1/3] accounts: Add /etc/subuid and /etc/subgid support. References: In-Reply-To: Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 07 Sep 2024 20:53:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172574232714048 (code B ref 72337); Sat, 07 Sep 2024 20:53:02 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Sep 2024 20:52:07 +0000 Received: from localhost ([127.0.0.1]:57679 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2Pe-0003eT-Nd for submit@debbugs.gnu.org; Sat, 07 Sep 2024 16:52:07 -0400 Received: from confino.investici.org ([93.190.126.19]:62493) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2Pc-0003eF-Jt for 72337@debbugs.gnu.org; Sat, 07 Sep 2024 16:52:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1725742322; bh=eb+5clUKO/1jGXfV4k9QcgTp8DbrUa9GLwE/7rDoo10=; h=From:To:Cc:Subject:Date:From; b=jA7HTGnSdygI48ICJZgxgJP6M3zSBF35XvS7Sz8MgDhi+vHZwLkI0FSREUzBf/ggA 0HtTDBDFVAOGx4Hw8smllHxY2eOwO8Bkm+erqhyK+s+0g5tMyOgF+5rK2fqJSY+jWc VwGT/pppo2aeQj+1wabHALIJLvOaVcxSHH7kEre8= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4X1QJL5wT6z11Fd; Sat, 7 Sep 2024 20:52:02 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4X1QJL537Fz11FW; Sat, 7 Sep 2024 20:52:02 +0000 (UTC) From: Giacomo Leidi Date: Sat, 7 Sep 2024 22:51:47 +0200 Message-ID: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a new record type, and serializers and deserializers for it in (gnu build accounts). Each instance of this record represents one line in either /etc/subuid or /etc/subgid. Since Shadow uses the same representation for both files, it should be ok if we do it as well. This commit adds also , a user facing representation of . It is supposed to be usable directly in OS configurations. * gnu/build/accounts.scm (subid-entry): New record; (write-subgid): add serializer for subgids; (write-subuid): add serializer for subuids; (read-subgid): add serializer for subgids; (read-subuid): add serializer for subuids. * gnu/system/accounts.scm (subid-range): New record. * test/accounts.scm: Test them. Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c Signed-off-by: Giacomo Leidi --- gnu/build/accounts.scm | 37 ++++++++++++++++++++++++--- gnu/system/accounts.scm | 17 +++++++++++++ tests/accounts.scm | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index fa6f454b5e..ea8c69f205 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019, 2021, 2023 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -51,13 +52,23 @@ (define-module (gnu build accounts) group-entry-gid group-entry-members + subid-entry + subid-entry? + subid-entry-name + subid-entry-start + subid-entry-count + %password-lock-file write-group write-passwd write-shadow + write-subgid + write-subuid read-group read-passwd read-shadow + read-subgid + read-subuid %id-min %id-max @@ -68,11 +79,12 @@ (define-module (gnu build accounts) ;;; Commentary: ;;; -;;; This modules provides functionality equivalent to the C library's +;;; This module provides functionality equivalent to the C library's ;;; , , and routines, as well as a subset of the ;;; functionality of the Shadow command-line tools. It can parse and write -;;; /etc/passwd, /etc/shadow, and /etc/group. It can also take care of UID -;;; and GID allocation in a way similar to what 'useradd' does. +;;; /etc/passwd, /etc/shadow, /etc/group, /etc/subuid and /etc/subgid. It can +;;; also take care of UID and GID allocation in a way similar to what 'useradd' +;;; does. The same goes for sub UID and sub GID allocation. ;;; ;;; The benefit is twofold: less code is involved, and the ID allocation ;;; strategy and state preservation is made explicit. @@ -225,6 +237,17 @@ (define-database-entry ; (serialization list->comma-separated comma-separated->list) (default '()))) +(define-database-entry ; + subid-entry make-subid-entry + subid-entry? + (serialization #\: subid-entry->string string->subid-entry) + + (name subid-entry-name) + (start subid-entry-start + (serialization number->string string->number)) + (count subid-entry-count + (serialization number->string string->number))) + (define %password-lock-file ;; The password database lock file used by libc's 'lckpwdf'. Users should ;; grab this lock with 'with-file-lock' when they access the databases. @@ -265,6 +288,10 @@ (define write-shadow (database-writer "/etc/shadow" #o600 shadow-entry->string)) (define write-group (database-writer "/etc/group" #o644 group-entry->string)) +(define write-subuid + (database-writer "/etc/subuid" #o644 subid-entry->string)) +(define write-subgid + (database-writer "/etc/subgid" #o644 subid-entry->string)) (define (database-reader file string->entry) (lambda* (#:optional (file-or-port file)) @@ -287,6 +314,10 @@ (define read-shadow (database-reader "/etc/shadow" string->shadow-entry)) (define read-group (database-reader "/etc/group" string->group-entry)) +(define read-subuid + (database-reader "/etc/subuid" string->subid-entry)) +(define read-subgid + (database-reader "/etc/subgid" string->subid-entry)) ;;; diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 586cff1842..9a006c188d 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -39,6 +40,12 @@ (define-module (gnu system accounts) user-group-id user-group-system? + subid-range + subid-range? + subid-range-name + subid-range-start + subid-range-count + sexp->user-account sexp->user-group @@ -85,6 +92,16 @@ (define-record-type* (system? user-group-system? ; Boolean (default #f))) +(define-record-type* + subid-range make-subid-range + subid-range? + (name subid-range-name) + (start subid-range-start (default #f)) ; number + (count subid-range-count ; number + ; from find_new_sub_gids.c and + ; find_new_sub_uids.c + (default 65536))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 78136390bb..4944c22f49 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -41,6 +42,16 @@ (define %shadow-sample charlie:" (crypt "hey!" "$6$abc") ":17169:::::: nobody:!:0::::::\n")) +(define %subuid-sample + "\ +root:100000:300 +ada:100300:300\n") + +(define %subgid-sample + "\ +root:100000:600 +ada:100600:300\n") + (test-begin "accounts") @@ -135,6 +146,50 @@ (define %shadow-sample read-shadow) port)))) +(test-equal "write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (list (subid-entry + (name "root") + (start 100000) + (count 300)) + (subid-entry + (name "ada") + (start 100300) + (count 300))) + port)))) + +(test-equal "read-subuid + write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (call-with-input-string %subuid-sample + read-subuid) + port)))) + +(test-equal "write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (list (subid-entry + (name "root") + (start 100000) + (count 600)) + (subid-entry + (name "ada") + (start 100600) + (count 300))) + port)))) + +(test-equal "read-subgid + write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (call-with-input-string %subgid-sample + read-subgid) + port)))) + (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) base-commit: 4ba9f3e0f1484524f91ca1f7ec3a4ce7cb8873ff -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v4 2/3] account: Add /etc/subid and /etc/subgid allocation logic. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 07 Sep 2024 20:53:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172574232814055 (code B ref 72337); Sat, 07 Sep 2024 20:53:02 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Sep 2024 20:52:08 +0000 Received: from localhost ([127.0.0.1]:57681 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2Pf-0003eX-EP for submit@debbugs.gnu.org; Sat, 07 Sep 2024 16:52:08 -0400 Received: from confino.investici.org ([93.190.126.19]:59135) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2Pc-0003eH-T4 for 72337@debbugs.gnu.org; Sat, 07 Sep 2024 16:52:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1725742323; bh=6ugOMZGSXDJjz+6Ma9hN3Meqh+YRJ4sYm4AGwbmHS1M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JnjCWpBpsWbUHM2CLpazc1MTA+GpfIrHno7cwLmht7m+mwZnxT09nr1PwnUc/G4/Q Bq9vkt+zIgpoUxwc10yHxmCGzwGYugiNTiw3SOnnJ2eoLkc2IeP5sE2Mo+EqTty2rb l8Vik/YCj3MWuiyMyS/c3yuVgUPNQUwfxgaAxFMY= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4X1QJM0vxVz11Fl; Sat, 7 Sep 2024 20:52:03 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4X1QJM04ctz11FW; Sat, 7 Sep 2024 20:52:02 +0000 (UTC) From: Giacomo Leidi Date: Sat, 7 Sep 2024 22:51:48 +0200 Message-ID: <2771695a2527240c89c0ba6879aeda0d4ab840ab.1725742309.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> References: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds allocation logic for subid ranges. Subid ranges are ranges of contiguous subids that are mapped to a user in the host system. This patch implements a flexible allocation algorithm allowing users that do not want (or need) to specify details of the subid ranges that they are requesting to avoid doing so, while upholding requests of users that need to have specific ranges. * gnu/build/accounts.scm (list-set): New variable; (%subordinate-id-min): new variable; (%subordinate-id-max): new variable; (%subordinate-id-count): new variable; (subordinate-id?): new variable; (within-interval?): new variable; (insert-subid-range): new variable; (reserve-subids): new variable; (range->entry): new variable; (entry->range): new variable; (allocate-subids): new variable; (subuid+subgid-databases): new variable. * gnu/system/accounts.scm (subid-range-end): New variable; (subid-range-has-start?): new variable; (subid-range-less): new variable. * test/accounts.scm: Test them. Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d Signed-off-by: Giacomo Leidi --- gnu/build/accounts.scm | 187 +++++++++++++++++++++++++++++++++++++++- gnu/system/accounts.scm | 30 +++++++ tests/accounts.scm | 152 ++++++++++++++++++++++++++++++++ 3 files changed, 368 insertions(+), 1 deletion(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index ea8c69f205..be981fca38 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -25,6 +25,8 @@ (define-module (gnu build accounts) #:use-module (srfi srfi-11) #:use-module (srfi srfi-19) #:use-module (srfi srfi-26) + #:use-module (srfi srfi-34) + #:use-module (srfi srfi-35) #:use-module (ice-9 match) #:use-module (ice-9 vlist) #:use-module (ice-9 rdelim) @@ -74,8 +76,19 @@ (define-module (gnu build accounts) %id-max %system-id-min %system-id-max + %subordinate-id-min + %subordinate-id-max + %subordinate-id-count - user+group-databases)) + &subordinate-id-error + subordinate-id-error? + &subordinate-id-range-error + subordinate-id-range-error? + subordinate-id-range-error-message + subordinate-id-range-error-ranges + + user+group-databases + subuid+subgid-databases)) ;;; Commentary: ;;; @@ -91,6 +104,18 @@ (define-module (gnu build accounts) ;;; ;;; Code: + +;;; +;;; General utilities. +;;; + +(define (vlist-set vlst el k) + (if (>= k (vlist-length vlst)) + (vlist-append vlst (vlist-cons el vlist-null)) + (vlist-append + (vlist-take vlst k) + (vlist-cons el (vlist-drop vlst k))))) + ;;; ;;; Machinery to define user and group databases. @@ -342,6 +367,19 @@ (define %id-max 60000) (define %system-id-min 100) (define %system-id-max 999) +;; According to Shadow's libmisc/find_new_sub_uids.c and +;; libmisc/find_new_sub_gids.c. +(define %subordinate-id-min 100000) +(define %subordinate-id-max 600100000) +(define %subordinate-id-count 65536) + +(define-condition-type &subordinate-id-error &error + subordinate-id-error?) +(define-condition-type &subordinate-id-range-error &subordinate-id-error + subordinate-id-range-error? + (message subordinate-id-range-error-message) + (ranges subordinate-id-range-error-ranges)) + (define (system-id? id) (and (> id %system-id-min) (<= id %system-id-max))) @@ -350,6 +388,10 @@ (define (user-id? id) (and (>= id %id-min) (< id %id-max))) +(define (subordinate-id? id) + (and (>= id %subordinate-id-min) + (< id %subordinate-id-max))) + (define* (allocate-id assignment #:key system?) "Return two values: a newly allocated ID, and an updated record based on ASSIGNMENT. If SYSTEM? is true, return a system ID." @@ -405,6 +447,90 @@ (define* (reserve-ids allocation ids #:key (skip? #t)) (allocation-ids allocation) ids)))) +(define (within-interval? start end range) + "Returns #t when RANGE is included in the interval +bounded by START and END. Both ends of the interval +are included in the comparison." + (unless (subid-range-has-start? range) + (raise + (condition + (&subordinate-id-range-error + (ranges (list range)) + (message + "Subid ranges should have a start to be tested within +an interval."))))) + (and (<= start + (subid-range-start range)) + (<= (subid-range-end range) + end))) + +(define (insert-subid-range range vlst) + "Allocates a range of subids in VLST, based on RANGE. Ranges +that do not explicitly specify a start subid are fitted based on +their size. This procedure assumes VLIST is sorted by SUBID-RANGE-LESS and +that all VLST members have a start." + (define* (actualize r #:key (start %subordinate-id-min)) + (if (subid-range-has-start? r) + r + (subid-range + (inherit r) + (start start)))) + + (define vlst-length (vlist-length vlst)) + (define range-name (subid-range-name range)) + (define range-start (subid-range-start range)) + (define range-end (subid-range-end range)) + + (when (subid-range-has-start? range) + (unless (and (subordinate-id? range-start) + (subordinate-id? range-end)) + (raise + (condition + (&subordinate-id-range-error + (ranges (list range)) + (message + (string-append "Subid range of " range-name + " from " (number->string range-start) " to " + (number->string range-end) + " spans over illegal subids. Max allowed is " + (number->string %subordinate-id-max) ", min is " + (number->string %subordinate-id-min) "."))))))) + + (let loop ((i 0) + (start %subordinate-id-min) + (end (if (< vlst-length 1) + %subordinate-id-max + (- (subid-range-start + (vlist-ref vlst 0)) + 1)))) + (define actual-range + (actualize range #:start start)) + (cond + ((> i vlst-length) + (raise + (condition + (&subordinate-id-range-error + (ranges (list range)) + (message + (string-append "Couldn't fit " range-name + ", reached end of list.")))))) + ((within-interval? start end actual-range) + (vlist-set vlst actual-range i)) + (else + (loop (+ i 1) + (+ 1 (subid-range-end + (vlist-ref vlst (if (= i vlst-length) (- i 1) i)))) + (if (>= i (- vlst-length 1)) + %subordinate-id-max + (- (subid-range-start + (vlist-ref vlst (+ i 1))) + 1))))))) + +(define* (reserve-subids allocation ranges) + "Mark the subid ranges listed in RANGES as reserved in ALLOCATION. +ALLOCATION is supposed to be sorted by SUBID-RANGE-LESS." + (vlist-fold insert-subid-range allocation ranges)) + (define (allocated? allocation id) "Return true if ID is already allocated as part of ALLOCATION." (->bool (vhash-assv id (allocation-ids allocation)))) @@ -540,6 +666,39 @@ (define* (allocate-passwd users groups #:optional (current-passwd '())) uids users))) +(define (range->entry range) + (subid-entry + (name (subid-range-name range)) + (start (subid-range-start range)) + (count (subid-range-count range)))) + +(define (entry->range entry) + (subid-range + (name (subid-entry-name entry)) + (start (subid-entry-start entry)) + (count (subid-entry-count entry)))) + +(define* (allocate-subids ranges #:optional (current-ranges '())) + "Return a list of subids entries for RANGES, a list of . Members +for each group are taken from MEMBERS, a vhash that maps ranges names to member +names. IDs found in CURRENT-RANGES, a list of subid entries, are reused." + (when (any (compose not subid-range-has-start?) current-ranges) + (raise + (condition + (&subordinate-id-range-error + (ranges current-ranges) + (message "Loaded ranges are supposed to have a start, but at least one does not."))))) + (define subids + ;; Mark all the currently used IDs and the explicitly requested IDs as + ;; reserved. + (reserve-subids (reserve-subids vlist-null + (list->vlist current-ranges)) + (list->vlist + (stable-sort ranges + subid-range-less)))) + + (map range->entry (vlist->list subids))) + (define* (days-since-epoch #:optional (current-time current-time)) "Return the number of days elapsed since the 1st of January, 1970." (let* ((now (current-time time-utc)) @@ -615,3 +774,29 @@ (define* (user+group-databases users groups #:current-time current-time)) (values group-entries passwd-entries shadow-entries)) + +(define* (subuid+subgid-databases subuids subgids + #:key + (current-subuids + (map entry->range + (empty-if-not-found read-subuid))) + (current-subgids + (map entry->range + (empty-if-not-found read-subgid)))) + "Return two values: the list of subgid entries, and the list of subuid entries +corresponding to SUBUIDS and SUBGIDS. +Preserve stateful bits from CURRENT-SUBUIDS and CURRENT-SUBGIDS." + + (define (range-eqv? a b) + (string=? (subid-range-name a) + (subid-range-name b))) + + (define subuid-entries + (allocate-subids + (lset-difference range-eqv? subuids current-subuids) current-subuids)) + + (define subgid-entries + (allocate-subids + (lset-difference range-eqv? subgids current-subgids) current-subgids)) + + (values subuid-entries subgid-entries)) diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 9a006c188d..1b88ca301f 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -45,6 +45,9 @@ (define-module (gnu system accounts) subid-range-name subid-range-start subid-range-count + subid-range-end + subid-range-has-start? + subid-range-less sexp->user-account sexp->user-group @@ -102,6 +105,33 @@ (define-record-type* ; find_new_sub_uids.c (default 65536))) +(define (subid-range-end range) + "Returns the last subid referenced in RANGE." + (and + (subid-range-has-start? range) + (+ (subid-range-start range) + (subid-range-count range) + -1))) + +(define (subid-range-has-start? range) + "Returns #t when RANGE's start is a number." + (number? (subid-range-start range))) + +(define (subid-range-less a b) + "Returns #t when subid range A either starts before, or is more specific +than B. When it is not possible to determine whether a range is more specific +w.r.t. another range their names are compared alphabetically." + (define start-a (subid-range-start a)) + (define start-b (subid-range-start b)) + (cond ((and (not start-a) (not start-b)) + (string< (subid-range-name a) + (subid-range-name b))) + ((and start-a start-b) + (< start-a start-b)) + (else + (and start-a + (not start-b))))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 4944c22f49..3d038568df 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -21,6 +21,7 @@ (define-module (test-accounts) #:use-module (gnu build accounts) #:use-module (gnu system accounts) #:use-module (srfi srfi-19) + #:use-module (srfi srfi-34) #:use-module (srfi srfi-64) #:use-module (ice-9 vlist) #:use-module (ice-9 match)) @@ -193,6 +194,7 @@ (define %subgid-sample (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) +(define allocate-subids (@@ (gnu build accounts) allocate-subids)) (test-equal "allocate-groups" ;; Allocate GIDs in a stateless fashion. @@ -257,6 +259,112 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (list (group-entry (name "d") (gid (- %id-max 2)))))) +(test-equal "allocate-subids" + ;; Allocate sub IDs in a stateless fashion. + (list (subid-entry (name "root") (start %subordinate-id-min) (count 100)) + (subid-entry (name "t") (start 100100) (count 899)) + (subid-entry (name "x") (start 100999) (count 200))) + (allocate-subids (list + (subid-range (name "x") (count 200)) + (subid-range (name "t") (count 899))) + (list (subid-range (name "root") + (start %subordinate-id-min) + (count 100))))) + +(test-equal "allocate-subids with requested IDs ranges" + ;; Make sure the requested sub ID for "k" and "root" are honored. + (list (subid-entry (name "x") (start %subordinate-id-min) (count 200)) + (subid-entry (name "k") (start (+ %subordinate-id-min 300)) (count 100)) + (subid-entry (name "t") (start (+ %subordinate-id-min 500)) (count 899)) + (subid-entry (name "root") (start (+ %subordinate-id-min 2500)) (count 100))) + + (allocate-subids (list + (subid-range (name "root") (start (+ %subordinate-id-min 2500)) (count 100)) + (subid-range (name "k") (start (+ %subordinate-id-min 300)) (count 100))) + (list + (subid-range (name "x") (start %subordinate-id-min) (count 200)) + (subid-range (name "t") (start (+ %subordinate-id-min 500)) (count 899))))) + +(let ((inputs+currents + (list + (list + "ranges must have start" + (list (subid-range (name "m"))) + (list (subid-range (name "x"))) + "Loaded ranges are supposed to have a start, but at least one does not.") + (list + "ranges must fall within allowed max min subids" + (list (subid-range (name "m") + (start (- %subordinate-id-min 1)) + (count + (+ %subordinate-id-max %subordinate-id-min)))) + (list + (subid-range (name "root") (start %subordinate-id-min))) + "Subid range of m from 99999 to 600299998 spans over illegal subids. Max allowed is 600100000, min is 100000.")))) + + ;; Make sure it's impossible to explicitly request impossible allocations + (for-each + (match-lambda + ((test-name ranges current-ranges message) + (test-assert (string-append "allocate-subids, impossible allocations - " + test-name) + (guard (c ((and (subordinate-id-range-error? c) + (string=? message (subordinate-id-range-error-message c))) + #t)) + (allocate-subids ranges current-ranges) + #f)))) + inputs+currents)) + +(test-equal "allocate-subids with interleaving" + ;; Make sure the requested sub ID for "m" is honored and + ;; for "l" and "i" are correctly deduced. + (list (subid-entry (name "x") (start %subordinate-id-min) (count 200)) + (subid-entry (name "l") (start (+ %subordinate-id-min 200)) (count 1)) + (subid-entry (name "m") (start (+ %subordinate-id-min 201)) (count 27)) + (subid-entry (name "i") (start (+ %subordinate-id-min 228)) (count 2)) + (subid-entry (name "root") (start (+ %subordinate-id-min 231)) (count 100))) + (allocate-subids (list + (subid-range (name "m") (start (+ %subordinate-id-min 201)) (count 27)) + (subid-range (name "l") (count 1)) + (subid-range (name "i") (count 2))) + (list + (subid-range (name "x") (start %subordinate-id-min) (count 200)) + (subid-range (name "root") (start (+ %subordinate-id-min 231)) (count 100))))) + +(let ((inputs+currents + (list + ;; Try impossible before + (list + (list (subid-range (name "m") (start %subordinate-id-min) (count 16))) + (list + (subid-range (name "x") (start (+ 15 %subordinate-id-min)) (count 150))) + "Couldn't fit m, reached end of list.") + ;; Try impossible after + (list + (list (subid-range (name "m") (start %subordinate-id-min) (count 30))) + (list + (subid-range (name "x") (start (+ 29 %subordinate-id-min)) (count 150))) + "Couldn't fit m, reached end of list.") + ;; Try impossible between + (list + (list (subid-range (name "m") (start 100200) (count 500))) + (list + (subid-range (name "root") (start %subordinate-id-min) (count 100)) + (subid-range (name "x") (start (+ %subordinate-id-min 500)) (count 100))) + "Couldn't fit m, reached end of list.")))) + + ;; Make sure it's impossible to explicitly request impossible allocations + (for-each + (match-lambda + ((ranges current-ranges message) + (test-assert "allocate-subids with interleaving, impossible interleaving" + (guard (c ((and (subordinate-id-range-error? c) + (string=? message (subordinate-id-range-error-message c))) + #t)) + (allocate-subids ranges current-ranges) + #f)))) + inputs+currents)) + (test-equal "allocate-passwd" ;; Allocate UIDs in a stateless fashion. (list (password-entry (name "alice") (uid %id-min) (gid 1000) @@ -376,4 +484,48 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (make-time type 0 (* 24 3600 100))))) list)) +(test-equal "subuid+subgid-databases" + ;; The whole process. + (list (list (subid-entry (name "root") + (start %subordinate-id-min) + (count 100)) + (subid-entry (name "alice") + (start (+ %subordinate-id-min 100)) + (count 200)) + (subid-entry (name "bob") + (start (+ %subordinate-id-min 100 200)) + (count 200))) + (list + (subid-entry (name "root") + (start %subordinate-id-min) + (count 200)) + (subid-entry (name "alice") + (start (+ %subordinate-id-min 200)) + (count 400)) + (subid-entry (name "charlie") + (start (+ %subordinate-id-min 200 400)) + (count 300)))) + (call-with-values + (lambda () + (subuid+subgid-databases + (list (subid-range (name "root") + (start %subordinate-id-min) + (count 100)) + (subid-range (name "alice") + (start (+ %subordinate-id-min 100)) + (count 200)) + (subid-range (name "bob") + (count 200))) + (list + (subid-range (name "alice") + (count 400)) + (subid-range (name "charlie") + (count 300))) + #:current-subgids + (list (subid-range (name "root") + (start %subordinate-id-min) + (count 200))) + #:current-subuids '())) + list)) + (test-end "accounts") -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v4 3/3] system: Add /etc/subuid and /etc/subgid support. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: pelzflorian@pelzflorian.de, ludo@gnu.org, maxim.cournoyer@gmail.com, guix-patches@gnu.org Resent-Date: Sat, 07 Sep 2024 20:53:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi , Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Maxim Cournoyer X-Debbugs-Original-Xcc: Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Maxim Cournoyer Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172574233714078 (code B ref 72337); Sat, 07 Sep 2024 20:53:03 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Sep 2024 20:52:17 +0000 Received: from localhost ([127.0.0.1]:57684 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2Pn-0003ey-Jw for submit@debbugs.gnu.org; Sat, 07 Sep 2024 16:52:16 -0400 Received: from confino.investici.org ([93.190.126.19]:22707) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sn2Pk-0003ep-G6 for 72337@debbugs.gnu.org; Sat, 07 Sep 2024 16:52:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1725742323; bh=v01i0/jI6+YBJY4LQkaWgUGU5YX2R8Tom7IxU30tvrU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JO+Z68u1pXTeBmOAy1ELN3QtZosqC+OXU9Y191g4qcLE9Zb68V7BbJify74M6AB0i 2i4o2eKBef5BmGrS/LcORtfj448g6oUy8J2TsAHweSzfSQZ/TGv9tNPkxcjjRFhsOB XkxG2fwPnj+CwaiMcqNrER0DaXHZxuZQ3cJtw24M= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4X1QJM3M77z11Fq; Sat, 7 Sep 2024 20:52:03 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4X1QJM2RB6z11FW; Sat, 7 Sep 2024 20:52:03 +0000 (UTC) From: Giacomo Leidi Date: Sat, 7 Sep 2024 22:51:49 +0200 Message-ID: <479d5a6eb25e4a4156fa04774ad8800f38ea08ec.1725742309.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> References: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a Guix System service to handle allocation of subuid and subgid requests. Users that don't care can just add themselves as a subid-range and don't need to specify anything but their user name. Users that care about specific ranges, such as possibly LXD, can specify a start and a count. * doc/guix.texi: Document the new service. * gnu/build/activation.scm (activate-subuids+subgids): New variable. * gnu/local.mk: Add gnu/tests/shadow.scm. * gnu/system/accounts.scm (sexp->subid-range): New variable. * gnu/system/shadow.scm (%root-subid): New variable; (subids-configuration): new record; (subid-range->gexp): new variable; (assert-valid-subids): new variable; (delete-duplicate-ranges): new variable; (subids-activation): new variable; (subids-extension): new record; (append-subid-ranges): new variable; (subids-extension-merge): new variable; (subids-service-type): new variable. * gnu/tests/shadow.scm (subids): New system test. Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 Signed-off-by: Giacomo Leidi --- doc/guix.texi | 180 +++++++++++++++++++++++++++++++++ gnu/build/activation.scm | 19 ++++ gnu/local.mk | 1 + gnu/system/accounts.scm | 10 ++ gnu/system/shadow.scm | 211 ++++++++++++++++++++++++++++++++++++++- gnu/tests/shadow.scm | 180 +++++++++++++++++++++++++++++++++ 6 files changed, 599 insertions(+), 2 deletions(-) create mode 100644 gnu/tests/shadow.scm diff --git a/doc/guix.texi b/doc/guix.texi index 981ffb8c58..16fd415b32 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -41683,6 +41683,186 @@ Miscellaneous Services @end deftp +@c %end of fragment + +@cindex Subids +@subsubheading Subid Service + +Among the virtualization facilities implemented by the Linux kernel, the is the +concept of subordinate IDs. Subordinate IDs allow for mapping user and group +IDs inside process namespaces to user and group IDs of the host system. +Subordinate user ID ranges (subids) allow to map virtual user IDs inside +containers to the user ID of an unprivileged user of the host system. +Subordinate group ID ranges (subgids), instead map virtual group IDs to the +group ID of an unprivileged user on the host system. You can access +@code{subuid(5)} and @code{subgid(5)} Linux man pages for more details. + +The @code{(gnu system shadow)} module exposes the +@code{subids-service-type}, its configuration record +@code{subids-configuration} and its extension record +@code{subids-extension}. + +With @code{subids-service-type}, subuids and subgids ranges can be reserved for +users that desire so: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Users (definitely other services), usually, are supposed to extend the service +instead of adding subids directly to @code{subids-configuration}, unless the +want to change the default behavior for root. With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @file{/etc/subuid} and @file{/etc/subgid}, possibly +starting at the minimum possible subid. Otherwise the root subuids and subgids +ranges are fitted wherever possible. + +The above configuration will yield the following: + +@example +# cat /etc/subgid +root:100000:65536 +alice:165536:65536 +# cat /etc/subuid +root:100000:700 +bob:100700:65536 +alice:166236:65536 +@end example + +@c %start of fragment + +@deftp {Data Type} subids-configuration + +With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @file{/etc/subuid} and @file{/etc/subgid}, possibly +starting at the minimum possible subid. To disable the default behavior and +provide your own definition for the root subid ranges you can set to @code{#f} +the @code{add-root?} field: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (service subids-service-type + (subids-configuration + (add-root? #f) + (subgids + (subid-range (name "root") + (start 120000) + (count 100))) + (subuids + (subid-range (name "root") + (start 120000) + (count 100))))) + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Available @code{subids-configuration} fields are: + +@table @asis +@item @code{add-root?} (default: @code{#t}) (type: boolean) +Whether to automatically configure subuids and subgids for root. + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subgid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subuid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subids-extension + +Available @code{subids-extension} fields are: + +@table @asis + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subgids}. Entries with the same name are deduplicated +upon merging. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subuids}. Entries with the same name are deduplicated +upon merging. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subid-range + +The @code{subid-range} record is defined at @code{(gnu system accounts)}. +Available fields are: + +@table @asis + +@item @code{name} (type: string) +The name of the user or group that will own this range. + +@item @code{start} (default: @code{#f}) (type: integer) +The first requested subid. When false the first available subid with enough +contiguous subids will be assigned. + +@item @code{count} (default: @code{#f}) (type: integer) +The number of total allocated subids. When #f the default of 65536 will be +assumed . + +@end table + +@end deftp + @c %end of fragment @node Privileged Programs diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index d1a2876a96..5236fbb403 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -10,6 +10,7 @@ ;;; Copyright © 2021 Brice Waegeneire ;;; Copyright © 2022 Tobias Geerinckx-Rice ;;; Copyright © 2024 Nicolas Graves +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -40,6 +41,7 @@ (define-module (gnu build activation) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) #:export (activate-users+groups + activate-subuids+subgids activate-user-home activate-etc activate-privileged-programs @@ -227,6 +229,23 @@ (define (activate-users+groups users groups) (chmod directory #o555)) (duplicates (map user-account-home-directory system-accounts)))) +(define (activate-subuids+subgids subuids subgids) + "Make sure SUBUIDS (a list of subid range records) and SUBGIDS (a list of +subid range records) are all available." + + ;; Take same lock as Shadow while we read + ;; and write the databases. This ensures there's no race condition with + ;; other tools that might be accessing it at the same time. + (with-file-lock "/etc/subgid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subgid subgid))) + + (with-file-lock "/etc/subuid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subuid subuid)))) + (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless they already exist." diff --git a/gnu/local.mk b/gnu/local.mk index ed630041ff..b36873f28a 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -841,6 +841,7 @@ GNU_SYSTEM_MODULES = \ %D%/tests/samba.scm \ %D%/tests/security.scm \ %D%/tests/security-token.scm \ + %D%/tests/shadow.scm \ %D%/tests/singularity.scm \ %D%/tests/ssh.scm \ %D%/tests/telephony.scm \ diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 1b88ca301f..f63d7f96bd 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -51,6 +51,7 @@ (define-module (gnu system accounts) sexp->user-account sexp->user-group + sexp->subid-range default-shell)) @@ -159,3 +160,12 @@ (define (sexp->user-account sexp) (create-home-directory? create-home-directory?) (shell shell) (password password) (system? system?))))) + +(define (sexp->subid-range sexp) + "Take SEXP, a tuple as returned by 'subid-range->gexp', and turn it into a +subid-range record." + (match sexp + ((name start count) + (subid-range (name name) + (start start) + (count count))))) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index d9f13271d8..48eca2564f 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen ;;; Copyright © 2020, 2023 Efraim Flashner ;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -28,6 +29,10 @@ (define-module (gnu system shadow) #:use-module (guix modules) #:use-module (guix sets) #:use-module (guix ui) + #:use-module ((gnu build accounts) + #:select (%subordinate-id-count + %subordinate-id-max + %subordinate-id-min)) #:use-module (gnu system accounts) #:use-module (gnu services) #:use-module (gnu services shepherd) @@ -77,7 +82,20 @@ (define-module (gnu system shadow) %base-user-accounts account-service-type - account-service)) + account-service + + subids-configuration + subids-configuration? + subids-configuration-add-root? + subids-configuration-subgids + subids-configuration-subuids + + subids-extension + subids-extension? + subids-extension-subgids + subids-extension-subuids + + subids-service-type)) ;;; Commentary: ;;; @@ -380,7 +398,7 @@ (define (assert-valid-users/groups users groups) ;;; -;;; Service. +;;; Accounts Service. ;;; (define (user-group->gexp group) @@ -521,4 +539,193 @@ (define (account-service accounts+groups skeletons) (service account-service-type (append skeletons accounts+groups))) + +;;; +;;; Subids Service. +;;; + +(define* (%root-subid #:optional (start %subordinate-id-min) (count %subordinate-id-count)) + (subid-range + (name "root") + (start start) + (count count))) + +(define-record-type* + subids-configuration make-subids-configuration + subids-configuration? + this-subids-configuration + + (add-root? subids-configuration-add-root? ; boolean + (default #t)) + (subgids subids-configuration-subgids ; list of + (default '())) + (subuids subids-configuration-subuids ; list of + (default '()))) + +(define (subid-range->gexp range) + "Turn RANGE, a object, into a list-valued gexp suitable for +'activate-subuids+subgids'." + (define count (subid-range-count range)) + #~`(#$(subid-range-name range) + #$(subid-range-start range) + #$(if (and (number? count) + (> count 0)) + count + %subordinate-id-count))) + +(define (assert-valid-subids ranges) + (cond ((>= (fold + 0 (map subid-range-count ranges)) + (- %subordinate-id-max %subordinate-id-min -1)) + (raise + (formatted-message + (G_ + "The configured ranges are more than the ~a max allowed.") + (- %subordinate-id-max %subordinate-id-min -1)))) + ((any (lambda (r) + (define start (subid-range-start r)) + (and start + (< start %subordinate-id-min))) + ranges) + (raise + (formatted-message + (G_ + "One subid-range starts before the minimum allowed sub id ~a.") + %subordinate-id-min))) + ((any (lambda (r) + (define end (subid-range-end r)) + (and end + (> end %subordinate-id-max))) + ranges) + (raise + (formatted-message + (G_ + "One subid-range ends after the maximum allowed sub id ~a.") + %subordinate-id-max))) + ((any (compose null? subid-range-name) + ranges) + (raise + (formatted-message + (G_ + "One subid-range has a null name.")))) + ((any (compose string-null? subid-range-name) + ranges) + (raise + (formatted-message + (G_ + "One subid-range has a name equal to the empty string.")))) + (else #t))) + +(define (delete-duplicate-ranges ranges) + (delete-duplicates ranges + (lambda args + (apply string=? (map subid-range-name ranges))))) + +(define (subids-activation config) + "Return a gexp that activates SUBUIDS+SUBGIDS, a list of +objects." + (define (add-root-when-missing ranges) + (define sorted-ranges + (sort-list ranges subid-range-less)) + (define root-missing? + (not + (find (lambda (r) + (string=? "root" + (subid-range-name r))) + sorted-ranges))) + (define first-start + (and (> (length sorted-ranges) 0) + (subid-range-start (first sorted-ranges)))) + (define first-has-start? + (number? first-start)) + (define root-start + (if first-has-start? + (and + (> first-start %subordinate-id-min) + %subordinate-id-min) + %subordinate-id-min)) + (define root-count + (if first-has-start? + (- first-start %subordinate-id-min) + %subordinate-id-count)) + (if (and root-missing? + (subids-configuration-add-root? config)) + (append (list (%root-subid root-start root-count)) + sorted-ranges) + sorted-ranges)) + + (define subuids + (delete-duplicate-ranges (subids-configuration-subuids config))) + + (define subuids-specs + (map subid-range->gexp (add-root-when-missing subuids))) + + (define subgids + (delete-duplicate-ranges (subids-configuration-subgids config))) + + (define subgids-specs + (map subid-range->gexp (add-root-when-missing subgids))) + + (assert-valid-subids subgids) + (assert-valid-subids subuids) + + ;; Add subuids and subgids. + (with-imported-modules (source-module-closure '((gnu system accounts))) + #~(begin + (use-modules (gnu system accounts)) + + (activate-subuids+subgids (map sexp->subid-range (list #$@subuids-specs)) + (map sexp->subid-range (list #$@subgids-specs)))))) + +(define-record-type* + subids-extension make-subids-extension + subids-extension? + this-subids-extension + + (subgids subids-extension-subgids ; list of + (default '())) + (subuids subids-extension-subuids ; list of + (default '()))) + +(define append-subid-ranges + (lambda args + (delete-duplicate-ranges + (apply append args)))) + +(define (subids-extension-merge a b) + (subids-extension + (subgids (append-subid-ranges + (subids-extension-subgids a) + (subids-extension-subgids b))) + (subuids (append-subid-ranges + (subids-extension-subuids a) + (subids-extension-subuids b))))) + +(define subids-service-type + (service-type (name 'subids) + ;; Concatenate lists. + (compose (lambda (args) + (fold subids-extension-merge + (subids-extension) + args))) + (extend + (lambda (config extension) + (subids-configuration + (inherit config) + (subgids + (append-subid-ranges + (subids-configuration-subgids config) + (subids-extension-subgids extension))) + (subuids + (append-subid-ranges + (subids-configuration-subuids config) + (subids-extension-subuids extension)))))) + (extensions + (list (service-extension activation-service-type + subids-activation))) + (default-value + (subids-configuration)) + (description + "Ensure the specified sub UIDs and sub GIDs exist in +/etc/subuid and /etc/subgid."))) + ;;; shadow.scm ends here diff --git a/gnu/tests/shadow.scm b/gnu/tests/shadow.scm new file mode 100644 index 0000000000..849b7b8af0 --- /dev/null +++ b/gnu/tests/shadow.scm @@ -0,0 +1,180 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Giacomo Leidi +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu tests shadow) + #:use-module (gnu packages base) + #:use-module (gnu packages containers) + #:use-module (gnu tests) + #:use-module (gnu services) + #:use-module (gnu system) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (gnu system vm) + #:use-module (guix gexp) + #:export (%test-subids)) + + +(define %subids-os + (simple-operating-system + (simple-service + 'simple-profile + profile-service-type + (list podman)) + (simple-service + 'simple-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range + (name "alice")) + (subid-range + (name "bob") + (start 100700)))) + (subuids + (list + (subid-range + (name "alice")))))))) + +(define (run-subids-test) + "Run IMAGE as an OCI backed Shepherd service, inside OS." + + (define os + (marionette-operating-system + (operating-system-with-gc-roots + %subids-os + (list)) + #:imported-modules '((gnu services herd) + (guix combinators)))) + + (define vm + (virtual-machine + (operating-system os) + (volatile? #f) + (memory-size 1024) + (disk-image-size (* 3000 (expt 2 20))) + (port-forwardings '()))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) (srfi srfi-64) + (gnu build marionette)) + + (define marionette + ;; Relax timeout to accommodate older systems and + ;; allow for pulling the image. + (make-marionette (list #$vm) #:timeout 60)) + + (test-runner-current (system-test-runner #$output)) + (test-begin "subids") + + (test-equal "/etc/subid and /etc/subgid are created and their content is sound" + '("root:100000:700\nbob:100700:65536\nalice:166236:65536\n" + "root:100000:65536\nalice:165536:65536\n") + (marionette-eval + `(begin + (use-modules (ice-9 textual-ports)) + + (define (read-file file-name) + (call-with-input-file file-name get-string-all)) + + (let* ((response1 (read-file "/etc/subgid")) + (response2 (read-file "/etc/subuid"))) + (list response1 response2))) + marionette)) + + (test-equal "podman unshare runs for unprivileged users" + " 0 1000 1\n 1 165536 65536" + (marionette-eval + `(begin + (use-modules (srfi srfi-1) + (ice-9 popen) + (ice-9 match) + (ice-9 rdelim) + (ice-9 textual-ports)) + (define out-dir "/tmp") + (define (read-file file-name) + (call-with-input-file file-name get-string-all)) + + (define (wait-for-file file) + ;; Wait until FILE shows up. + (let loop ((i 60)) + (cond ((file-exists? file) + #t) + ((zero? i) + (error "file didn't show up" file)) + (else + (sleep 1) + (loop (- i 1)))))) + + (define (read-lines file-or-port) + (define (loop-lines port) + (let loop ((lines '())) + (match (read-line port) + ((? eof-object?) + (reverse lines)) + (line + (loop (cons line lines)))))) + + (if (port? file-or-port) + (loop-lines file-or-port) + (call-with-input-file file-or-port + loop-lines))) + + (define slurp + (lambda args + (let* ((port (apply open-pipe* OPEN_READ + (list "sh" "-l" "-c" + (string-join + args + " ")))) + (output (read-lines port)) + (status (close-pipe port))) + output))) + + (match (primitive-fork) + (0 + (dynamic-wind + (const #f) + (lambda () + (setgid (passwd:gid (getpwnam "alice"))) + (setuid (passwd:uid (getpw "alice"))) + + (let* ((response1 (slurp + "podman" "unshare" "cat" "/proc/self/uid_map"))) + (call-with-output-file (string-append out-dir "/response1") + (lambda (port) + (display (string-join response1 "\n") port))))) + (lambda () + (primitive-exit 127)))) + (pid + (cdr (waitpid pid)))) + (wait-for-file (string-append out-dir "/response1")) + (read-file (string-append out-dir "/response1"))) + marionette)) + + (test-end)))) + + (gexp->derivation "subids-test" test)) + +(define %test-subids + (system-test + (name "subids") + (description "Test sub UIDs and sub GIDs provisioning service.") + (value (run-subids-test)))) -- 2.45.2 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Thu, 19 Sep 2024 11:16:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Giacomo Leidi Cc: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.172674452732296 (code B ref 72337); Thu, 19 Sep 2024 11:16:02 +0000 Received: (at 72337) by debbugs.gnu.org; 19 Sep 2024 11:15:27 +0000 Received: from localhost ([127.0.0.1]:59921 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1srF8A-0008NK-Ry for submit@debbugs.gnu.org; Thu, 19 Sep 2024 07:15:27 -0400 Received: from eggs.gnu.org ([209.51.188.92]:59328) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1srF87-0008Hb-OV for 72337@debbugs.gnu.org; Thu, 19 Sep 2024 07:15:25 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1srF7k-0002pO-QC; Thu, 19 Sep 2024 07:15:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=1LRtbkEpGgZj++dFcEESbHEiIsR2SsI8trrz3OKJ0gE=; b=HXCnNvSxAS/O2NXrEDxQ ZuvL37JUifYoTmUzE1NeKdDsWtvaC7IBLqQ8alAkWi/Csh26H7I4kagIuqJo5ciyqUMkxoO44UzHD DxIn3HX06fE7ZBbuky++EFtHLrvx7YLC3FJVKeagJcLyuxCTHyLQ2Y0FiwS+u0Tm55dPnjHd839mw X3gnkUeKdLR2Ahff4GJhW9yOORuoJLTBdzlVWL/f3/zfQAR2eTugyiXrWHkES2s7OCVe6FlugetgM 24Y0xVSSpQjOUsQ0F1t0sS31WiJ1IYEefGRW5huUNn7VzBAe4T+sriiY4oaqIFpBloe6ATXQbV+Jc VPPI+nKcwrezsQ==; From: Ludovic =?UTF-8?Q?Court=C3=A8s?= In-Reply-To: <2771695a2527240c89c0ba6879aeda0d4ab840ab.1725742309.git.goodoldpaul@autistici.org> (Giacomo Leidi's message of "Sat, 7 Sep 2024 22:51:48 +0200") References: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> <2771695a2527240c89c0ba6879aeda0d4ab840ab.1725742309.git.goodoldpaul@autistici.org> Date: Thu, 19 Sep 2024 13:14:57 +0200 Message-ID: <87ploz7v4e.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Giacomo Leidi skribis: > This commit adds allocation logic for subid ranges. Subid ranges are > ranges of contiguous subids that are mapped to a user in the host > system. This patch implements a flexible allocation algorithm allowing > users that do not want (or need) to specify details of the subid ranges > that they are requesting to avoid doing so, while upholding requests of > users that need to have specific ranges. > > * gnu/build/accounts.scm (list-set): New variable; > (%subordinate-id-min): new variable; > (%subordinate-id-max): new variable; > (%subordinate-id-count): new variable; > (subordinate-id?): new variable; > (within-interval?): new variable; > (insert-subid-range): new variable; > (reserve-subids): new variable; > (range->entry): new variable; > (entry->range): new variable; > (allocate-subids): new variable; > (subuid+subgid-databases): new variable. > > * gnu/system/accounts.scm (subid-range-end): New variable; > (subid-range-has-start?): new variable; > (subid-range-less): new variable. > > * test/accounts.scm: Test them. > > Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d > Signed-off-by: Giacomo Leidi [...] > +(define (vlist-set vlst el k) > + (if (>=3D k (vlist-length vlst)) > + (vlist-append vlst (vlist-cons el vlist-null)) > + (vlist-append > + (vlist-take vlst k) > + (vlist-cons el (vlist-drop vlst k))))) So hmm, this is not great either because the =E2=80=98else=E2=80=99 branch = has linear complexity. I don=E2=80=99t think there=E2=80=99s a good persistent data structure for = this in Guile unfortunately. Again maybe plain lists or vlists are okay *if* we know the lists are going to be small, but there needs to be a comment stating it. > +(define-condition-type &subordinate-id-range-error &subordinate-id-error > + subordinate-id-range-error? > + (message subordinate-id-range-error-message) > + (ranges subordinate-id-range-error-ranges)) Remove =E2=80=98message=E2=80=99 from here. If we want a human-readable me= ssage, we can always raise a =E2=80=9Ccompound error condition=E2=80=9D that combines =E2=80=98&subordinate-id-range-error=E2=80=99 and =E2=80=98&message=E2=80= =99. But I=E2=80=99m not sure we want messages anyway; I think we should focus on ensuring =E2=80=98&subordinate-id-range-error=E2=80=99 has all the info. > +(define (insert-subid-range range vlst) > + "Allocates a range of subids in VLST, based on RANGE. Ranges > +that do not explicitly specify a start subid are fitted based on > +their size. This procedure assumes VLIST is sorted by SUBID-RANGE-LESS = and > +that all VLST members have a start." I=E2=80=99m not convinced by the use of (v)lists and the lack of abstraction here. How about having a tree along these lines: (define-record-type (unused-subuid-range left min max right) unused-subuid-range? (left unused-subuid-range-left) ;previous unused subuid range or #f (min unused-subuid-range-min) ;lower bound of this unused subuid r= ange (max unused-subuid-range-max) ;upper bound (right unused-subuid-range-right)) ;next unused subuid range or #f We=E2=80=99d start with: (unused-subuid-range #f %subordinate-id-min %subordinate-id-max #f) Then, when consuming =E2=80=9Cto the left=E2=80=9D, we=E2=80=99d add a chil= d there, and so on. Searching for an available range would be logarithmic. Does that make sense? (I=E2=80=99m really thinking out loud, this probably needs more thought.) > +(let ((inputs+currents > + (list > + (list > + "ranges must have start" > + (list (subid-range (name "m"))) > + (list (subid-range (name "x"))) > + "Loaded ranges are supposed to have a start, but at least one d= oes not.") > + (list > + "ranges must fall within allowed max min subids" > + (list (subid-range (name "m") > + (start (- %subordinate-id-min 1)) > + (count > + (+ %subordinate-id-max %subordinate-id-min)= ))) > + (list > + (subid-range (name "root") (start %subordinate-id-min))) > + "Subid range of m from 99999 to 600299998 spans over illegal su= bids. Max allowed is 600100000, min is 100000.")))) > + > + ;; Make sure it's impossible to explicitly request impossible allocati= ons > + (for-each > + (match-lambda > + ((test-name ranges current-ranges message) > + (test-assert (string-append "allocate-subids, impossible allocatio= ns - " > + test-name) > + (guard (c ((and (subordinate-id-range-error? c) > + (string=3D? message (subordinate-id-range-error-= message c))) > + #t)) > + (allocate-subids ranges current-ranges) > + #f)))) > + inputs+currents)) This is hard to read. It might be best to unroll the loop? Also, I would check for =E2=80=98&subordinate-id-range-error=E2=80=99 detai= ls than for messages: messages are for human beings, not for automated tests. Thoughts? Thanks, Ludo=E2=80=99. From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: paul Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 07 Oct 2024 22:36:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17283405304342 (code B ref 72337); Mon, 07 Oct 2024 22:36:02 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Oct 2024 22:35:30 +0000 Received: from localhost ([127.0.0.1]:49259 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwK9-00017x-J1 for submit@debbugs.gnu.org; Mon, 07 Oct 2024 18:35:29 -0400 Received: from confino.investici.org ([93.190.126.19]:40759) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwK7-00017p-BX for 72337@debbugs.gnu.org; Mon, 07 Oct 2024 18:35:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1728340511; bh=o9QpG5UsQDAnbeYRFKl4/LTchDNWxdtZDopInmlJWvU=; h=Date:Subject:To:Cc:References:From:In-Reply-To:From; b=qJ/SJ2M6FkBHOzAplOFoYmRqOXoAzR207JmWSUiH35v8/XXHDhZBeCOgAwnipqisB XcsWfsJWZvUFrk9tnqqz2ykE3CCKEE5mTDTz/8VpDIIurglFLkZoKDwdT4hBgdDp1i miwuiRONMRghIX1JcvjkfmLpaZ43oF/CzJAb7QZA= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4XMv9W2jGpz11XK; Mon, 7 Oct 2024 22:35:11 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4XMv9W21mWz11XF; Mon, 7 Oct 2024 22:35:11 +0000 (UTC) Content-Type: multipart/alternative; boundary="------------hJbd8LBh6HHrS39wpUQznLLi" Message-ID: <45280b7f-dd6e-47b2-87ba-41c68235f50b@autistici.org> Date: Tue, 8 Oct 2024 00:35:10 +0200 MIME-Version: 1.0 User-Agent: Icedove Daily References: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> <2771695a2527240c89c0ba6879aeda0d4ab840ab.1725742309.git.goodoldpaul@autistici.org> <87ploz7v4e.fsf_-_@gnu.org> Content-Language: en-US From: paul In-Reply-To: <87ploz7v4e.fsf_-_@gnu.org> X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This is a multi-part message in MIME format. --------------hJbd8LBh6HHrS39wpUQznLLi Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Hi Ludo’ , I think I have addressed your comments. I have now implemented two separate code paths: - when the request is specific (i.e. the subid range has a start) we can traverse the tree logarithmically - when the request is generic (i.e. the subid range does not have a start) the search is linear since all the nodes have to be visited worst case to avoid leaving empty spaces interleaved, that could actually evade requests As for estimating the size of the input, I'm not sure I know enough to answer this. My reasoning has been: in general the number of possible subids (i.e. %subordinate-id-max - %subordinate-id-min) is huge. The use case I have in mind for subids is rootless podman, so how many users in average need to use rootless containers on a system and how many subids are they to request in average are two very good questions I don't know how to answer yet, or where I could find data for. Let me know if you have any idea. Please let me know if this v5 looks ok, thank you a lot for your help. giacomo --------------hJbd8LBh6HHrS39wpUQznLLi Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit

Hi Ludo’ ,

I think I have addressed your comments. I have now implemented two separate code paths: - when the request is specific (i.e. the subid range has a start) we can traverse the tree logarithmically

- when the request is generic (i.e. the subid range does not have a start) the search is linear since all the nodes have to be visited worst case to avoid leaving empty spaces interleaved, that could actually evade requests


As for estimating the size of the input, I'm not sure I know enough to answer this. My reasoning has been: in general the number of possible subids (i.e. %subordinate-id-max - %subordinate-id-min) is huge. The use case I have in mind for subids is rootless podman, so how many users in average need to use rootless containers on a system and how many subids are they to request in average are two very good questions I don't know how to answer yet, or where I could find data for. Let me know if you have any idea.


Please let me know if this v5 looks ok, thank you a lot for your help. giacomo

--------------hJbd8LBh6HHrS39wpUQznLLi-- From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v5 2/3] account: Add /etc/subid and /etc/subgid allocation logic. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 07 Oct 2024 22:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi , Ludovic =?UTF-8?Q?Court=C3=A8s?= Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17283408725407 (code B ref 72337); Mon, 07 Oct 2024 22:42:01 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Oct 2024 22:41:12 +0000 Received: from localhost ([127.0.0.1]:49274 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwPf-0001P8-G8 for submit@debbugs.gnu.org; Mon, 07 Oct 2024 18:41:12 -0400 Received: from confino.investici.org ([93.190.126.19]:60741) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwPc-0001Ot-SQ for 72337@debbugs.gnu.org; Mon, 07 Oct 2024 18:41:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1728340860; bh=0LM/X9oUHI3PC8uhGvWBHGBGVue+8vJdzE6cw0LYRyM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GQhn4lCwDQ/wV9Tz/SyiICR48GyrqgJwl4Ljfn6EAdTJZBQA/2UoRJlOHEaF7M8Uc tjIuxf2K8DKCFDi8tULMy2jD5jBxchvmUmbiy4IeCxG9pj82ZNtEO2DkG1ePvVSMX4 eS9SOv1XRDGrtF+1nhalH/pSZd7Yd20x1GwFtTU0= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4XMvJD3g70z11XH; Mon, 7 Oct 2024 22:41:00 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4XMvJD2fLcz11XF; Mon, 7 Oct 2024 22:41:00 +0000 (UTC) From: Giacomo Leidi Date: Tue, 8 Oct 2024 00:40:27 +0200 Message-ID: X-Mailer: git-send-email 2.46.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds allocation logic for subid ranges. Subid ranges are ranges of contiguous subids that are mapped to a user in the host system. This patch implements a flexible allocation algorithm allowing users that do not want (or need) to specify details of the subid ranges that they are requesting to avoid doing so, while upholding requests of users that need to have specific ranges. * gnu/build/accounts.scm (%subordinate-id-min): New variable; (%subordinate-id-max): new variable; (%subordinate-id-count): new variable; (subordinate-id?): new variable; (&subordinate-id-error): new variable; (&subordinate-id-overflow-error): new variable; (&illegal-subid-range-error): new variable; (&specific-subid-range-expected-error): new variable; (&generic-subid-range-expected-error): new variable; (within-interval?): new variable; (allocate-unused-range): new variable; (allocate-generic-range): new variable; (allocate-specific-range): new variable; (reserve-subids): new variable; (range->entry): new variable; (entry->range): new variable; (allocate-subids): new variable; (subuid+subgid-databases): new variable. * gnu/system/accounts.scm (subid-range-end): New variable; (subid-range-has-start?): new variable; (subid-range-less): new variable. * test/accounts.scm: Test them. Change-Id: I8de1fd7cfe508b9c76408064d6f498471da0752d Co-Authored-By: Ludovic Courtès Signed-off-by: Giacomo Leidi --- gnu/build/accounts.scm | 319 +++++++++++++++++++++++++++++++++++++++- gnu/system/accounts.scm | 30 ++++ tests/accounts.scm | 134 +++++++++++++++++ 3 files changed, 481 insertions(+), 2 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index ea8c69f205..be0db27215 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -25,8 +25,11 @@ (define-module (gnu build accounts) #:use-module (srfi srfi-11) #:use-module (srfi srfi-19) #:use-module (srfi srfi-26) + #:use-module (srfi srfi-34) + #:use-module (srfi srfi-35) #:use-module (ice-9 match) #:use-module (ice-9 vlist) + #:use-module (ice-9 receive) #:use-module (ice-9 rdelim) #:export (password-entry password-entry? @@ -74,8 +77,27 @@ (define-module (gnu build accounts) %id-max %system-id-min %system-id-max - - user+group-databases)) + %subordinate-id-min + %subordinate-id-max + %subordinate-id-count + + &subordinate-id-error + subordinate-id-error? + &subordinate-id-overflow-error + subordinate-id-overflow-error? + subordinate-id-overflow-error-range + &illegal-subid-range-error + illegal-subid-range-error? + illegal-subid-range-error-range + &specific-subid-range-expected-error + specific-subid-range-expected-error? + specific-subid-range-expected-error-range + &generic-subid-range-expected-error + generic-subid-range-expected-error? + generic-subid-range-expected-error-range + + user+group-databases + subuid+subgid-databases)) ;;; Commentary: ;;; @@ -331,6 +353,18 @@ (define-record-type* (next-id allocation-next-id (default %id-min)) (next-system-id allocation-next-system-id (default %system-id-max))) +(define-record-type* + unused-subid-range make-unused-subid-range + unused-subid-range? + (left unused-subid-range-left ;previous unused subuid range or #f + (default #f)) + (min unused-subid-range-min ;lower bound of this unused subuid range + (default %subordinate-id-min)) + (max unused-subid-range-max ;upper bound + (default %subordinate-id-max)) + (right unused-subid-range-right ;next unused subuid range or #f + (default #f))) + ;; Trick to avoid name clashes... (define-syntax %allocation (identifier-syntax allocation)) @@ -342,6 +376,27 @@ (define %id-max 60000) (define %system-id-min 100) (define %system-id-max 999) +;; According to Shadow's libmisc/find_new_sub_uids.c and +;; libmisc/find_new_sub_gids.c. +(define %subordinate-id-min 100000) +(define %subordinate-id-max 600100000) +(define %subordinate-id-count 65536) + +(define-condition-type &subordinate-id-error &error + subordinate-id-error?) +(define-condition-type &subordinate-id-overflow-error &subordinate-id-error + subordinate-id-overflow-error? + (range subordinate-id-overflow-error)) +(define-condition-type &illegal-subid-range-error &subordinate-id-error + illegal-subid-range-error? + (range illegal-subid-range-error-range)) +(define-condition-type &specific-subid-range-expected-error &subordinate-id-error + specific-subid-range-expected-error? + (range specific-subid-range-expected-error-range)) +(define-condition-type &generic-subid-range-expected-error &subordinate-id-error + generic-subid-range-expected-error? + (range generic-subid-range-expected-error-range)) + (define (system-id? id) (and (> id %system-id-min) (<= id %system-id-max))) @@ -350,6 +405,10 @@ (define (user-id? id) (and (>= id %id-min) (< id %id-max))) +(define (subordinate-id? id) + (and (>= id %subordinate-id-min) + (< id %subordinate-id-max))) + (define* (allocate-id assignment #:key system?) "Return two values: a newly allocated ID, and an updated record based on ASSIGNMENT. If SYSTEM? is true, return a system ID." @@ -405,6 +464,194 @@ (define* (reserve-ids allocation ids #:key (skip? #t)) (allocation-ids allocation) ids)))) +(define (within-interval? allocation range) + "Returns #t when RANGE is included in the ALLOCATION. +Both ends of the ALLOCATION are included in the comparison." + (define allocation-start + (unused-subid-range-min allocation)) + (define allocation-end + (unused-subid-range-max allocation)) + (unless (subid-range-has-start? range) + (raise + (condition + (&specific-subid-range-expected-error + (range range))))) + (and (<= allocation-start + (subid-range-start range)) + (<= (subid-range-end range) + allocation-end))) + +(define (allocate-unused-range allocation actual-range) + "Allocates RANGE inside ALLOCATION. RANGE is assumed to be +@code{within-interval?} of ALLOCATION, a new @code{unused-subid-range} record is +returned with all the subids contained in RANGE marked as used." + (define allocation-start + (unused-subid-range-min allocation)) + (define allocation-end + (unused-subid-range-max allocation)) + (define allocation-left + (unused-subid-range-left allocation)) + (define allocation-right + (unused-subid-range-left allocation)) + (define range-start + (subid-range-start actual-range)) + (define range-end + (subid-range-end actual-range)) + (define new-start + (+ 1 range-end)) + (define new-end + (- range-start 1)) + (if (or (= allocation-start range-start) + (= allocation-end range-end)) + (unused-subid-range + (inherit allocation) + (min (if (= allocation-start range-start) + new-start + allocation-start)) + (max (if (= allocation-end range-end) + new-end + allocation-end))) + (let* ((left-child? + (<= (- range-start allocation-start) + (- allocation-end range-end))) + (child + (unused-subid-range + (min allocation-start) + (max new-end) + (left + (and left-child? + allocation-left)) + (right + (and (not left-child?) + allocation-right))))) + (unused-subid-range + (inherit allocation) + (min new-start) + (max allocation-end) + (left + (if left-child? + child + allocation-left)) + (right + (if left-child? + allocation-right + child)))))) + +(define (allocate-generic-range allocation range) + "Allocates a range of subids in ALLOCATION, based on RANGE. RANGE is expected +to be a generic range i.e. to not have an explicit start subordinate id. All +nodes in ALLOCATION are visited and the first where RANGE is +@code{within-interval?} will be selected, the subordinate ids contained in RANGE +will be marked as used in it." + (when (subid-range-has-start? range) + (raise + (condition + (&generic-subid-range-expected-error + (ranges range))))) + (define left (unused-subid-range-left allocation)) + (define right (unused-subid-range-right allocation)) + (define allocation-start + (unused-subid-range-min allocation)) + (define actual-range + (subid-range + (inherit range) + (start allocation-start))) + + (if (within-interval? allocation actual-range) + (values + (allocate-unused-range allocation actual-range) + actual-range) + (if left + (let-values (((new-left new-range) + (allocate-generic-range left range))) + (values (unused-subid-range + (inherit allocation) + (left new-left)) + new-range)) + (if right + (let-values (((new-right new-range) + (allocate-generic-range right range))) + (values (unused-subid-range + (inherit allocation) + (left new-right)) + new-range)) + (raise + (condition + (&subordinate-id-overflow-error + (range range)))))))) + +(define (allocate-specific-range allocation range) + "Allocates a range of subids in ALLOCATION, based on RANGE. RANGE is expected +to be a specific range i.e. to have an explicit start subordinate id. ALLOCATION +is visited to find the best unused range that can hold RANGE." + (unless (subid-range-has-start? range) + (raise + (condition + (&specific-subid-range-expected-error + (range range))))) + (define allocation-left + (unused-subid-range-left allocation)) + (define allocation-right + (unused-subid-range-right allocation)) + (define allocation-start + (unused-subid-range-min allocation)) + (define allocation-end + (unused-subid-range-max allocation)) + + (define range-start + (subid-range-start range)) + (define range-end + (subid-range-end range)) + + (unless (and (subordinate-id? range-start) + (subordinate-id? range-end)) + (raise + (condition + (&illegal-subid-range-error + (range range))))) + + (define less? + (< range-end allocation-start)) + (define more? + (> range-start allocation-end)) + + (cond ((within-interval? allocation range) + (values (allocate-unused-range allocation range) + range)) + ((and allocation-left less?) + (let-values (((new-left _) + (allocate-specific-range allocation-left range))) + (values (unused-subid-range + (inherit allocation) + (left new-left)) + range))) + ((and allocation-right more?) + (let-values (((new-right _) + (allocate-specific-range allocation-right range))) + (values (unused-subid-range + (inherit allocation) + (right new-right)) + range))) + (else + (raise + (condition + (&subordinate-id-overflow-error + (range range))))))) + +(define* (reserve-subids allocation ranges) + "Mark the subid ranges listed in RANGES as reserved in ALLOCATION." + (fold (lambda (range state) + (define-values (new-allocation actual-range) + ((if (subid-range-has-start? range) + allocate-specific-range + allocate-generic-range) + (first state) + range)) + (list new-allocation + (cons actual-range + (second state)))) + (list allocation '()) ranges)) + (define (allocated? allocation id) "Return true if ID is already allocated as part of ALLOCATION." (->bool (vhash-assv id (allocation-ids allocation)))) @@ -540,6 +787,48 @@ (define* (allocate-passwd users groups #:optional (current-passwd '())) uids users))) +(define (range->entry range) + (subid-entry + (name (subid-range-name range)) + (start (subid-range-start range)) + (count (subid-range-count range)))) + +(define (entry->range entry) + (subid-range + (name (subid-entry-name entry)) + (start (subid-entry-start entry)) + (count (subid-entry-count entry)))) + +(define* (allocate-subids ranges #:optional (current-ranges '())) + "Return a list of subids entries for RANGES, a list of . IDs +found in CURRENT-RANGES, a list of subid entries, are reused." + (let ((generic (any (compose not subid-range-has-start?) current-ranges))) + (when generic + (raise + (condition + (&specific-subid-range-expected-error + (range generic)))))) + (define sorted-ranges + (stable-sort ranges + subid-range-less)) + (define current-allocation+subids + (reserve-subids (unused-subid-range) + current-ranges)) + (define subids + ;; Reserve first specific subid-ranges + ;; and later generic ones. + (second + (reserve-subids (first + current-allocation+subids) + sorted-ranges))) + + (map range->entry + ;; Produce deterministic subid collections. + (stable-sort + (append (second current-allocation+subids) + subids) + subid-range-less))) + (define* (days-since-epoch #:optional (current-time current-time)) "Return the number of days elapsed since the 1st of January, 1970." (let* ((now (current-time time-utc)) @@ -615,3 +904,29 @@ (define* (user+group-databases users groups #:current-time current-time)) (values group-entries passwd-entries shadow-entries)) + +(define* (subuid+subgid-databases subuids subgids + #:key + (current-subuids + (map entry->range + (empty-if-not-found read-subuid))) + (current-subgids + (map entry->range + (empty-if-not-found read-subgid)))) + "Return two values: the list of subgid entries, and the list of subuid entries +corresponding to SUBUIDS and SUBGIDS. +Preserve stateful bits from CURRENT-SUBUIDS and CURRENT-SUBGIDS." + + (define (range-eqv? a b) + (string=? (subid-range-name a) + (subid-range-name b))) + + (define subuid-entries + (allocate-subids + (lset-difference range-eqv? subuids current-subuids) current-subuids)) + + (define subgid-entries + (allocate-subids + (lset-difference range-eqv? subgids current-subgids) current-subgids)) + + (values subuid-entries subgid-entries)) diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 9a006c188d..1b88ca301f 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -45,6 +45,9 @@ (define-module (gnu system accounts) subid-range-name subid-range-start subid-range-count + subid-range-end + subid-range-has-start? + subid-range-less sexp->user-account sexp->user-group @@ -102,6 +105,33 @@ (define-record-type* ; find_new_sub_uids.c (default 65536))) +(define (subid-range-end range) + "Returns the last subid referenced in RANGE." + (and + (subid-range-has-start? range) + (+ (subid-range-start range) + (subid-range-count range) + -1))) + +(define (subid-range-has-start? range) + "Returns #t when RANGE's start is a number." + (number? (subid-range-start range))) + +(define (subid-range-less a b) + "Returns #t when subid range A either starts before, or is more specific +than B. When it is not possible to determine whether a range is more specific +w.r.t. another range their names are compared alphabetically." + (define start-a (subid-range-start a)) + (define start-b (subid-range-start b)) + (cond ((and (not start-a) (not start-b)) + (string< (subid-range-name a) + (subid-range-name b))) + ((and start-a start-b) + (< start-a start-b)) + (else + (and start-a + (not start-b))))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 4944c22f49..616632edca 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -21,6 +21,7 @@ (define-module (test-accounts) #:use-module (gnu build accounts) #:use-module (gnu system accounts) #:use-module (srfi srfi-19) + #:use-module (srfi srfi-34) #:use-module (srfi srfi-64) #:use-module (ice-9 vlist) #:use-module (ice-9 match)) @@ -193,6 +194,7 @@ (define %subgid-sample (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) +(define allocate-subids (@@ (gnu build accounts) allocate-subids)) (test-equal "allocate-groups" ;; Allocate GIDs in a stateless fashion. @@ -257,6 +259,94 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (list (group-entry (name "d") (gid (- %id-max 2)))))) +(test-equal "allocate-subids" + ;; Allocate sub IDs in a stateless fashion. + (list (subid-entry (name "root") (start %subordinate-id-min) (count 100)) + (subid-entry (name "t") (start 100100) (count 899)) + (subid-entry (name "x") (start 100999) (count 200))) + (allocate-subids (list + (subid-range (name "x") (count 200)) + (subid-range (name "t") (count 899))) + (list (subid-range (name "root") + (start %subordinate-id-min) + (count 100))))) + +(test-equal "allocate-subids with requested IDs ranges" + ;; Make sure the requested sub ID for "k" and "root" are honored. + (list (subid-entry (name "x") (start %subordinate-id-min) (count 200)) + (subid-entry (name "k") (start (+ %subordinate-id-min 300)) (count 100)) + (subid-entry (name "t") (start (+ %subordinate-id-min 500)) (count 899)) + (subid-entry (name "root") (start (+ %subordinate-id-min 2500)) (count 100))) + + (allocate-subids (list + (subid-range (name "root") (start (+ %subordinate-id-min 2500)) (count 100)) + (subid-range (name "k") (start (+ %subordinate-id-min 300)) (count 100))) + (list + (subid-range (name "x") (start %subordinate-id-min) (count 200)) + (subid-range (name "t") (start (+ %subordinate-id-min 500)) (count 899))))) + +(test-assert "allocate-subids, impossible allocations - ranges must have start" + (guard (c ((specific-subid-range-expected-error? c) + #t)) + (allocate-subids (list (subid-range (name "m"))) (list (subid-range (name "x")))) + #f)) + +(test-assert "allocate-subids, impossible allocations - ranges must fall within allowed max min subids" + (guard (c ((illegal-subid-range-error? c) + #t)) + (allocate-subids + (list (subid-range (name "m") + (start (- %subordinate-id-min 1)) + (count + (+ %subordinate-id-max %subordinate-id-min)))) + (list + (subid-range (name "root") (start %subordinate-id-min)))) + #f)) + +(test-equal "allocate-subids with interleaving" + ;; Make sure the requested sub ID for "m" is honored and + ;; for "l" and "i" are correctly deduced. + (list (subid-entry (name "x") (start %subordinate-id-min) (count 200)) + (subid-entry (name "m") (start (+ %subordinate-id-min 201)) (count 27)) + (subid-entry (name "root") (start (+ %subordinate-id-min 231)) (count 100)) + (subid-entry (name "i") (start (+ %subordinate-id-min 331)) (count 2)) + (subid-entry (name "l") (start (+ %subordinate-id-min 333)) (count 1))) + (allocate-subids (list + (subid-range (name "m") (start (+ %subordinate-id-min 201)) (count 27)) + (subid-range (name "l") (count 1)) + (subid-range (name "i") (count 2))) + (list + (subid-range (name "x") (start %subordinate-id-min) (count 200)) + (subid-range (name "root") (start (+ %subordinate-id-min 231)) (count 100))))) + +(test-assert "allocate-subids with interleaving, impossible interleaving - before" + (guard (c ((subordinate-id-overflow-error? c) + #t)) + (allocate-subids + (list (subid-range (name "m") (start %subordinate-id-min) (count 16))) + (list + (subid-range (name "x") (start (+ 15 %subordinate-id-min)) (count 150)))) + #f)) + +(test-assert "allocate-subids with interleaving, impossible interleaving - after" + (guard (c ((subordinate-id-overflow-error? c) + #t)) + (allocate-subids + (list (subid-range (name "m") (start %subordinate-id-min) (count 30))) + (list + (subid-range (name "x") (start (+ 29 %subordinate-id-min)) (count 150)))) + #f)) + +(test-assert "allocate-subids with interleaving, impossible interleaving - between" + (guard (c ((subordinate-id-overflow-error? c) + #t)) + (allocate-subids + (list (subid-range (name "m") (start 100200) (count 500))) + (list + (subid-range (name "root") (start %subordinate-id-min) (count 100)) + (subid-range (name "x") (start (+ %subordinate-id-min 500)) (count 100)))) + #f)) + (test-equal "allocate-passwd" ;; Allocate UIDs in a stateless fashion. (list (password-entry (name "alice") (uid %id-min) (gid 1000) @@ -376,4 +466,48 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) (make-time type 0 (* 24 3600 100))))) list)) +(test-equal "subuid+subgid-databases" + ;; The whole process. + (list (list (subid-entry (name "root") + (start %subordinate-id-min) + (count 100)) + (subid-entry (name "alice") + (start (+ %subordinate-id-min 100)) + (count 200)) + (subid-entry (name "bob") + (start (+ %subordinate-id-min 100 200)) + (count 200))) + (list + (subid-entry (name "root") + (start %subordinate-id-min) + (count 200)) + (subid-entry (name "alice") + (start (+ %subordinate-id-min 200)) + (count 400)) + (subid-entry (name "charlie") + (start (+ %subordinate-id-min 200 400)) + (count 300)))) + (call-with-values + (lambda () + (subuid+subgid-databases + (list (subid-range (name "root") + (start %subordinate-id-min) + (count 100)) + (subid-range (name "alice") + (start (+ %subordinate-id-min 100)) + (count 200)) + (subid-range (name "bob") + (count 200))) + (list + (subid-range (name "alice") + (count 400)) + (subid-range (name "charlie") + (count 300))) + #:current-subgids + (list (subid-range (name "root") + (start %subordinate-id-min) + (count 200))) + #:current-subuids '())) + list)) + (test-end "accounts") -- 2.46.0 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v5 3/3] system: Add /etc/subuid and /etc/subgid support. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: pelzflorian@pelzflorian.de, ludo@gnu.org, maxim.cournoyer@gmail.com, guix-patches@gnu.org Resent-Date: Mon, 07 Oct 2024 22:42:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi , Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Maxim Cournoyer X-Debbugs-Original-Xcc: Florian Pelz , Ludovic =?UTF-8?Q?Court=C3=A8s?= , Maxim Cournoyer Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17283408755418 (code B ref 72337); Mon, 07 Oct 2024 22:42:02 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Oct 2024 22:41:15 +0000 Received: from localhost ([127.0.0.1]:49276 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwPh-0001PH-Sw for submit@debbugs.gnu.org; Mon, 07 Oct 2024 18:41:15 -0400 Received: from confino.investici.org ([93.190.126.19]:38697) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwPd-0001Ou-7R for 72337@debbugs.gnu.org; Mon, 07 Oct 2024 18:41:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1728340860; bh=7UqiHhs9VaImj9oIiGyYV/xGmQ9n8WJ1ZzxHEQWXav8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iICE3Qy5nY9JdUeoqlea8rr4oU5f1rDZhiJ7Vom/10CF8sVx/ELjYGvCOr7ibYNHr tq1lHKEnc0C5ha1WTns3sNdMstmDLyKFUHerrLb3O2wCWDZj2FwBiUskC1+UhjcDnt qsqxrT17I0OM65TvjelXNsaHEjgCYvnvNifbd5Gw= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4XMvJD6022z11XK; Mon, 7 Oct 2024 22:41:00 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4XMvJD58gFz11XF; Mon, 7 Oct 2024 22:41:00 +0000 (UTC) From: Giacomo Leidi Date: Tue, 8 Oct 2024 00:40:28 +0200 Message-ID: <7be849965238ddc6d30c696a5328b6c278d00565.1728340828.git.goodoldpaul@autistici.org> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a Guix System service to handle allocation of subuid and subgid requests. Users that don't care can just add themselves as a subid-range and don't need to specify anything but their user name. Users that care about specific ranges, such as possibly LXD, can specify a start and a count. * doc/guix.texi: Document the new service. * gnu/build/activation.scm (activate-subuids+subgids): New variable. * gnu/local.mk: Add gnu/tests/shadow.scm. * gnu/system/accounts.scm (sexp->subid-range): New variable. * gnu/system/shadow.scm (%root-subid): New variable; (subids-configuration): new record; (subid-range->gexp): new variable; (assert-valid-subids): new variable; (delete-duplicate-ranges): new variable; (subids-activation): new variable; (subids-extension): new record; (append-subid-ranges): new variable; (subids-extension-merge): new variable; (subids-service-type): new variable. * gnu/tests/shadow.scm (subids): New system test. Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 Signed-off-by: Giacomo Leidi --- doc/guix.texi | 180 +++++++++++++++++++++++++++++++++ gnu/build/activation.scm | 19 ++++ gnu/local.mk | 1 + gnu/system/accounts.scm | 10 ++ gnu/system/shadow.scm | 211 ++++++++++++++++++++++++++++++++++++++- gnu/tests/shadow.scm | 180 +++++++++++++++++++++++++++++++++ 6 files changed, 599 insertions(+), 2 deletions(-) create mode 100644 gnu/tests/shadow.scm diff --git a/doc/guix.texi b/doc/guix.texi index 4aafcf9cc0..f9d079d4a4 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -41703,6 +41703,186 @@ Miscellaneous Services @end deftp +@c %end of fragment + +@cindex Subids +@subsubheading Subid Service + +Among the virtualization facilities implemented by the Linux kernel, the is the +concept of subordinate IDs. Subordinate IDs allow for mapping user and group +IDs inside process namespaces to user and group IDs of the host system. +Subordinate user ID ranges (subids) allow to map virtual user IDs inside +containers to the user ID of an unprivileged user of the host system. +Subordinate group ID ranges (subgids), instead map virtual group IDs to the +group ID of an unprivileged user on the host system. You can access +@code{subuid(5)} and @code{subgid(5)} Linux man pages for more details. + +The @code{(gnu system shadow)} module exposes the +@code{subids-service-type}, its configuration record +@code{subids-configuration} and its extension record +@code{subids-extension}. + +With @code{subids-service-type}, subuids and subgids ranges can be reserved for +users that desire so: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Users (definitely other services), usually, are supposed to extend the service +instead of adding subids directly to @code{subids-configuration}, unless the +want to change the default behavior for root. With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @file{/etc/subuid} and @file{/etc/subgid}, possibly +starting at the minimum possible subid. Otherwise the root subuids and subgids +ranges are fitted wherever possible. + +The above configuration will yield the following: + +@example +# cat /etc/subgid +root:100000:65536 +alice:165536:65536 +# cat /etc/subuid +root:100000:700 +bob:100700:65536 +alice:166236:65536 +@end example + +@c %start of fragment + +@deftp {Data Type} subids-configuration + +With default settings the +@code{subids-service-type} adds, if it's not already there, a configuration +for the root account to both @file{/etc/subuid} and @file{/etc/subgid}, possibly +starting at the minimum possible subid. To disable the default behavior and +provide your own definition for the root subid ranges you can set to @code{#f} +the @code{add-root?} field: + +@lisp +(use-modules (gnu system shadow) ;for 'subids-service-type' + (gnu system accounts) ;for 'subid-range' + @dots{}) + +(operating-system + ;; @dots{} + (services + (list + (service subids-service-type + (subids-configuration + (add-root? #f) + (subgids + (subid-range (name "root") + (start 120000) + (count 100))) + (subuids + (subid-range (name "root") + (start 120000) + (count 100))))) + (simple-service 'alice-bob-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range (name "alice")))) + (subuids + (list + (subid-range (name "alice")) + (subid-range (name "bob") + (start 100700))))))))) +@end lisp + +Available @code{subids-configuration} fields are: + +@table @asis +@item @code{add-root?} (default: @code{#t}) (type: boolean) +Whether to automatically configure subuids and subgids for root. + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subgid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be serialized to @code{/etc/subuid}. +If a range doesn't specify a start it will be fitted based on its number of +requrested subids. If a range doesn't specify a count the default size +of 65536 will be assumed. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subids-extension + +Available @code{subids-extension} fields are: + +@table @asis + +@item @code{subgids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subgids}. Entries with the same name are deduplicated +upon merging. + +@item @code{subuids} (default: @code{'()}) (type: list-of-subid-ranges) +The list of @code{subid-range}s that will be appended to +@code{subids-configuration-subuids}. Entries with the same name are deduplicated +upon merging. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} subid-range + +The @code{subid-range} record is defined at @code{(gnu system accounts)}. +Available fields are: + +@table @asis + +@item @code{name} (type: string) +The name of the user or group that will own this range. + +@item @code{start} (default: @code{#f}) (type: integer) +The first requested subid. When false the first available subid with enough +contiguous subids will be assigned. + +@item @code{count} (default: @code{#f}) (type: integer) +The number of total allocated subids. When #f the default of 65536 will be +assumed . + +@end table + +@end deftp + @c %end of fragment @node Privileged Programs diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index d1a2876a96..5236fbb403 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -10,6 +10,7 @@ ;;; Copyright © 2021 Brice Waegeneire ;;; Copyright © 2022 Tobias Geerinckx-Rice ;;; Copyright © 2024 Nicolas Graves +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -40,6 +41,7 @@ (define-module (gnu build activation) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) #:export (activate-users+groups + activate-subuids+subgids activate-user-home activate-etc activate-privileged-programs @@ -227,6 +229,23 @@ (define (activate-users+groups users groups) (chmod directory #o555)) (duplicates (map user-account-home-directory system-accounts)))) +(define (activate-subuids+subgids subuids subgids) + "Make sure SUBUIDS (a list of subid range records) and SUBGIDS (a list of +subid range records) are all available." + + ;; Take same lock as Shadow while we read + ;; and write the databases. This ensures there's no race condition with + ;; other tools that might be accessing it at the same time. + (with-file-lock "/etc/subgid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subgid subgid))) + + (with-file-lock "/etc/subuid.lock" + (let-values (((subuid subgid) + (subuid+subgid-databases subuids subgids))) + (write-subuid subuid)))) + (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless they already exist." diff --git a/gnu/local.mk b/gnu/local.mk index 9502f24621..a9383a6615 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -842,6 +842,7 @@ GNU_SYSTEM_MODULES = \ %D%/tests/samba.scm \ %D%/tests/security.scm \ %D%/tests/security-token.scm \ + %D%/tests/shadow.scm \ %D%/tests/singularity.scm \ %D%/tests/ssh.scm \ %D%/tests/telephony.scm \ diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 1b88ca301f..f63d7f96bd 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -51,6 +51,7 @@ (define-module (gnu system accounts) sexp->user-account sexp->user-group + sexp->subid-range default-shell)) @@ -159,3 +160,12 @@ (define (sexp->user-account sexp) (create-home-directory? create-home-directory?) (shell shell) (password password) (system? system?))))) + +(define (sexp->subid-range sexp) + "Take SEXP, a tuple as returned by 'subid-range->gexp', and turn it into a +subid-range record." + (match sexp + ((name start count) + (subid-range (name name) + (start start) + (count count))))) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index d9f13271d8..48eca2564f 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen ;;; Copyright © 2020, 2023 Efraim Flashner ;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -28,6 +29,10 @@ (define-module (gnu system shadow) #:use-module (guix modules) #:use-module (guix sets) #:use-module (guix ui) + #:use-module ((gnu build accounts) + #:select (%subordinate-id-count + %subordinate-id-max + %subordinate-id-min)) #:use-module (gnu system accounts) #:use-module (gnu services) #:use-module (gnu services shepherd) @@ -77,7 +82,20 @@ (define-module (gnu system shadow) %base-user-accounts account-service-type - account-service)) + account-service + + subids-configuration + subids-configuration? + subids-configuration-add-root? + subids-configuration-subgids + subids-configuration-subuids + + subids-extension + subids-extension? + subids-extension-subgids + subids-extension-subuids + + subids-service-type)) ;;; Commentary: ;;; @@ -380,7 +398,7 @@ (define (assert-valid-users/groups users groups) ;;; -;;; Service. +;;; Accounts Service. ;;; (define (user-group->gexp group) @@ -521,4 +539,193 @@ (define (account-service accounts+groups skeletons) (service account-service-type (append skeletons accounts+groups))) + +;;; +;;; Subids Service. +;;; + +(define* (%root-subid #:optional (start %subordinate-id-min) (count %subordinate-id-count)) + (subid-range + (name "root") + (start start) + (count count))) + +(define-record-type* + subids-configuration make-subids-configuration + subids-configuration? + this-subids-configuration + + (add-root? subids-configuration-add-root? ; boolean + (default #t)) + (subgids subids-configuration-subgids ; list of + (default '())) + (subuids subids-configuration-subuids ; list of + (default '()))) + +(define (subid-range->gexp range) + "Turn RANGE, a object, into a list-valued gexp suitable for +'activate-subuids+subgids'." + (define count (subid-range-count range)) + #~`(#$(subid-range-name range) + #$(subid-range-start range) + #$(if (and (number? count) + (> count 0)) + count + %subordinate-id-count))) + +(define (assert-valid-subids ranges) + (cond ((>= (fold + 0 (map subid-range-count ranges)) + (- %subordinate-id-max %subordinate-id-min -1)) + (raise + (formatted-message + (G_ + "The configured ranges are more than the ~a max allowed.") + (- %subordinate-id-max %subordinate-id-min -1)))) + ((any (lambda (r) + (define start (subid-range-start r)) + (and start + (< start %subordinate-id-min))) + ranges) + (raise + (formatted-message + (G_ + "One subid-range starts before the minimum allowed sub id ~a.") + %subordinate-id-min))) + ((any (lambda (r) + (define end (subid-range-end r)) + (and end + (> end %subordinate-id-max))) + ranges) + (raise + (formatted-message + (G_ + "One subid-range ends after the maximum allowed sub id ~a.") + %subordinate-id-max))) + ((any (compose null? subid-range-name) + ranges) + (raise + (formatted-message + (G_ + "One subid-range has a null name.")))) + ((any (compose string-null? subid-range-name) + ranges) + (raise + (formatted-message + (G_ + "One subid-range has a name equal to the empty string.")))) + (else #t))) + +(define (delete-duplicate-ranges ranges) + (delete-duplicates ranges + (lambda args + (apply string=? (map subid-range-name ranges))))) + +(define (subids-activation config) + "Return a gexp that activates SUBUIDS+SUBGIDS, a list of +objects." + (define (add-root-when-missing ranges) + (define sorted-ranges + (sort-list ranges subid-range-less)) + (define root-missing? + (not + (find (lambda (r) + (string=? "root" + (subid-range-name r))) + sorted-ranges))) + (define first-start + (and (> (length sorted-ranges) 0) + (subid-range-start (first sorted-ranges)))) + (define first-has-start? + (number? first-start)) + (define root-start + (if first-has-start? + (and + (> first-start %subordinate-id-min) + %subordinate-id-min) + %subordinate-id-min)) + (define root-count + (if first-has-start? + (- first-start %subordinate-id-min) + %subordinate-id-count)) + (if (and root-missing? + (subids-configuration-add-root? config)) + (append (list (%root-subid root-start root-count)) + sorted-ranges) + sorted-ranges)) + + (define subuids + (delete-duplicate-ranges (subids-configuration-subuids config))) + + (define subuids-specs + (map subid-range->gexp (add-root-when-missing subuids))) + + (define subgids + (delete-duplicate-ranges (subids-configuration-subgids config))) + + (define subgids-specs + (map subid-range->gexp (add-root-when-missing subgids))) + + (assert-valid-subids subgids) + (assert-valid-subids subuids) + + ;; Add subuids and subgids. + (with-imported-modules (source-module-closure '((gnu system accounts))) + #~(begin + (use-modules (gnu system accounts)) + + (activate-subuids+subgids (map sexp->subid-range (list #$@subuids-specs)) + (map sexp->subid-range (list #$@subgids-specs)))))) + +(define-record-type* + subids-extension make-subids-extension + subids-extension? + this-subids-extension + + (subgids subids-extension-subgids ; list of + (default '())) + (subuids subids-extension-subuids ; list of + (default '()))) + +(define append-subid-ranges + (lambda args + (delete-duplicate-ranges + (apply append args)))) + +(define (subids-extension-merge a b) + (subids-extension + (subgids (append-subid-ranges + (subids-extension-subgids a) + (subids-extension-subgids b))) + (subuids (append-subid-ranges + (subids-extension-subuids a) + (subids-extension-subuids b))))) + +(define subids-service-type + (service-type (name 'subids) + ;; Concatenate lists. + (compose (lambda (args) + (fold subids-extension-merge + (subids-extension) + args))) + (extend + (lambda (config extension) + (subids-configuration + (inherit config) + (subgids + (append-subid-ranges + (subids-configuration-subgids config) + (subids-extension-subgids extension))) + (subuids + (append-subid-ranges + (subids-configuration-subuids config) + (subids-extension-subuids extension)))))) + (extensions + (list (service-extension activation-service-type + subids-activation))) + (default-value + (subids-configuration)) + (description + "Ensure the specified sub UIDs and sub GIDs exist in +/etc/subuid and /etc/subgid."))) + ;;; shadow.scm ends here diff --git a/gnu/tests/shadow.scm b/gnu/tests/shadow.scm new file mode 100644 index 0000000000..849b7b8af0 --- /dev/null +++ b/gnu/tests/shadow.scm @@ -0,0 +1,180 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Giacomo Leidi +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu tests shadow) + #:use-module (gnu packages base) + #:use-module (gnu packages containers) + #:use-module (gnu tests) + #:use-module (gnu services) + #:use-module (gnu system) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (gnu system vm) + #:use-module (guix gexp) + #:export (%test-subids)) + + +(define %subids-os + (simple-operating-system + (simple-service + 'simple-profile + profile-service-type + (list podman)) + (simple-service + 'simple-subids + subids-service-type + (subids-extension + (subgids + (list + (subid-range + (name "alice")) + (subid-range + (name "bob") + (start 100700)))) + (subuids + (list + (subid-range + (name "alice")))))))) + +(define (run-subids-test) + "Run IMAGE as an OCI backed Shepherd service, inside OS." + + (define os + (marionette-operating-system + (operating-system-with-gc-roots + %subids-os + (list)) + #:imported-modules '((gnu services herd) + (guix combinators)))) + + (define vm + (virtual-machine + (operating-system os) + (volatile? #f) + (memory-size 1024) + (disk-image-size (* 3000 (expt 2 20))) + (port-forwardings '()))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) (srfi srfi-64) + (gnu build marionette)) + + (define marionette + ;; Relax timeout to accommodate older systems and + ;; allow for pulling the image. + (make-marionette (list #$vm) #:timeout 60)) + + (test-runner-current (system-test-runner #$output)) + (test-begin "subids") + + (test-equal "/etc/subid and /etc/subgid are created and their content is sound" + '("root:100000:700\nbob:100700:65536\nalice:166236:65536\n" + "root:100000:65536\nalice:165536:65536\n") + (marionette-eval + `(begin + (use-modules (ice-9 textual-ports)) + + (define (read-file file-name) + (call-with-input-file file-name get-string-all)) + + (let* ((response1 (read-file "/etc/subgid")) + (response2 (read-file "/etc/subuid"))) + (list response1 response2))) + marionette)) + + (test-equal "podman unshare runs for unprivileged users" + " 0 1000 1\n 1 165536 65536" + (marionette-eval + `(begin + (use-modules (srfi srfi-1) + (ice-9 popen) + (ice-9 match) + (ice-9 rdelim) + (ice-9 textual-ports)) + (define out-dir "/tmp") + (define (read-file file-name) + (call-with-input-file file-name get-string-all)) + + (define (wait-for-file file) + ;; Wait until FILE shows up. + (let loop ((i 60)) + (cond ((file-exists? file) + #t) + ((zero? i) + (error "file didn't show up" file)) + (else + (sleep 1) + (loop (- i 1)))))) + + (define (read-lines file-or-port) + (define (loop-lines port) + (let loop ((lines '())) + (match (read-line port) + ((? eof-object?) + (reverse lines)) + (line + (loop (cons line lines)))))) + + (if (port? file-or-port) + (loop-lines file-or-port) + (call-with-input-file file-or-port + loop-lines))) + + (define slurp + (lambda args + (let* ((port (apply open-pipe* OPEN_READ + (list "sh" "-l" "-c" + (string-join + args + " ")))) + (output (read-lines port)) + (status (close-pipe port))) + output))) + + (match (primitive-fork) + (0 + (dynamic-wind + (const #f) + (lambda () + (setgid (passwd:gid (getpwnam "alice"))) + (setuid (passwd:uid (getpw "alice"))) + + (let* ((response1 (slurp + "podman" "unshare" "cat" "/proc/self/uid_map"))) + (call-with-output-file (string-append out-dir "/response1") + (lambda (port) + (display (string-join response1 "\n") port))))) + (lambda () + (primitive-exit 127)))) + (pid + (cdr (waitpid pid)))) + (wait-for-file (string-append out-dir "/response1")) + (read-file (string-append out-dir "/response1"))) + marionette)) + + (test-end)))) + + (gexp->derivation "subids-test" test)) + +(define %test-subids + (system-test + (name "subids") + (description "Test sub UIDs and sub GIDs provisioning service.") + (value (run-subids-test)))) -- 2.46.0 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] [PATCH v5 1/3] accounts: Add /etc/subuid and /etc/subgid support. References: In-Reply-To: Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 07 Oct 2024 22:42:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 72337@debbugs.gnu.org Cc: Giacomo Leidi Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.17283408785435 (code B ref 72337); Mon, 07 Oct 2024 22:42:02 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Oct 2024 22:41:18 +0000 Received: from localhost ([127.0.0.1]:49279 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwPl-0001Pa-Bt for submit@debbugs.gnu.org; Mon, 07 Oct 2024 18:41:18 -0400 Received: from confino.investici.org ([93.190.126.19]:42311) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sxwPj-0001PR-PA for 72337@debbugs.gnu.org; Mon, 07 Oct 2024 18:41:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1728340860; bh=6IyggPKBnl6k95IHQEDqZD2Lvs6/xHwt27mjWnZFqHM=; h=From:To:Cc:Subject:Date:From; b=pPv7cNP9S7rILXSRkAMSG5MaqURrBlo8ZatllkhfMp3PplaWBzBXHen4xMoNnElqm JbjolMS83wbHSHw2xO/VnvJ26LZDNyfpg2XXv/uqu6iUxG7xtqT4zx5gDvIOSpj9lg iALrbOO6OpmM2nZJ3QgZfSyMQ09PBeOor4d8ROx0= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4XMvJD1JDtz11XG; Mon, 7 Oct 2024 22:41:00 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4XMvJD0WGJz11XF; Mon, 7 Oct 2024 22:41:00 +0000 (UTC) From: Giacomo Leidi Date: Tue, 8 Oct 2024 00:40:26 +0200 Message-ID: X-Mailer: git-send-email 2.46.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This commit adds a new record type, and serializers and deserializers for it in (gnu build accounts). Each instance of this record represents one line in either /etc/subuid or /etc/subgid. Since Shadow uses the same representation for both files, it should be ok if we do it as well. This commit adds also , a user facing representation of . It is supposed to be usable directly in OS configurations. * gnu/build/accounts.scm (subid-entry): New record; (write-subgid): add serializer for subgids; (write-subuid): add serializer for subuids; (read-subgid): add serializer for subgids; (read-subuid): add serializer for subuids. * gnu/system/accounts.scm (subid-range): New record. * test/accounts.scm: Test them. Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c Signed-off-by: Giacomo Leidi --- gnu/build/accounts.scm | 37 ++++++++++++++++++++++++--- gnu/system/accounts.scm | 17 +++++++++++++ tests/accounts.scm | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index fa6f454b5e..ea8c69f205 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019, 2021, 2023 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -51,13 +52,23 @@ (define-module (gnu build accounts) group-entry-gid group-entry-members + subid-entry + subid-entry? + subid-entry-name + subid-entry-start + subid-entry-count + %password-lock-file write-group write-passwd write-shadow + write-subgid + write-subuid read-group read-passwd read-shadow + read-subgid + read-subuid %id-min %id-max @@ -68,11 +79,12 @@ (define-module (gnu build accounts) ;;; Commentary: ;;; -;;; This modules provides functionality equivalent to the C library's +;;; This module provides functionality equivalent to the C library's ;;; , , and routines, as well as a subset of the ;;; functionality of the Shadow command-line tools. It can parse and write -;;; /etc/passwd, /etc/shadow, and /etc/group. It can also take care of UID -;;; and GID allocation in a way similar to what 'useradd' does. +;;; /etc/passwd, /etc/shadow, /etc/group, /etc/subuid and /etc/subgid. It can +;;; also take care of UID and GID allocation in a way similar to what 'useradd' +;;; does. The same goes for sub UID and sub GID allocation. ;;; ;;; The benefit is twofold: less code is involved, and the ID allocation ;;; strategy and state preservation is made explicit. @@ -225,6 +237,17 @@ (define-database-entry ; (serialization list->comma-separated comma-separated->list) (default '()))) +(define-database-entry ; + subid-entry make-subid-entry + subid-entry? + (serialization #\: subid-entry->string string->subid-entry) + + (name subid-entry-name) + (start subid-entry-start + (serialization number->string string->number)) + (count subid-entry-count + (serialization number->string string->number))) + (define %password-lock-file ;; The password database lock file used by libc's 'lckpwdf'. Users should ;; grab this lock with 'with-file-lock' when they access the databases. @@ -265,6 +288,10 @@ (define write-shadow (database-writer "/etc/shadow" #o600 shadow-entry->string)) (define write-group (database-writer "/etc/group" #o644 group-entry->string)) +(define write-subuid + (database-writer "/etc/subuid" #o644 subid-entry->string)) +(define write-subgid + (database-writer "/etc/subgid" #o644 subid-entry->string)) (define (database-reader file string->entry) (lambda* (#:optional (file-or-port file)) @@ -287,6 +314,10 @@ (define read-shadow (database-reader "/etc/shadow" string->shadow-entry)) (define read-group (database-reader "/etc/group" string->group-entry)) +(define read-subuid + (database-reader "/etc/subuid" string->subid-entry)) +(define read-subgid + (database-reader "/etc/subgid" string->subid-entry)) ;;; diff --git a/gnu/system/accounts.scm b/gnu/system/accounts.scm index 586cff1842..9a006c188d 100644 --- a/gnu/system/accounts.scm +++ b/gnu/system/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -39,6 +40,12 @@ (define-module (gnu system accounts) user-group-id user-group-system? + subid-range + subid-range? + subid-range-name + subid-range-start + subid-range-count + sexp->user-account sexp->user-group @@ -85,6 +92,16 @@ (define-record-type* (system? user-group-system? ; Boolean (default #f))) +(define-record-type* + subid-range make-subid-range + subid-range? + (name subid-range-name) + (start subid-range-start (default #f)) ; number + (count subid-range-count ; number + ; from find_new_sub_gids.c and + ; find_new_sub_uids.c + (default 65536))) + (define (default-home-directory account) "Return the default home directory for ACCOUNT." (string-append "/home/" (user-account-name account))) diff --git a/tests/accounts.scm b/tests/accounts.scm index 78136390bb..4944c22f49 100644 --- a/tests/accounts.scm +++ b/tests/accounts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -41,6 +42,16 @@ (define %shadow-sample charlie:" (crypt "hey!" "$6$abc") ":17169:::::: nobody:!:0::::::\n")) +(define %subuid-sample + "\ +root:100000:300 +ada:100300:300\n") + +(define %subgid-sample + "\ +root:100000:600 +ada:100600:300\n") + (test-begin "accounts") @@ -135,6 +146,50 @@ (define %shadow-sample read-shadow) port)))) +(test-equal "write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (list (subid-entry + (name "root") + (start 100000) + (count 300)) + (subid-entry + (name "ada") + (start 100300) + (count 300))) + port)))) + +(test-equal "read-subuid + write-subuid" + %subuid-sample + (call-with-output-string + (lambda (port) + (write-subuid (call-with-input-string %subuid-sample + read-subuid) + port)))) + +(test-equal "write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (list (subid-entry + (name "root") + (start 100000) + (count 600)) + (subid-entry + (name "ada") + (start 100600) + (count 300))) + port)))) + +(test-equal "read-subgid + write-subgid" + %subgid-sample + (call-with-output-string + (lambda (port) + (write-subgid (call-with-input-string %subgid-sample + read-subgid) + port)))) + (define allocate-groups (@@ (gnu build accounts) allocate-groups)) (define allocate-passwd (@@ (gnu build accounts) allocate-passwd)) base-commit: a950a89d2f7e6fed8c0a209e5c75f6605e7b469b -- 2.46.0 From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: paul Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 07 Dec 2024 22:36:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.173361092529679 (code B ref 72337); Sat, 07 Dec 2024 22:36:02 +0000 Received: (at 72337) by debbugs.gnu.org; 7 Dec 2024 22:35:25 +0000 Received: from localhost ([127.0.0.1]:48871 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tK3OX-0007ib-A8 for submit@debbugs.gnu.org; Sat, 07 Dec 2024 17:35:25 -0500 Received: from confino.investici.org ([93.190.126.19]:54435) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tK3OV-0007iS-8X for 72337@debbugs.gnu.org; Sat, 07 Dec 2024 17:35:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1733610914; bh=Z4MwhJFL6doqQSn67QLhvvTXY9k2/d2uZsW09LTTLmc=; h=Date:Subject:From:To:Cc:References:In-Reply-To:From; b=N7kZZLBbFbeRv5kzEcEl4oMZ0fXmn5Q4oYo39UEQWDkZ2PuBc51/UTlISLLVQWQTJ Jkplrizdp5hwwQgpFNDZE+se/Ylz9zflQMyKXB+xgvoAYETGiHVzcvEZTYtrZgOURO IdQUWWA36SeYHDFgCctPj8sBIoyeQCQow04Xm0TA= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4Y5NHQ4DB2z111R; Sat, 7 Dec 2024 22:35:14 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4Y5NHQ3Rz0z110M; Sat, 7 Dec 2024 22:35:14 +0000 (UTC) Content-Type: multipart/alternative; boundary="------------ZuxI6IeIdYHtj026N7AWPbhv" Message-ID: Date: Sat, 7 Dec 2024 23:35:13 +0100 MIME-Version: 1.0 User-Agent: Icedove Daily From: paul References: <8737329a065c5436643c6e5e7d52ec760f069725.1725742309.git.goodoldpaul@autistici.org> <2771695a2527240c89c0ba6879aeda0d4ab840ab.1725742309.git.goodoldpaul@autistici.org> <87ploz7v4e.fsf_-_@gnu.org> <45280b7f-dd6e-47b2-87ba-41c68235f50b@autistici.org> Content-Language: en-US In-Reply-To: <45280b7f-dd6e-47b2-87ba-41c68235f50b@autistici.org> X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) This is a multi-part message in MIME format. --------------ZuxI6IeIdYHtj026N7AWPbhv Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Hi Ludo’ , did you have any chance to look at the latest revision of the patches? Thank you for your help, giacomo --------------ZuxI6IeIdYHtj026N7AWPbhv Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit

Hi Ludo’ ,

did you have any chance to look at the latest revision of the patches? Thank you for your help, giacomo

--------------ZuxI6IeIdYHtj026N7AWPbhv-- From unknown Sat Jun 21 03:14:17 2025 X-Loop: help-debbugs@gnu.org Subject: [bug#72337] Add /etc/subuid and /etc/subgid support Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 18 Dec 2024 14:35:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72337 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: Giacomo Leidi Cc: 72337@debbugs.gnu.org Received: via spool by 72337-submit@debbugs.gnu.org id=B72337.173453249425717 (code B ref 72337); Wed, 18 Dec 2024 14:35:01 +0000 Received: (at 72337) by debbugs.gnu.org; 18 Dec 2024 14:34:54 +0000 Received: from localhost ([127.0.0.1]:34051 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tNv8X-0006gi-N0 for submit@debbugs.gnu.org; Wed, 18 Dec 2024 09:34:54 -0500 Received: from eggs.gnu.org ([209.51.188.92]:41204) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tNv8T-0006gP-SY for 72337@debbugs.gnu.org; Wed, 18 Dec 2024 09:34:50 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tNv8N-0004n1-Jl; Wed, 18 Dec 2024 09:34:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=TvdN9XMPC7XYnNNEJqOHeuN+GEh11IyBNYe4OesMFfI=; b=S+2eYk+MkXR5OZ+rUfGo 7Bj7WOpDxVpF98QB9GMHcYdoSRxkn81b8SivGctamipPaoeCNae0kaP3DcnywJZ6RL+IHhZ6GgT8I 716GAaP/FN2WMXL/9AQk2cmgy4AhnYAQoJceKc5sple4JiKROBJEn/2IL3PRdxMu+/oy3PRF6JW/B EnhHXhHnHik011HP8MsxTU5qEaNf/NIImrtdgPDBuejOG5bJbc1u1hP14ovWmg4WVrYAQVrFmu0rZ pNO9Z8M6pAj3gXVjLcGV6haiYZqEp1Hrv5pLEZis6PC3CdmOZyofRkcQtKLLARnZTpHlb4Fc1M9ix i2z89J3S7ltcnA==; From: Ludovic =?UTF-8?Q?Court=C3=A8s?= In-Reply-To: (Giacomo Leidi's message of "Tue, 8 Oct 2024 00:40:27 +0200") References: Date: Wed, 18 Dec 2024 15:34:41 +0100 Message-ID: <874j31kqke.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Hi, Applied (along with the previous one) with one minor nit: Giacomo Leidi skribis: > + &illegal-subid-range-error > + illegal-subid-range-error? > + illegal-subid-range-error-range I changed =E2=80=9Cillegal=E2=80=9D to =E2=80=9Cinvalid=E2=80=9D everywhere. Ludo=E2=80=99. From unknown Sat Jun 21 03:14:17 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: paul Subject: bug#72337: closed (Re: bug#72337: Add /etc/subuid and /etc/subgid support) Message-ID: References: <87v7vhj91t.fsf_-_@gnu.org> X-Gnu-PR-Message: they-closed 72337 X-Gnu-PR-Package: guix-patches Reply-To: 72337@debbugs.gnu.org Date: Wed, 18 Dec 2024 15:39:02 +0000 Content-Type: multipart/mixed; boundary="----------=_1734536342-6312-1" This is a multi-part message in MIME format... ------------=_1734536342-6312-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #72337: Add /etc/subuid and /etc/subgid support which was filed against the guix-patches package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 72337@debbugs.gnu.org. --=20 72337: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D72337 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1734536342-6312-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 72337-done) by debbugs.gnu.org; 18 Dec 2024 15:38:36 +0000 Received: from localhost ([127.0.0.1]:35614 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tNw8A-0001d0-U1 for submit@debbugs.gnu.org; Wed, 18 Dec 2024 10:38:36 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43868) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tNw88-0001cg-2v for 72337-done@debbugs.gnu.org; Wed, 18 Dec 2024 10:38:33 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tNw81-0001D5-GF; Wed, 18 Dec 2024 10:38:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=W45TmLRJVLgo6wVnJexoI3pDimYZWKt2pQRaH0AKhUs=; b=kSF5Av3uHBij1u68BUTn e9WvE56xrFLKunwrWQMxvqs1Ut9JT6GfJFvXZmPp75xnQS1RUny5RgsNJNrbSXxumZ641utk7dkGH ghd8SUnA3LkEW4jGy0Z+gzaWJZgzr/lAPZbNby+T+5T8x2k1mUp2QE244S2Lc62QorEGpqxWhoxRa YL+ebEZBfoH+2StHwLpK0ECokL9GlvDCIXh7SMYcJrGzZ0s3G/6GsEzelGvyD2ELSUrMSWHXZgG+5 ppLiHyNCJhNhJrOSZduXhRI3Dl5GOrKBTJc2nc8QoaidpWxKdids4m6qy8GtzFl3R60LmEF/9GgSH YAvxmtY+YMMQIA==; From: =?utf-8?Q?Ludovic_Court=C3=A8s?= To: Giacomo Leidi Subject: Re: bug#72337: Add /etc/subuid and /etc/subgid support In-Reply-To: <7be849965238ddc6d30c696a5328b6c278d00565.1728340828.git.goodoldpaul@autistici.org> (Giacomo Leidi's message of "Tue, 8 Oct 2024 00:40:28 +0200") References: <7be849965238ddc6d30c696a5328b6c278d00565.1728340828.git.goodoldpaul@autistici.org> Date: Wed, 18 Dec 2024 16:38:22 +0100 Message-ID: <87v7vhj91t.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 72337-done Cc: 72337-done@debbugs.gnu.org, Maxim Cournoyer , Florian Pelz X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Giacomo Leidi skribis: > This commit adds a Guix System service to handle allocation of subuid > and subgid requests. Users that don't care can just add themselves as a > subid-range and don't need to specify anything but their user name. > Users that care about specific ranges, such as possibly LXD, can specify > a start and a count. > > * doc/guix.texi: Document the new service. > * gnu/build/activation.scm (activate-subuids+subgids): New variable. > * gnu/local.mk: Add gnu/tests/shadow.scm. > * gnu/system/accounts.scm (sexp->subid-range): New variable. > * gnu/system/shadow.scm (%root-subid): New variable; > (subids-configuration): new record; > (subid-range->gexp): new variable; > (assert-valid-subids): new variable; > (delete-duplicate-ranges): new variable; > (subids-activation): new variable; > (subids-extension): new record; > (append-subid-ranges): new variable; > (subids-extension-merge): new variable; > (subids-service-type): new variable. > * gnu/tests/shadow.scm (subids): New system test. > > Change-Id: I3755e1c75771220c74fe8ae5de1a7d90f2376635 > Signed-off-by: Giacomo Leidi Applied as well! I took the liberty to make the changes below to the documentation. I=E2=80=99m sorry that it took me so long. I appreciate your patience and = the time you took to polish this patch series; I like the end result! And I realize it=E2=80=99s quite an important feature that will unlock a few thin= gs. Thumbs up! Thanks, Ludo=E2=80=99. --=-=-= Content-Type: text/x-patch Content-Disposition: inline diff --git a/doc/guix.texi b/doc/guix.texi index f49154dc1b..fe84b52052 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -18848,6 +18848,13 @@ User Accounts special-case and is automatically added whether or not it is specified. @end defvar +@cindex containers, subordinate IDs +The Linux kernel also implements @dfn{subordinate user and group IDs}, +or ``subids'', which are used to map the ID of a user and group to +several IDs inside separate name spaces---inside ``containers''. +@xref{subordinate-user-group-ids, the subordinate user and group ID +service}, for information on how to configure it. + @node Keyboard Layout @section Keyboard Layout @@ -41524,13 +41531,15 @@ Miscellaneous Services @c %end of fragment -@cindex Subids -@subsubheading Subid Service +@anchor{subordinate-user-group-ids} +@cindex subordinate user and group IDs +@cindex subid, subordinate user and group IDs +@subsubheading Subordinate User and Group ID Service -Among the virtualization facilities implemented by the Linux kernel, the is the -concept of subordinate IDs. Subordinate IDs allow for mapping user and group +Among the virtualization facilities implemented by the Linux kernel is the +concept of @dfn{subordinate IDs}. Subordinate IDs allow for mapping user and group IDs inside process namespaces to user and group IDs of the host system. -Subordinate user ID ranges (subids) allow to map virtual user IDs inside +Subordinate user ID ranges (subuids) allow users to map virtual user IDs inside containers to the user ID of an unprivileged user of the host system. Subordinate group ID ranges (subgids), instead map virtual group IDs to the group ID of an unprivileged user on the host system. You can access --=-=-=-- ------------=_1734536342-6312-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 28 Jul 2024 15:25:42 +0000 Received: from localhost ([127.0.0.1]:44229 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5mH-0003ro-Jl for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:25:41 -0400 Received: from lists.gnu.org ([209.51.188.17]:52464) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sY5mE-0003rc-OC for submit@debbugs.gnu.org; Sun, 28 Jul 2024 11:25:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sY5m2-0004V0-Uq for guix-patches@gnu.org; Sun, 28 Jul 2024 11:25:26 -0400 Received: from confino.investici.org ([2a11:7980:1::2:0]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sY5m0-00053o-JC; Sun, 28 Jul 2024 11:25:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1722180309; bh=OUwnvqhujTfQ/pGw1McFt2HPEcGsux1nVERDFA8AyTo=; h=Date:To:Cc:From:Subject:From; b=o9TPXbjZYtmR2usVZ2mGu/eh7/89bvl/k2QCI2lRjvnwNOgLSxFJkjPQjpQ7txz6B 530fdE8UKAueDNj57CiW3oivoZ6MqUW4POVZnQdNwoAsurDWLsNKebSmvLtAe+mArp LUcFrBjMQeiMntGdQGFieikHt/WRy1avXdCBHNpw= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4WX5053k9wz112h; Sun, 28 Jul 2024 15:25:09 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4WX50538RHz112f; Sun, 28 Jul 2024 15:25:09 +0000 (UTC) Message-ID: Date: Sun, 28 Jul 2024 17:25:09 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 To: guix-patches@gnu.org Content-Language: en-US From: paul Subject: Add /etc/subuid and /etc/subgid support Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2a11:7980:1::2:0; envelope-from=goodoldpaul@autistici.org; helo=confino.investici.org X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.4 (-) X-Debbugs-Envelope-To: submit Cc: =?UTF-8?Q?Ludovic_Court=c3=a8s?= X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.4 (--) Dear guixers, I'm sending a small patch set to add a Guix System service (hopefully :) ) able to handle /etc/subuid and /etc/subgid . It should be a first step towards a structured rootless-podman-service-type that I plan to implement. Please let me know your thoughts. Ludo’ : I'm CCing you just FYI , this is not an ask for review just in some files your name is the only one in the copyright section and it may be that you are the most familiar with those, but please look at this when and if you have time. Thank you everyone for your work, giacomo ------------=_1734536342-6312-1--