Unification of boot loader updates, phase 1
Summary
Begin the process of using single tool (likely bootupd) for most boot loader updates, especially grub and shim. This decouples package installation, e.g., via rpm transaction, from actual update in /boot, /boot/efi. This change does not affect zipl and systemd-boot.
Owner
- Name/Emails:
- Timothée Ravier siosm@fedoraproject.org (Atomic Desktops, CoreOS, bootc)
- Colin Walters walters@verbum.org (bootupd, bootc)
- Bootloader team member / maintainer needed here 🙂
Current status
- Targeted release: Fedora Linux 42
- Last updated: 2024-12-19
- [Announced]
- [<will be assigned by the Wrangler> Discussion thread]
- FESCo issue: <will be assigned by the Wrangler>
- Tracker bug: <will be assigned by the Wrangler>
- Release notes tracker: <will be assigned by the Wrangler>
Detailed Description
Our goal is to make boot loader updates in all environments: rpm mode, image mode, etc., safer and more reliable, and to add a fallback option so that a system is always bootable. We want to use a single interface, bootupd, to perform the actual boot loader update on a system once all new packages have been installed on that system.
On rpm-based systems, most components are updated monolithically along with boot loader packages, which automatically install into the /boot and/or /boot/efi directories, overwriting binaries that were there. Notably, kernel installation is performed via systemd script kernel-install, which runs at the end of the rpm transaction. Each distribution has a single directory structure constituting its bootpath, and if anything goes wrong during the subsequent boot, repair can be difficult or even impossible.
On image-based systems, the boot loader update is decoupled from the system update, but, bootupd, once triggered, will also overwrite entries in /boot & /boot/efi, and any problem with the boot loaders has the potential to create an unbootable and unrecoverable system.
Rather than using different, yet equally precarious, methods for updating these critical components, we want to adapt bootupd to work on all systems in order to make boot loader updates easier and safer. It would additionally be aware of dependencies between packages, such as boot loaders and kernels. bootupd would be the interface that is used on all systems to perform the actual update once all new packages are available, and it would in the future retain a fallback option in case any problem arises during the subsequent boot process.
This change will be split into two phases:
Phase 1 (this change, proposed for Fedora 42)
- Install the following packages into /usr/lib/<pkg>/<arch> rather than /boot & /boot/efi
- grub2
- shim
- Separate rpm actions that happen at build time vs. runtime:
- Add a mechanism that installs the bootloader for package mode installations as part of a RPM post trans. It is not yet defined how that will happen. Options that were suggested:
- Add a dumb Bash script that copies the bootloader to the ESP
- Add a new action verb to kernel-install, which will run script(s) for given component
- Adapt bootupd to cover this case
- Add a mechanism that installs the bootloader for package mode installations as part of a RPM post trans. It is not yet defined how that will happen. Options that were suggested:
- Teach new boot loader location (/usr) to bootupd (needed for rpm-ostree & Bootable Containers variants)
- Extend systemd package-notes to support PE files
Phase 2 (will be proposed for Fedora 43)
- Add A/B support, BootNext to bootupd https://github.com/coreos/bootupd/issues/440
- Unify on bootupd to perform all boot loader updates at both system install (e.g. Anaconda) time and for updates
- Install bootupd on dnf and image based systems by default
- Consider switching to a static GRUB configuration file (to be detailed)
In phase 1 of this change, we will focus on moving the content included in the grub and shim packages from /boot and /boot/efi to /usr and adding the logic needed to install them to /boot as part of a posttrans script.
Moving the content from /boot and /boot/efi to /usr (in the RPM packages) is a pre-requisite for all the potential future improvements as it decouples the bootloader installation phase via the RPM (that happens offline for all image mode systems and image builds in general) from the actual update in the ESP and any runtime EFI variable updates.
As we move the bootloader and shim to /usr, we now need a mechanism to sync the content from /usr to /boot and the ESP (and the MBR for BIOS systems, but we already have to do that). In all cases, the current suggestion is to do this synchronization step as part of a posttrans trigger at the end of the RPM transaction.
The first suggested option is to add a “dumb” Bash script that copies the new bootloader to the ESP partition.
The second suggested option is to add scripts to the kernel/install.d directory. Currently, when a new kernel gets installed, kernel-install (systemd) runs and invokes a number of bash and python scripts in /usr/lib/kernel/install.d/ which make the initramfs, create BLS entries, etc. We could extend kernel-install to add a new action that will be triggered when the relevant components (shim, grub2, sd-boot) are updated.
The third option is to adapt bootupd to install the updated bootloader to cover this case and run as part of the posttrans trigger.
In phase 2, we will look at unifying in a single tool how we do bootloader and shim updates, likely using bootupd, and extend the safe of boot loader updates, mainly on EFI based systems.
We will teach bootupd how to create a full new boot chain, e.g., shim -> grub2 -> kernel, based on newly installed components while retaining the working boot chain as a fallback option. Upon reboot, the new boot chain will be attempted, and if successful, set as the new default/fallback.
We will also need to choose how to trigger the script(s) so that in the end all new content is in a single directory in /boot, and a new efi entry is created for that directory and set to BootNext.
It has not yet been decided what trigger will be used to initiate the update. There is an idea to create a new systemd target, but obviously this has to happen before the system is rebooted.
One possibility is to use the reboot/poweroff target as the trigger: in case the system is powered off accidentally, no update would occur. If the user chooses to reboot, the new boot chain will be created just before shutdown so that it can be set as BootNext.
It has been proposed to use systemd package-notes for version numbers to track dependencies between kernels and boot loaders. This would remove bootupd’s dependency on rpm to scrape package numbers.
Architecture comments:
Phase 1 is architecture agnostic.
Our current targets for phase 2 are UEFI based systems: x86_64 and aarch64. Additionally, we believe ppc64le will want this support and will thus make itself more compliant in the meantime. s390 systems are out of scope at this time.
Feedback
Q: What about UKIs?
A: This should not impact setups with UKIs. We will not touch the bootloader configuration itself or how GRUB works as part of this change.
Benefit to Fedora
Once phase 1 and 2 are complete:
- Boot loader updates are safer and more reliable.
- The same mechanism is used for boot loader updates across Fedora products.
- Fallback to known working boot loader is always available.
Scope
- Proposal owners:
- Packaging changes to move the content from /boot to /usr/lib/… for the shim and grub2 packages.
- Update the scripts needed to copy those files to /boot as part of a post-trans scriptlet
- Teach bootupd about these new paths
- Other developers:
- Other packages that install files in /boot and /boot/efi and other bootloader packages should adapt for this change as well. It should still continue to work if they don’t, but they won’t benefit from the changes.
- Release engineering: #Releng issue number
- Policies and guidelines: N/A (not needed for this Change)
- Trademark approval: N/A (not needed for this Change)
- Alignment with the Fedora Strategy: Nothing specific
Upgrade/compatibility impact
Changes will be self-consistent, so upgrading from the previous release should not be affected.
Early Testing (Optional)
Do you require 'QA Blueprint' support? Unclear yet
We will reach out to QA as soon as we have a proof of concept ready for testing.
How To Test
We will make a COPR available with updated packages. Updating an existing system with the packages from this COPR should work and result in a working system without any specific action.
User Experience
If this is done properly, this should be transparent for users.
fwupd does this already, as does systemd-boot (installs itself into /usr/lib/systemd/boot/efi). Other distributions, like Arch and Debian, install boot loaders into /usr/lib/grub/<platform> rather than into /boot directly.
Dependencies
systemd:
- Extend package-notes to support PE files
- Add a new action to kernel-install script if this is the option that is decided
bootupd:
- Update to handle the new filesystem paths for the bootloader and shim components
- Add support to run as posttrans is this is the option that is decided
Contingency Plan
If each component is updated consistently, then dependency on other components is minimal. Components that are dependent, will wait until dependencies have been fulfilled before making changes.
Example: i) shim changes its installation location to /usr/lib/shim/x86_64/ and then runs a simple cp to move its components to /boot in posttrans; ii) shim script is added to /usr/lib/kernel/install.d/ and shim posttrans triggers the script, etc.
- Contingency deadline: Beta release
- Blocks release? Yes if not completed and not reverted
Documentation
Documentation will have to be written.
Release Notes
Fedora shim and grub2 packages are now installing content in /usr/lib/… and not in /boot and /boot/efi directly.