anatol/booster

`extra_files: fido2-assert` can't unlock w/ systemd-cryptenroll -ed Yubikey

Closed this issue · 4 comments

5long commented

My root partition is a Btrfs on a LUKS2 encrypted partition with a Yubikey 5 NFC enrolled with systemd-cryptenroll --fido2-device=auto at slot 1. I can successfully boot the system with a mkinitcpio generated initramfs-linux-{lts,zen}.img.

With the following environment & config for booster:

  • OS: Arch Linux
  • Booster version: both 0.10-1 and 0.10-2 from Arch official repo
  • Bootloader: systemd-boot from systemd=253.6-2
  • Kernel: both linux-zen=6.4.* and linux-lts=6.1.* (probably doesn't matter)

/etc/booster.yaml:

modules_force_load: i915
modules: vmd,i915,intel_lpss_pci
extra_files: fido2-assert

/boot/loader/entries/arch-lts.conf:

title Arch LTS
linux /vmlinuz-linux-lts
initrd /intel-ucode.img
initrd /booster-linux-lts.img
options rd.luks.name=<REDACTED UUID>=arch root=/dev/mapper/arch rootflags=subvol=@ rw add_efi_memmap random.trust_cpu=on intel_iommu=on

Expected behavior: when the screen shows Enter passphase for arch:, with my Yubikey plugged in, the LED on the Yubikey should be flashing. Touching the Yubikey (the metal part, that is) should unlock the LUKS partition and continue the boot process

Actual behavior: The LED on the Yubikey is not flashing. Touching the Yubikey would result a screen showing this:

Enter passphase for arch:   Unlocking...
   Incorrect passphrase, please try again
Enter passphase for arch:

I can still unlock w/ the passphrase at slot 0.

Attempted fiddling 1: use absolute path, avoid symlink directory (/bin)

This idea comes from mkinitcpio: all the executables in the images initramfs-* are located in /usr/bin/ instead of /bin/.

  • In /etc/booster.yaml, replace the line extra_files: fido2-assert with extra_files: /usr/bin/fido2-assert
  • Rebuild image with /usr/lib/booster/regenerate_images
  • Reboot

...and the expected behavior actually happens.

Attempted fiddling 2: throw in /bin/setfont to debug

Technically speaking this isn't really necessary for me -- the early userspace console looks exactly the same with or without vconsole: true for now.

  • Append a line vconsole: true to /etc/booster.yaml
  • fido2-assert is still loaded by extra_files: fido2-assert, putting it at /bin/fido2-assert
  • Rebuild image
  • Reboot

Now the boot process is stuck at

[1.<can't remember exact number here>] booster: exec: "setfont": executable file not found in $PATH
Press ENTER to reboot

Looking at booster ls /boot/booster-linux-lts.img, /bin/setfont is present (along with /bin/fido2-assert) in the image.

Attempt to booster unpack /boot/booster-linux-lts.img /tmp would print a line of error: 2023/07/16 01:50:39 mkdir /tmp/bin: file exists (not sure if this helps but FWIW)

Attempted fiddling 3: 1 and 2 combined

  • Rebuild image with both extra_files: /usr/bin/fido2-assert and vconsole: true, resulted images with /usr/bin/fido2-assert and /bin/setfont
  • Reboot

Expected behavior happens: no setfont error, touched Yubikey to unlock. Feels confused but okay.

Attempted fiddling 4: build a universal image

... with a line universal: true in /etc/booster.yaml, no full path of fido2-assert, no vconsole, problem still exists.

I'm not sure if this is an issue with booster or my own setup. For now I can totally get my boot process back to working condition with extra_files: /usr/bin/fido2-assert without having to use mkinitcpio (which is pretty slow compared to booster).

5long commented

I think I've found the root cause:

  • On my system I've been running opendoas instead of good old sudo
  • opendoas sets the PATH environment variable to a hardcode set of "safepath" instead of inheriting the value of $PATH from current shell
  • and this "safepath" puts /bin at the top of the list
  • booster build picks up executables in /bin because it's at the top of the list

sudo has a simillar setting named secure_path but somehow plays nice with booster. I just tried running sudo booster build ... and images have /usr/bin/fido2-assert which should work just fine.

But still, right now booster(1) claims that a relative path is resolved from /usr/bin without mentioning the PATH environmental variable. Meanwhile in CHANGES.md (which is not necessarily packaged by Linux distros) it claims that booster will actually lookup executables in PATH.

Before I could come up with some constructive suggestions I could really use a break...

anatol commented

Hello @5long thank you for this extensive analysis.

right now booster(1) claims that a relative path is resolved from /usr/bin without mentioning the PATH environmental variable. Meanwhile in CHANGES.md (which is not necessarily packaged by Linux distros) it claims that booster will actually lookup executables in PATH.

Until recently booster was using golan's exec.LookPath function that is relying on PATH envvar.

But recently (commit 7766b07) booster has switched to predefined list of directories to lookup. It was done for the security and reproducibility reasons. The list is here

paths := []string{
"/usr/bin",
"/usr/sbin",
"/bin",
"/sbin",
"/usr/local/bin",
"/usr/local/sbin",
}
.

The change is not part of a released version. It targets the upcoming 0.11 release.

@5long By any chance, are you still experiencing this issue? On my host machine, booster's default minimal generated initramfs would not reliably unlock my encrypted device using a Yubikey unless it was configured to generate a universal image.

I was able to get around this by force loading my graphics module, usbhid and hid_sensor_hub.

booster.yaml:

modules_force_load: amdgpu,usbhid,hid_sensor_hub
extra_files: fido2-assert

5long commented

@c3Ls1US Upgrading to booster=v0.11-1 solved my issue. Can't be of help here, sorry.