[pkg-cryptsetup-devel] Bug#1052290: cryptsetup-initramfs: askpass is not executed; cryptroot-unlock fails
Tj
debian at iam.tj
Wed Sep 20 12:38:39 BST 2023
On 20/09/2023 08:35, Guilhem Moulin wrote:
> Control: tag -1 moreinfo
>
> On Tue, 19 Sep 2023 at 22:39:40 +0100, Tj wrote:
>> Error: Timeout reached while waiting for askpass.
>>
>> After using `break=mount` and investigating with `sh -x
>> /bin/cryptsetup-unlock` it seems it fails because it is not finding
>> `askpass` in the process list.
>
> cryptsetup-unlock waits until the initramfs boot script is blocking on
> passphrase prompt. This is only useful for injecting passphrases from
> outside the initramfs console (for instance from a remote shell).
>
> When you set ‘break=mount’ our boot script isn't running in the
> background, so cryptsetup-unlock timeouts. This is expected. Why are
> you running cryptsetup-unlock in the first place instead of relying on
> the builtin initramfs logic? Also, FWIW ‘break=mount’ breaks *after*
> unlocking whatever block devices need to be unlocked, so cryptsetup-initramfs
> has nothing more to do at this point.
Apologies for a mis-type there; I am using `break=premount`.
The install "appears" to fail to find and unlock both LUKS devices;
it "hangs" (pauses) for a very long time with only kernel messages showing but
no passphrase prompt is shown.
After debugging it turns out the kernel command-line option `debug` and initramfs-tools
`init` script cause the passphrase prompts to be redirected to `initramfs.debug` when askpass
is using "console" output.
It might be better if askpass writes the prompt directly to `/dev/console`. I've done a basic
test and this does work when stdin/stderr are redirected. See end of this email.
Tapping `[Enter]` a few times will sometimes cause a few blank lines to
scroll and seem to move things on since a few more kernel messages are
generated (showing that more udev rules are being triggered).
Eventually, after more taps of `[Enter]` (or maybe due to a coincidental timeout)
it does drop to shell. This is after something like 600 seconds (10 minutes).
Then I find:
REASON=ALERT! UUID=cb2a... does not exist. Dropping to shell!
`/proc/cmdline`: BOOT_IMAGE=/@/boot/vmlinuz... root=UUID=cb2a... ro rootflags=subvol=@ debug systemd.log_level=info
Looking at `/run/initramfs/initramfs.debug` today I see the reason for it failing:
when using `debug` the init script does:
```
debug)
debug=y
quiet=n
if [ -n "${netconsole}" ]; then
log_output=/dev/kmsg
else
log_output=/run/initramfs/initramfs.debug
fi
set -x
;;
```
And looking at `/run/initramfs/initramfs.debug` it has 'captured' the passphrase prompts:
```
+ /scripts/local-top/cryptroot
Please unlock disk luks-88faf2e0-400b-4533-bdab-11ddb8d07fa7:
Nothing to read on input.
cryptsetup: ERROR: luks-88faf2e0-400b-4533-bdab-11ddb8d07fa7: cryptsetup
failed, bad password or options?
Please unlock disk luks-88faf2e0-400b-4533-bdab-11ddb8d07fa7:
Nothing to read on input.
cryptsetup: ERROR: luks-88faf2e0-400b-4533-bdab-11ddb8d07fa7: cryptsetup
failed, bad password or options?
Please unlock disk luks-88faf2e0-400b-4533-bdab-11ddb8d07fa7:
Nothing to read on input.
cryptsetup: ERROR: luks-88faf2e0-400b-4533 if (fwrite(prompt_ptr, line_len, 1, stderr) < 1 ||
fwrite("\n", 1, 1, stderr) < 1) {
-bdab-11ddb8d07fa7: cryptsetup
failed, bad password or options?
cryptsetup: ERROR: luks-88faf2e0-400b-4533-bdab-11ddb8d07fa7: maximum number of
tries exceeded
```
Typing the passphrases blind when the kernel messages 'hang' with a decent pause between them
to allow for the time it takes to 'unlock' allows one to continue starting successfully.
So the issue isn't askpass not running but the lack of a passphrase prompt when using
`debug` on kernel command line AND askpass using its "console" method.
I set `debug` by default on all hosts but on most that use cryptsetup-initramfs the host
is using key-files so never prompts for a passphrase and therefore I never hit this issue before.
Diagnosing why the prompt is 'lost' `run_keyscript()` does:
```
elif [ "$keyscriptarg" = "none" ]; then
# don't export the prompt message as CRYPTTAB_KEY
keyscript="/lib/cryptsetup/askpass"
keyscriptarg="Please unlock disk $CRYPTTAB_NAME: "
fi
exec "$keyscript" "$keyscriptarg"
```
and that is the source of the prompt (there are 2 places where an identical prompt
is set/written).
I enabled DEBUG in `askpass` and copied it into the initrd to capture `/tmp/askpass.debug`
and then allowed init to continue (`exit`).
I had to tap [Enter] a few times to get back to the shell, then looking at the log:
```
Enabling method systemd
Enabling method fifo
Enabling method plymouth
Enabling method console
method 1 has fd 4 and name fifo
method 3 has fd 0 and name console
Starting select with nfds 5
Writing 0 bytes to stdout
Disabling method ALL
```
This is repeated six times (presumably three tries each for the two LUKS devices).
So when using its "console" method stdout is redirected by initramfs-tools `init` when
`debug` is set:
```
if [ -n "$log_output" ]; then
exec >"$log_output" 2>&1
unset log_output
fi
```
and as askpass.c::console_prepare() does:
```
if (fwrite(prompt_ptr, line_len, 1, stderr) < 1 ||
fwrite("\n", 1, 1, stderr) < 1) {
```
the output is swallowed.
I wrote a proof-of-concept to write to `/dev/console` to avoid the redirects and it
appears to work successfully in the initialramfs:
```
(initramfs) /mnt/usb/test_console >/tmp/test.log 2>&1
Testing /dev/console
```
Code:
```
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv, char **env)
{
char *console = "/dev/console";
if (access(console, W_OK) < 0) {
perror("access('/dev/console') ");
return -1;
}
FILE *out = fopen(console, "a");
if (!out) {
fprintf(stderr, "Failed to open %s\n", console);
return -2;
} else {
fprintf(out, "\nTesting %s\n", console);
fclose(out);
}
return 0;
}
```
So I wonder if this would be possible with askpass?
More information about the pkg-cryptsetup-devel
mailing list