kexec is broken with lanzaboote
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?
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.
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.
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.
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.
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
The solution seems to be to enable/run the
prepare-kexec.serviceservice, 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.
The solution seems to be to enable/run the
prepare-kexec.serviceservice, 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" ];
systemd.services."prepare-kexec".wantedBy = [ "multi-user.target" ];
I added to my configuration and the problems are fixed!
This seems like something that should be sent to NixOS upstream by pinging the @NixOS/systemd team.
If someone can retest kexec on master, let me know. I will try to write test for it before.