From: "Ludovic Courtès" <ludo@gnu.org>
To: 54770@debbugs.gnu.org
Subject: bug#54770: Non-root LUKS devices unusable after Shepherd upgrade
Date: Fri, 08 Apr 2022 11:32:17 +0200 [thread overview]
Message-ID: <87mtgvdiou.fsf@gnu.org> (raw)
In-Reply-To: <87r168etvd.fsf@inria.fr> ("Ludovic Courtès"'s message of "Thu, 07 Apr 2022 18:33:10 +0200")
[-- Attachment #1: Type: text/plain, Size: 2748 bytes --]
Hi,
Ludovic Courtès <ludo@gnu.org> skribis:
> Following the Shepherd upgrade in commit
> 400c9ed3d779308e56038305d40cd93acb496180, attempts to open non-root LUKS
> devices from a Shepherd service fail with this cryptsetup message:
>
> Nothing to read on input.
>
> This is because standard input is now /dev/null so it cannot read the
> passphrase.
In Cryptsetup, the ‘tools_get_key’ function reads this:
--8<---------------cut here---------------start------------->8---
if (tools_is_stdin(key_file)) {
if (isatty(STDIN_FILENO)) {
if (keyfile_offset) {
log_err(_("Cannot use offset with terminal input."));
} else {
if (!prompt && !crypt_get_device_name(cd))
snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
else if (!prompt) {
backing_file = crypt_loop_backing_file(crypt_get_device_name(cd));
snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd));
free(backing_file);
}
r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify, cd);
}
} else {
log_dbg("STDIN descriptor passphrase entry requested.");
/* No keyfile means STDIN with EOL handling (\n will end input)). */
r = crypt_keyfile_device_read(cd, NULL, key, key_size,
keyfile_offset, keyfile_size_max,
key_file ? 0 : CRYPT_KEYFILE_STOP_EOL);
}
}
--8<---------------cut here---------------end--------------->8---
isatty(3) would return 0 when stdin is /dev/null; simply binding stdin
to /dev/console:
(with-input-from-file "/dev/console"
(lambda ()
(system* "cryptsetup" …)))
wouldn’t help, for reasons that are less clear to me¹.
The attached patch solves the ‘cryptsetup open’ problem for the case
when ‘cryptsetup’ is invoked from shepherd—e.g., for an encrypted /home.
I’m now running the “encrypted-root-os” test.
I’m not sure how to test fsck interactivity though; ideas welcome. If
you’re reading this and would like to test it on the bare metal (worst
case is it fails to boot and you have to reboot into the older
generation), that’s also much appreciated.
Feedback welcome!
Thanks,
Ludo’.
¹ This returns true:
sudo strace -f -o ,,s guile -c '(with-input-from-file "/dev/console" (lambda () (system* "guile" "-c" "(pk (isatty? (current-input-port)))")))'
[-- Attachment #2: Type: text/x-patch, Size: 13483 bytes --]
diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm
index d95340df83..b06a4cc25c 100644
--- a/gnu/build/file-systems.scm
+++ b/gnu/build/file-systems.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014-2018, 2020-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016, 2017 David Craven <david@craven.ch>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019 Guillaume Le Vaillant <glv@posteo.net>
@@ -54,6 +54,7 @@ (define-module (gnu build file-systems)
bind-mount
+ system*/tty
mount-flags->bit-mask
check-file-system
mount-file-system
@@ -67,6 +68,33 @@ (define-module (gnu build file-systems)
;;;
;;; Code:
+(define (system*/console program . args)
+ "Run PROGRAM with ARGS in a tty on top of /dev/console. The return value is
+as for 'system*'."
+ (match (primitive-fork)
+ (0
+ (dynamic-wind
+ (const #t)
+ (lambda ()
+ (login-tty (open-fdes "/dev/console" O_RDWR))
+ (apply execlp program program args))
+ (lambda ()
+ (primitive-_exit 127))))
+ (pid
+ (cdr (waitpid pid)))))
+
+(define (system*/tty program . args)
+ "Run PROGRAM with ARGS, creating a tty if its standard input isn't one.
+The return value is as for 'system*'.
+
+This is necessary for commands such as 'cryptsetup open' or 'fsck' that may
+need to interact with the user but might be invoked from shepherd, where
+standard input is /dev/null."
+ (apply (if (isatty? (current-input-port))
+ system*
+ system*/console)
+ program args))
+
(define (bind-mount source target)
"Bind-mount SOURCE at TARGET."
(mount source target "" MS_BIND))
@@ -180,13 +208,13 @@ (define (check-ext2-file-system device force? repair)
do not write to the file system to fix errors. If it's #t, fix all
errors. Otherwise, fix only those considered safe to repair automatically."
(match (status:exit-val
- (apply system* `("e2fsck" "-v" "-C" "0"
- ,@(if force? '("-f") '())
- ,@(match repair
- (#f '("-n"))
- (#t '("-y"))
- (_ '("-p")))
- ,device)))
+ (apply system*/tty "e2fsck" "-v" "-C" "0"
+ `(,@(if force? '("-f") '())
+ ,@(match repair
+ (#f '("-n"))
+ (#t '("-y"))
+ (_ '("-p")))
+ ,device)))
(0 'pass)
(1 'errors-corrected)
(2 'reboot-required)
@@ -312,14 +340,14 @@ (define (check-bcachefs-file-system device force? repair)
(status
;; A number, or #f on abnormal termination (e.g., assertion failure).
(status:exit-val
- (apply system* `("bcachefs" "fsck" "-v"
- ,@(if force? '("-f") '())
- ,@(match repair
- (#f '("-n"))
- (#t '("-y"))
- (_ '("-p")))
- ;; Make each multi-device member a separate argument.
- ,@(string-split device #\:))))))
+ (apply system*/tty "bcachefs" "fsck" "-v"
+ `(,@(if force? '("-f") '())
+ ,@(match repair
+ (#f '("-n"))
+ (#t '("-y"))
+ (_ '("-p")))
+ ;; Make each multi-device member a separate argument.
+ ,@(string-split device #\:))))))
(match (and=> status (cut logand <> (lognot ignored-bits)))
(0 'pass)
(1 'errors-corrected)
@@ -364,17 +392,17 @@ (define (check-btrfs-file-system device force? repair)
fix only those considered safe to repair automatically."
(if force?
(match (status:exit-val
- (apply system* `("btrfs" "check" "--progress"
- ;; Btrfs's ‘--force’ is not relevant to us here.
- ,@(match repair
- ;; Upstream considers ALL repairs dangerous
- ;; and will warn the user at run time.
- (#t '("--repair"))
- (_ '("--readonly" ; a no-op for clarity
- ;; A 466G file system with 180G used is
- ;; enough to kill btrfs with 6G of RAM.
- "--mode" "lowmem")))
- ,device)))
+ (apply system*/tty "btrfs" "check" "--progress"
+ ;; Btrfs's ‘--force’ is not relevant to us here.
+ `(,@(match repair
+ ;; Upstream considers ALL repairs dangerous
+ ;; and will warn the user at run time.
+ (#t '("--repair"))
+ (_ '("--readonly" ; a no-op for clarity
+ ;; A 466G file system with 180G used is
+ ;; enough to kill btrfs with 6G of RAM.
+ "--mode" "lowmem")))
+ ,device)))
(0 'pass)
(_ 'fatal-error))
'pass))
@@ -412,11 +440,11 @@ (define (check-fat-file-system device force? repair)
not write to the file system to fix errors. Otherwise, automatically fix them
using the least destructive approach."
(match (status:exit-val
- (apply system* `("fsck.vfat" "-v"
- ,@(match repair
- (#f '("-n"))
- (_ '("-a"))) ; no 'safe/#t distinction
- ,device)))
+ (system*/tty "fsck.vfat" "-v"
+ (match repair
+ (#f "-n")
+ (_ "-a")) ;no 'safe/#t distinction
+ device))
(0 'pass)
(1 'errors-corrected)
(_ 'fatal-error)))
@@ -545,7 +573,7 @@ (define (check-jfs-file-system device force? repair)
only if FORCE? is true. Otherwise, replay the transaction log before checking
and automatically fix found errors."
(match (status:exit-val
- (apply system*
+ (apply system*/tty
`("jfs_fsck" "-v"
;; The ‘LEVEL’ logic is convoluted. To quote fsck/xchkdsk.c
;; (‘-p’, ‘-a’, and ‘-r’ are aliases in every way):
@@ -621,10 +649,10 @@ (define (check-f2fs-file-system device force? repair)
"warning: forced check of F2FS ~a implies repairing any errors~%"
device))
(match (status:exit-val
- (apply system* `("fsck.f2fs"
- ,@(if force? '("-f") '())
- ,@(if repair '("-p") '("--dry-run"))
- ,device)))
+ (apply system*/tty "fsck.f2fs"
+ `(,@(if force? '("-f") '())
+ ,@(if repair '("-p") '("--dry-run"))
+ ,device)))
;; 0 and -1 are the only two possibilities according to the man page.
(0 'pass)
(_ 'fatal-error)))
@@ -709,9 +737,9 @@ (define (check-ntfs-file-system device force? repair)
true and the volume has been repaired by an external tool, clear the volume
dirty flag to indicate that it's now safe to mount."
(match (status:exit-val
- (apply system* `("ntfsfix"
- ,@(if repair '("--clear-dirty") '("--no-action"))
- ,device)))
+ (system*/tty "ntfsfix"
+ (if repair "--clear-dirty" "--no-action")
+ device))
(0 'pass)
(_ 'fatal-error)))
@@ -754,11 +782,11 @@ (define (check-xfs-file-system device force? repair)
Otherwise, only replay the log, and check without attempting further repairs."
(define (xfs_repair)
(status:exit-val
- (apply system* `("xfs_repair" "-Pv"
- ,@(match repair
- (#t '("-e"))
- (_ '("-n"))) ; will miss some errors
- ,device))))
+ (system*/tty "xfs_repair" "-Pv"
+ (match repair
+ (#t "-e")
+ (_ "-n")) ;will miss some errors
+ device)))
(if force?
;; xfs_repair fails with exit status 2 if the log is dirty, which is
;; likely in situations where you're running xfs_repair. Only the kernel
diff --git a/gnu/system/mapped-devices.scm b/gnu/system/mapped-devices.scm
index 96a381d5fe..e6b8970c12 100644
--- a/gnu/system/mapped-devices.scm
+++ b/gnu/system/mapped-devices.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Andreas Enge <andreas@enge.fr>
;;; Copyright © 2017, 2018 Mark H Weaver <mhw@netris.org>
;;;
@@ -202,7 +202,8 @@ (define (open-luks-device source targets)
;; XXX: 'use-modules' should be at the top level.
(use-modules (rnrs bytevectors) ;bytevector?
((gnu build file-systems)
- #:select (find-partition-by-luks-uuid))
+ #:select (find-partition-by-luks-uuid
+ system*/tty))
((guix build utils) #:select (mkdir-p)))
;; Create '/run/cryptsetup/' if it does not exist, as device locking
@@ -211,28 +212,32 @@ (define (open-luks-device source targets)
;; Use 'cryptsetup-static', not 'cryptsetup', to avoid pulling the
;; whole world inside the initrd (for when we're in an initrd).
- (zero? (system* #$(file-append cryptsetup-static "/sbin/cryptsetup")
- "open" "--type" "luks"
+ ;; 'cryptsetup open' requires standard input to be a tty to allow
+ ;; for interaction but shepherd sets standard input to /dev/null;
+ ;; thus, explicitly request a tty.
+ (zero? (system*/tty
+ #$(file-append cryptsetup-static "/sbin/cryptsetup")
+ "open" "--type" "luks"
- ;; Note: We cannot use the "UUID=source" syntax here
- ;; because 'cryptsetup' implements it by searching the
- ;; udev-populated /dev/disk/by-id directory but udev may
- ;; be unavailable at the time we run this.
- (if (bytevector? source)
- (or (let loop ((tries-left 10))
- (and (positive? tries-left)
- (or (find-partition-by-luks-uuid source)
- ;; If the underlying partition is
- ;; not found, try again after
- ;; waiting a second, up to ten
- ;; times. FIXME: This should be
- ;; dealt with in a more robust way.
- (begin (sleep 1)
- (loop (- tries-left 1))))))
- (error "LUKS partition not found" source))
- source)
+ ;; Note: We cannot use the "UUID=source" syntax here
+ ;; because 'cryptsetup' implements it by searching the
+ ;; udev-populated /dev/disk/by-id directory but udev may
+ ;; be unavailable at the time we run this.
+ (if (bytevector? source)
+ (or (let loop ((tries-left 10))
+ (and (positive? tries-left)
+ (or (find-partition-by-luks-uuid source)
+ ;; If the underlying partition is
+ ;; not found, try again after
+ ;; waiting a second, up to ten
+ ;; times. FIXME: This should be
+ ;; dealt with in a more robust way.
+ (begin (sleep 1)
+ (loop (- tries-left 1))))))
+ (error "LUKS partition not found" source))
+ source)
- #$target)))))))
+ #$target)))))))
(define (close-luks-device source targets)
"Return a gexp that closes TARGET, a LUKS device."
next prev parent reply other threads:[~2022-04-08 9:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-07 16:33 bug#54770: Non-root LUKS devices unusable after Shepherd upgrade Ludovic Courtès
2022-04-08 9:32 ` Ludovic Courtès [this message]
2022-04-08 13:34 ` Ludovic Courtès
2022-04-08 16:18 ` Ludovic Courtès
2022-04-09 14:51 ` Christoph Weiss
2022-04-11 12:39 ` Ludovic Courtès
2022-04-11 17:07 ` bug#54770: (no subject) Christoph Weiss
2022-04-12 8:41 ` bug#54770: Non-root LUKS devices unusable after Shepherd upgrade Ludovic Courtès
2022-04-12 17:00 ` Christoph Weiss
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87mtgvdiou.fsf@gnu.org \
--to=ludo@gnu.org \
--cc=54770@debbugs.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/guix.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).