lanzaboote icon indicating copy to clipboard operation
lanzaboote copied to clipboard

kexec is broken with lanzaboote

Open jpdisco opened this issue 3 years ago • 11 comments

I am trying to reboot via kexec my computer using systemdctl kexec. This used to work just fine with normal nixos, but I am trying out lanzaboote (very cool btw :)) and it is not working at all anymore.

I now get this error.

Running /nix/store/pjp3v7ni274d1hh7cn4m5yhslgggzbrl-kexec-tools-2.0.25/bin/kexec --load "/boot/EFI/Linux/nixos-generation-294.efi" --append "init=/nix/store/h4mjlcgl479ll843nv43slmaqzr62wd8-nixos-system-poopbox-23.05.20230406.0e19daa/init loglevel=4"(null)
Cannot determine the file type of /boot/EFI/Linux/nixos-generation-294.efi
(kexec) failed with exit status 255.

Is there something I can do to fix this, or is kexec just something that is broken right now?

jpdisco avatar Apr 08 '23 02:04 jpdisco

Can you show the command line that used to work for you before?

Cannot determine the file type of /boot/EFI/Linux/nixos-generation-294.efi

I'm pretty sure kexec doesn't support UEFI binaries. You need to specify the kernel directly for --load. It's one of the bzImage files in EFI/nixos.

blitz avatar Apr 09 '23 08:04 blitz

It looks like you are right about the UEFI binaries, when I disable lanzaboote, it runs load with one of those bzImage files and it works well.

Running /nix/store/pjp3v7ni274d1hh7cn4m5yhslgggzbrl-kexec-tools-2.0.25/bin/kexec --load "/boot/EFI/nixos/zk1jnsj87zc6rl0klly6534sj5q5vzj8-linux-6.9.2-bzImage.efi" --append "init=/nix/store/h4mjlcgl479ll843nv43slmaqzr62wd8-nixos-system-poopbox-23.05.20230406.0e19daa/init loglevel=4(null)

So it seems like when lanzaboote is enabled it tries to load a UEFI binary for some reason.

jpdisco avatar Apr 09 '23 20:04 jpdisco

Looked into it and it seems like kexec has yet to add support for Unified Kernel Images^1. As lanzaboote only emits UKI's onto your ESP that one won't work, as a workaround try to use the kernel and init path provided by /nix/var/nix/profiles/system/boot.json or the other systems/generations.

Myaats avatar Apr 09 '23 21:04 Myaats

I ran into this same problem a few weeks ago. If no kernel is manually loaded for kexec, systemd will try to load the one in the default boot loader entry. Run bootctl status | grep linux:, and it will show which kernel systemd will try to kexec into.

The solution seems to be to enable/run the prepare-kexec.service service, which will run a NixOS provided script to correctly setup kexec.

MatthewCash avatar Apr 09 '23 21:04 MatthewCash

It looks like systemd can either parse the systemd-boot conf to determine the linux kernel to kexec or it just looks in $esp/EFI/Linux, which is where it is getting the lanzaboote image from

I did look into the systemd source code though and noticed there is a functionality to allow other bootloaders to specify this sort of information:

https://github.com/systemd/systemd/blob/v253/src/shared/bootspec.c#L1154-L1159

/* This function is similar to boot_entries_load_config(), however we automatically search for the
 * ESP and the XBOOTLDR partition unless it is explicitly specified. Also, if the user did not pass
 * an ESP or XBOOTLDR path directly, let's see if /run/boot-loader-entries/ exists. If so, let's
 * read data from there, as if it was an ESP (i.e. loading both entries and loader.conf data from
 * it). This allows other boot loaders to pass boot loader entry information to our tools if they
 * want to. */

So we could just synthesize a /run/boot-loader-entries with fake systemd-boot config for the correct kernels/initrds and then systemctl kexec would also work as expected

lilyinstarlight avatar Apr 09 '23 21:04 lilyinstarlight

The solution seems to be to enable/run the prepare-kexec.service service, which will run a NixOS provided script to correctly setup kexec.

This service is already enabled, but for some reason it doesn't get run automatically.

alois31 avatar Apr 10 '23 17:04 alois31

The solution seems to be to enable/run the prepare-kexec.service service, which will run a NixOS provided script to correctly setup kexec.

This service is already enabled, but for some reason it doesn't get run automatically.

I meant enable as in run on startup, like the systemctl enable command, so on NixOS you would set

systemd.services."prepare-kexec".wantedBy = [ "multi-user.target" ];

MatthewCash avatar Apr 10 '23 17:04 MatthewCash

systemd.services."prepare-kexec".wantedBy = [ "multi-user.target" ];

I added to my configuration and the problems are fixed!

jpdisco avatar Apr 11 '23 22:04 jpdisco

This seems like something that should be sent to NixOS upstream by pinging the @NixOS/systemd team.

RaitoBezarius avatar Apr 12 '23 12:04 RaitoBezarius

If someone can retest kexec on master, let me know. I will try to write test for it before.

RaitoBezarius avatar May 18 '23 19:05 RaitoBezarius