From d497b6ab397273cd250003b6266f22ad74f4c20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Mon, 3 Jun 2019 17:14:17 +0200 Subject: [PATCH] activation: Lock /etc/.pwd.lock before accessing databases. Suggested by Florian Pelz in . * gnu/build/accounts.scm (%password-lock-file): New variable. * gnu/build/activation.scm (activate-users+groups): Wrap calls to 'user+group-databases', 'write-group', etc. into 'with-file-lock'. --- gnu/build/accounts.scm | 6 ++++++ gnu/build/activation.scm | 33 +++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm index c43ce85b60..8687446aa6 100644 --- a/gnu/build/accounts.scm +++ b/gnu/build/accounts.scm @@ -51,6 +51,7 @@ group-entry-gid group-entry-members + %password-lock-file write-group write-passwd write-shadow @@ -224,6 +225,11 @@ each field." (serialization list->comma-separated comma-separated->list) (default '()))) +(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. + "/etc/.pwd.lock") + (define (database-writer file mode entry->string) (lambda* (entries #:optional (file-or-port file)) "Write ENTRIES to FILE-OR-PORT. When FILE-OR-PORT is a file name, write diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index cfdf17df0f..c6c7e7fd3b 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -22,6 +22,7 @@ #:use-module (gnu build accounts) #:use-module (gnu build linux-boot) #:use-module (guix build utils) + #:use-module ((guix build syscalls) #:select (with-file-lock)) #:use-module (ice-9 ftw) #:use-module (ice-9 match) #:use-module (ice-9 vlist) @@ -129,22 +130,26 @@ group records) are all available." ;; Allow home directories to be created under /var/lib. (mkdir-p "/var/lib") - (let-values (((groups passwd shadow) - (user+group-databases users groups))) - (write-group groups) - (write-passwd passwd) - (write-shadow shadow) + ;; Take same lock as libc's 'lckpwdf' (but without a timeout) 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 %password-lock-file + (let-values (((groups passwd shadow) + (user+group-databases users groups))) + (write-group groups) + (write-passwd passwd) + (write-shadow shadow))) - ;; Home directories of non-system accounts are created by - ;; 'activate-user-home'. - (for-each make-home-directory system-accounts) + ;; Home directories of non-system accounts are created by + ;; 'activate-user-home'. + (for-each make-home-directory system-accounts) - ;; Turn shared home directories, such as /var/empty, into root-owned, - ;; read-only places. - (for-each (lambda (directory) - (chown directory 0 0) - (chmod directory #o555)) - (duplicates (map user-account-home-directory system-accounts))))) + ;; Turn shared home directories, such as /var/empty, into root-owned, + ;; read-only places. + (for-each (lambda (directory) + (chown directory 0 0) + (chmod directory #o555)) + (duplicates (map user-account-home-directory system-accounts)))) (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless