Skip to content

Conversation

p5
Copy link

@p5 p5 commented Aug 8, 2025

This just invokes bootctl to setup systemd-boot.

TODO:

  • Figure out the public API we wish to expose for enabling sd-boot
  • Correctly detect whether to install with sd-boot or grub
  • Figure out how to boot without emergency mode
  • Everything else

Copy link

openshift-ci bot commented Aug 8, 2025

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 /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

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.

@p5 p5 changed the title [WIP] feat: enable systemd-boot support [WIP] feat: enable systemd-boot/UKIs support Aug 8, 2025
Copy link

@gemini-code-assist gemini-code-assist bot left a 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.

@cgwalters cgwalters marked this pull request as ready for review August 15, 2025 11:23
@cgwalters cgwalters marked this pull request as draft August 15, 2025 11:24
@cgwalters
Copy link
Member

Figure out the public API we wish to expose for enabling sd-boot

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.

@p5
Copy link
Author

p5 commented Aug 15, 2025

Would you mind if I went straight for the dynamic detection?
I'm trying to gate grub behind a feature flag, but doing so rapidly turns the codebase into a mess because it also means disabling bios and ostree (currently).

@p5 p5 force-pushed the sdboot-support branch from 9d5eb1a to 912de59 Compare August 15, 2025 12:49
@cgwalters
Copy link
Member

Would you mind if I went straight for the dynamic detection?

Yes of course that's fine!

I'm trying to gate grub behind a feature flag, but doing so rapidly turns the codebase into a mess because it also means disabling bios and ostree (currently).

Yeah, makes sense.

@p5

This comment was marked as outdated.

@p5
Copy link
Author

p5 commented Aug 29, 2025

Discussed in Bootc Weekly Community Meeting

This will check if grub is present, and use it.
If grub is not present, use sd-boot.
If neither is present, explode.

@p5 p5 force-pushed the sdboot-support branch from 23d044c to a350c97 Compare August 30, 2025 10:31
@p5 p5 changed the title [WIP] feat: enable systemd-boot/UKIs support [WIP] feat: enable basic systemd-boot support Aug 30, 2025
@p5

This comment was marked as outdated.

Copy link

@gemini-code-assist gemini-code-assist bot left a 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.

@p5 p5 force-pushed the sdboot-support branch from a350c97 to 5f916c3 Compare August 30, 2025 11:03
@p5 p5 marked this pull request as ready for review August 30, 2025 11:04
@p5 p5 changed the title [WIP] feat: enable basic systemd-boot support feat: enable basic systemd-boot support Aug 30, 2025
@p5 p5 force-pushed the sdboot-support branch 3 times, most recently from ab12d29 to f3da9f1 Compare August 30, 2025 11:42
let esp_path_str = esp_path_buf
.to_str()
.context("ESP path is not valid UTF-8")?;
let status = std::process::Command::new("bootctl")
Copy link
Member

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.

Copy link
Author

@p5 p5 Sep 1, 2025

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.

Copy link
Member

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.

Copy link
Member

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.

@travier
Copy link
Member

travier commented Sep 2, 2025

Note that we should not rely on systemd's systemd-boot-update.service either for updates as it does not update shim.

@p5
Copy link
Author

p5 commented Sep 2, 2025

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 generate-update-metadata searching for systemd-boot files, update copying files from the update directory to /boot and whatnot.

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.

Copy link
Member

@cgwalters cgwalters left a 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")
Copy link
Member

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) => {
Copy link
Member

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() {
Copy link
Member

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")?;
Copy link
Member

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.");
Copy link
Member

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(),
Copy link
Member

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()
Copy link
Member

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()

@cgwalters
Copy link
Member

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.

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!

@p5
Copy link
Author

p5 commented Sep 4, 2025

Do you want someone else on the team to pick this up?

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()
Copy link

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.

Copy link
Author

@p5 p5 Sep 5, 2025

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!

Copy link

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]>
@openshift-merge-robot
Copy link
Collaborator

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.

@travier
Copy link
Member

travier commented Sep 9, 2025

Making it a separated comment:

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?

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 🙂.

@travier
Copy link
Member

travier commented Sep 9, 2025

So shim support is also important for other distribution to get Secure Boot working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants