-
Notifications
You must be signed in to change notification settings - Fork 38
feat: enable basic systemd-boot support #978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Hi @p5. Thanks for your PR. I'm waiting for a coreos member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces initial support for systemd-boot
. It's a work-in-progress, adding a new systemd_boot_configs
module and modifying the EFI component installation logic to handle systemd-boot
entries and bootctl
.
My review focuses on correctness and robustness. I've found a few critical issues in the new systemd_boot_configs.rs
file related to incorrect path and UUID generation for the bootloader entries, which would likely prevent the system from booting. I've also pointed out a potential panic in efi.rs
due to an unsafe unwrap.
Additionally, there are several places where log::warn
is used for debugging; these should be reverted to more appropriate log levels. There are also some hardcoded values and logic that are marked as TODOs in the PR description, which I've also commented on for completeness.
Overall, this is a good start, and addressing the feedback will significantly improve the correctness and stability of the new functionality.
First I think we can add a build time option which entirely disables GRUB support. Then it's simple on UEFI platforms and where systemd-boot is in the target, we use it by default. But for dynamic detection one way to do this would be to detect if the target system is both:
Also of course, if the target image doesn't have grub then we should default to systemd-boot. |
Would you mind if I went straight for the dynamic detection? |
Yes of course that's fine!
Yeah, makes sense. |
This comment was marked as outdated.
This comment was marked as outdated.
Discussed in Bootc Weekly Community Meeting This will check if grub is present, and use it. |
This comment was marked as outdated.
This comment was marked as outdated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces foundational support for systemd-boot
by adding logic to detect its presence and proxying installation to bootctl
. The changes are generally well-structured, introducing a systemd-boot
feature flag and updating the component model to be aware of different bootloaders. However, there are a couple of significant issues. A critical issue will cause a compilation failure on riscv64
due to a missing architecture-specific configuration. Additionally, there's a high-severity issue where loader.conf
is sourced from the host's filesystem instead of the specified source root, which breaks the encapsulation of bootupd
's operations. My review includes suggestions to fix these problems.
ab12d29
to
f3da9f1
Compare
let esp_path_str = esp_path_buf | ||
.to_str() | ||
.context("ESP path is not valid UTF-8")?; | ||
let status = std::process::Command::new("bootctl") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't be able to use bootctl isntall
by default here as that's skipping shim entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, understood.
Would you suggest doing something like this (but pointing to the right paths)?
efibootmgr --disk /dev/sda --part 1 --create --label "Linux Secure Boot" --loader '\EFI\Systemd\shimx64.efi' --unicode '\EFI\Systemd\systemd-bootx64.efi'
Will need to figure out a way to identify the shim without reintroducing the RPM code.
Though with this approach, we can probably still use bootctl install
, but optionally followed by copying the shim and running efibootmgr if the shim is detected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I did not know that we could pass arguments to shim! If this works then this is great. We should probably install the systemd-boot binary under the os path: /EFI/<os|fedora|arch>/systemd-bootx64.efi
to not have a "global" instance of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't be able to use bootctl isntall by default here as that's skipping shim entirely.
For sealed images we do want to skip shim though right?
Will need to figure out a way to identify the shim without reintroducing the RPM code.
I think it should be the same as detecting grub ideally. I'm not sure we care about grub-but-not-shim (hopefully?) but we do care about the matrix of:
- shim+grub
- shim+systemd-boot
- systemd-boot
So...I think we can reasonably do this by detecting if we have shim*.efi
in the image.
Would you suggest doing something like [https://github.com/systemd/systemd/issues/27234#issuecomment-2424826157] (but pointing to the right paths)?
Hmm AFAIK efibootmgr is primarily for manipulating the EFI firmware, which is distinct from the files on disk. We already have code which...currently hardcodes targeting shim, which would definitely have to change for sealed images.
Note that we should not rely on systemd's systemd-boot-update.service either for updates as it does not update shim. |
Ok. So it seems like it would be better (though not necessarily simpler) to add full systemd-boot support into bootupd, rather than proxying bootctl as we initially thought. This being This PR started off as "a super thin wrapper for systemd-boot" but seems to be turning into a larger implementation. I'll certainly keep looking into it, but if the Bootc team are working to a tighter schedule, please feel free to forge on ahead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Overall this looks sane, and we can likely just get it in with some minor tweaks.
let esp_path_str = esp_path_buf | ||
.to_str() | ||
.context("ESP path is not valid UTF-8")?; | ||
let status = std::process::Command::new("bootctl") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't be able to use bootctl isntall by default here as that's skipping shim entirely.
For sealed images we do want to skip shim though right?
Will need to figure out a way to identify the shim without reintroducing the RPM code.
I think it should be the same as detecting grub ideally. I'm not sure we care about grub-but-not-shim (hopefully?) but we do care about the matrix of:
- shim+grub
- shim+systemd-boot
- systemd-boot
So...I think we can reasonably do this by detecting if we have shim*.efi
in the image.
Would you suggest doing something like [https://github.com/systemd/systemd/issues/27234#issuecomment-2424826157] (but pointing to the right paths)?
Hmm AFAIK efibootmgr is primarily for manipulating the EFI firmware, which is distinct from the files on disk. We already have code which...currently hardcodes targeting shim, which would definitely have to change for sealed images.
log::info!("loader.conf copied to {}", dst_loader_conf.display()); | ||
Ok(()) | ||
} | ||
Err(e) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should only match if this is ENOENT
, but propagate other errors.
For cap-std-ext we have https://docs.rs/cap-std-ext/latest/cap_std_ext/dirext/trait.CapStdExtDirExt.html#tymethod.open_optional but we're not yet using cap-std here...
.status() | ||
.context("Failed to execute bootctl")?; | ||
|
||
if !status.success() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use our helper trait .run_with_cmd_context()
or so
/// This mostly proxies the bootctl install command | ||
#[context("Installing systemd-boot")] | ||
pub(crate) fn install(src_root: &openat::Dir, esp_path: &openat::Dir) -> Result<()> { | ||
let esp_path_buf = esp_path.recover_path().context("ESP path is not valid")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using recover_path()
a trick is to pass the fd to the child via its working directory. Again in cap-std-ext we have https://docs.rs/cap-std-ext/latest/cap_std_ext/cmdext/trait.CapStdExtCommandExt.html#tymethod.cwd_dir
if std::env::var("CARGO_FEATURE_SYSTEMD_BOOT").is_ok() { | ||
if let Ok(arch) = std::env::var("CARGO_CFG_TARGET_ARCH") { | ||
if arch.starts_with("riscv") { | ||
panic!("The systemd-boot feature is not supported on RISC-V."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, this whole build.rs seems like it could use a comment for why; I'm sure some RISC-V systems aren't UEFI but it looks like at least some are working on it e.g. https://archive.fosdem.org/2021/schedule/event/firmware_uor/#:~:text=Online%20%2F%206%20%26%207%20February%202021,EDK2%20UEFI%20on%20RISC%2DV
Do we actually fail to build on RISC-V in this case?
crate::systemdbootconfigs::install(src_root, &esp_dir)?; | ||
return Ok(InstalledContent { | ||
meta: ContentMetadata { | ||
timestamp: Utc::now(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This timestamp should be sourced from the bootctl
binary
/// Determine whether the necessary bootloader files are present for systemd-boot. | ||
#[cfg(feature = "systemd-boot")] | ||
fn has_systemd_boot(source_root: &openat::Dir) -> bool { | ||
source_root.open_file(efi::SYSTEMD_BOOT_EFI).is_ok() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super minor but doing a stat()
instead of open()
is slightly more efficient i.e. use source_root.metadata()
Yeah makes sense. Do you want someone else on the team to pick this up? And thanks so much for starting it and sorry for the delay in reviews! |
I'm more than happy to continue looking into this, but I am not wanting to block the bootc systemd-boot implementation with this PR if your team is planning to implement it sooner. Your team will have far more context in this space and know how the different parts should fit together. I'm tempted to create a separate branch/draft PR though since people seem to be starting to target this one for experimental non-RPM based images which I don't want to be breaking (although I've made it clear in Discord that it shouldn't be trusted yet :)). It's clear there's a lot of interest in using Bootc outside the Red Hat ecosystem now this is proven to (mostly) work with the cfs backend, and support here is the primary blocker right now. |
src/bootupd.rs
Outdated
|
||
/// Determine whether the necessary bootloader files are present for GRUB. | ||
fn has_grub(source_root: &openat::Dir) -> bool { | ||
source_root.open_file(bios::GRUB_BIN).is_ok() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this causes build error on arch other than powerpc64 or x86_64 due to arch specific use of bios crate on line 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a temporary workaround, I've hardcoded the GRUB_BIN value in the function. Should compile on other architectures now.
Will be fixed properly when I get chance to implement some of the larger refactors requested in other comments.
As you can probably tell, you're the first to try and run on ARM so please let me know if you face any other issues!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isn't there a "thank you" reaction emoji?
thank you.
Signed-off-by: Robert Sturla <[email protected]>
PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
Making it a separated comment:
We also want shim for sealed images. Fedora CoreOS & Atomic Desktops will provide sealed images signed by the Fedora key and a user would extend things locally by enrolling another key via MOK. It's also unlikely that systemd-boot itself would be signed for Secure Boot directly. It would be signed by the Fedora key that is carried in shim so we need it in the bootchain. I agree that we should support setups without shim as well for users that want to fully control the chain and enroll their own keys in the firmware. We need both 🙂. |
So shim support is also important for other distribution to get Secure Boot working. |
This just invokes bootctl to setup systemd-boot.
TODO: