Skip to content

Commit

Permalink
arch: add script to generate UKIs (#252)
Browse files Browse the repository at this point in the history
Currently, booster does not support generating Universal Kernel Images (UKIs) natively and this PR allows creating UKIs via ukify on Arch Linux.

To generate UKIs, we can simply delegate the functionality to external tools such as ukify. The resulting binaries are currently stored in /boot/Linux/EFI and manual intervention would be required from the user to configure the appropriate boot loader configuration files to load the binary by default. Otherwise, binaries would probably need to be selected at boot time. For instance, in systemd-boot, loader.conf should be modified.

Closes #110 and potentially #79 if there are no plans for a native UKI implementation.
  • Loading branch information
c3Ls1US committed Jan 27, 2024
1 parent 05a3f46 commit 67eaed9
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/manpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,16 @@ At the final step booster computes dependency graphs between modules and all req
For example if a user manually added `ext4` and kernel build system says `ext` module requires `mbcache` and `jbd2` then both
`mbcache` and `jbd2` automatically added to the image.

## Universal Kernel Image
A [Universal Kernel Image](https://uapi-group.org/specifications/specs/unified_kernel_image/) (UKI) is a PE binary the bundles various boot components (e.g. kernel, initrd, and an UEFI boot stub) as a single executable.
This allows for booting directly through the firmware (UEFI) as well as authenticating all of the boot components at once for Secure Boot.

To generate UKIs in Booster, please install the systemd UKI generator (systemd-ukify) from your distribution's package manager and use `/usr/lib/booster/regenerate_uki`.
It is a convenience script that performs the same type of image regeneration as if you installed `booster` with your package manager, then passes the result to systemd's UKI generator (ukify) as input.
The script only passes a subset of boot components, namely the system's microcode(s), initrd, os-release file, boot splash image and kernel. Kernel command-line entries of the UKI are inherited from `/etc/booster.yaml`.

Please note that to boot the UKI by default, it may be necessary to configure your system's boot loader configuration file(s) accordingly.

## DEBUGGING
If you have a problem with booster boot tool you can enable debug mode to get more
information about what is going on. Just add `booster.log=debug,console` kernel parameter and booster
Expand Down Expand Up @@ -240,6 +250,10 @@ So /boot/loader/entries/booster.conf should looks like this:
initrd /booster-linux.img
options root=UUID=69bc4dd2-7f6c-4821-aa6b-d80d9c97d470 rw rootflags=relatime,autodefrag,compress=zstd:2,space_cache,subvol=root

Create a Unified Kernel Image and write the result to /boot/EFI/Linux:

$ /usr/lib/booster/regenerate_uki build /boot/EFI/Linux

## COPYRIGHT
Booster is Copyright (C) 2020 Anatol Pomazau <http://github.com/anatol>

Expand Down
1 change: 1 addition & 0 deletions packaging/arch/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ optdepends=(
'busybox: to enable emergency shell at the boot time'
'yubikey-personalization: for clevis Yubikey challenge-response support'
'libfido2: for systemd-enroll with FIDO2'
'systemd-ukify: for generating UKIs'
)
backup=(etc/booster.yaml)
provides=(booster initramfs)
Expand Down
76 changes: 76 additions & 0 deletions packaging/arch/regenerate_uki
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/bin/bash -e

# create a basic universal kernel image (UKI) via ukify
# by default, the output is written to the current working directory unless specified by the user
create_uki() {
local microcodes
local kernel="$1"
local pkgbase="$2"
local esp="$3"
local initrd="/boot/booster-${pkgbase}.img"
local osrel="/etc/os-release"
local splash="/usr/share/systemd/bootctl/splash-arch.bmp"

# find all microcodes and delete the trailing white space
microcodes=$(find /boot -name '*-ucode.img' -type f -printf "/boot/%f " | tr -d ' ')

booster build --force --kernel-version "${kernel##/usr/lib/modules/}" "$initrd"
ukify --initrd="$microcodes" --initrd="$initrd" --linux="${kernel}/vmlinuz" --os-release="@${osrel}" --splash="$splash" --output="${esp}/booster-${pkgbase}.efi" build
install -Dm644 "${kernel}/vmlinuz" "/boot/vmlinuz-${pkgbase}"
}

usage() {
echo "Usage: regenerate_uki build [path]"
echo "See booster(1) for more info and examples."
}

main() {
local esp
local package
esp=$(pwd)

if ! [ "$1" == "build" ]; then
usage
exit 1
fi

if [ -n "$2" ]; then
esp="$2"
fi

if ! [ -d "$esp" ]; then
usage
echo "Path to ESP does not exist or is not a directory: ${esp}"
exit 1
fi

# check if the systemd-ukify package is installed via pacman
package=$(pacman -Qq "systemd-ukify")
if ! [ "$package" == "systemd-ukify" ]; then
echo "$package"
exit 1
fi

# check for root
if ! [ "$EUID" -eq 0 ]; then
echo "regenerate_uki must be run as root."
exit 1
fi

# find out all installed kernels
mapfile -d '' kernels < <(find /usr/lib/modules -maxdepth 1 -type d ! -name "modules" -print0)

for kernel in "${kernels[@]}"; do
if ! pacman -Qqo "${kernel}/pkgbase" > /dev/null 2>&1; then
# if pkgbase does not belong to any package then skip this kernel
continue
fi
read -r pkgbase < "${kernel}/pkgbase"

create_uki "$kernel" "$pkgbase" "$esp" &
done

wait
}

main "$@"

0 comments on commit 67eaed9

Please sign in to comment.