]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Add support for pre-signed Bootloader variants without shim 3397/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 21 Jan 2025 11:58:28 +0000 (12:58 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 21 Jan 2025 12:01:09 +0000 (13:01 +0100)
Currently we only pick up pre-signed bootloader binaries if
ShimBootloader=signed is configured. Let's also add support for
installing pre-signed bootloader binaries without using shim.

mkosi/__init__.py
mkosi/bootloader.py
mkosi/config.py
mkosi/resources/man/mkosi.1.md
tests/test_boot.py

index 55c8ccb9bb4144b441aecf0de10069fd93b26b07..dad8609d81e5a2b8669a0b205103974454d96d02 100644 (file)
@@ -50,7 +50,6 @@ from mkosi.config import (
     PACKAGE_GLOBS,
     Args,
     ArtifactOutput,
-    Bootloader,
     Cacheonly,
     CertificateSourceType,
     Compression,
@@ -1763,7 +1762,7 @@ def systemd_stub_version(context: Context, stub: Path) -> Optional[GenericVersio
 
 def want_uki(context: Context) -> bool:
     return want_efi(context.config) and (
-        context.config.bootloader == Bootloader.uki
+        context.config.bootloader.is_uki()
         or context.config.unified_kernel_images == ConfigFeature.enabled
         or (
             context.config.unified_kernel_images == ConfigFeature.auto
@@ -1870,6 +1869,7 @@ def install_type1(
             want_efi(context.config)
             and context.config.secure_boot
             and context.config.shim_bootloader != ShimBootloader.signed
+            and not context.config.bootloader.is_signed()
             and KernelType.identify(context.config, kimg) == KernelType.pe
         ):
             kimg = sign_efi_binary(context, kimg, dst / "vmlinuz")
@@ -1993,7 +1993,7 @@ def install_uki(
         boot_count=boot_count,
     )
 
-    if context.config.bootloader == Bootloader.uki:
+    if context.config.bootloader.is_uki():
         if context.config.shim_bootloader != ShimBootloader.none:
             boot_binary = context.root / shim_second_stage_binary(context)
         else:
@@ -2005,7 +2005,7 @@ def install_uki(
     with umask(~0o700):
         boot_binary.parent.mkdir(parents=True, exist_ok=True)
 
-    if context.config.shim_bootloader == ShimBootloader.signed:
+    if context.config.shim_bootloader == ShimBootloader.signed or context.config.bootloader.is_signed():
         for p in (context.root / "usr/lib/modules" / kver).glob("*.efi"):
             log_step(f"Installing prebuilt UKI at {p} to {boot_binary}")
             shutil.copy2(p, boot_binary)
@@ -2143,7 +2143,7 @@ def install_kernel(context: Context, partitions: Sequence[Partition]) -> None:
         if not want_uki(context) or want_grub_bios(context, partitions):
             install_type1(context, kver, kimg, token, partitions, cmdline)
 
-        if context.config.bootloader == Bootloader.uki:
+        if context.config.bootloader.is_uki():
             break
 
 
index 0829212ea2dab515cfd06549fd45f83e7a8d8bf5..68f56aabaea56ba11e3bdba8c379afd1616967cc 100644 (file)
@@ -69,13 +69,13 @@ def want_grub_efi(context: Context) -> bool:
     if not want_efi(context.config):
         return False
 
-    if context.config.bootloader != Bootloader.grub:
+    if not context.config.bootloader.is_grub():
         return False
 
     if not (arch := context.config.architecture.to_grub()):
         return False
 
-    if context.config.shim_bootloader != ShimBootloader.signed:
+    if context.config.shim_bootloader != ShimBootloader.signed and not context.config.bootloader.is_signed():
         have = find_grub_directory(context, target=f"{arch}-efi") is not None
         if not have and context.config.bootable == ConfigFeature.enabled:
             die("An EFI bootable image with grub was requested but grub for EFI is not installed")
@@ -323,7 +323,7 @@ def install_grub(context: Context) -> None:
         with umask(~0o700):
             output.parent.mkdir(parents=True, exist_ok=True)
 
-        if context.config.shim_bootloader == ShimBootloader.signed:
+        if context.config.shim_bootloader == ShimBootloader.signed or context.config.bootloader.is_signed():
             if not (signed := find_signed_grub_image(context)):
                 if context.config.bootable == ConfigFeature.enabled:
                     die("Couldn't find a signed grub EFI binary installed in the image")
@@ -632,7 +632,7 @@ def install_systemd_boot(context: Context) -> None:
     if not want_efi(context.config):
         return
 
-    if context.config.bootloader != Bootloader.systemd_boot:
+    if not context.config.bootloader.is_systemd_boot():
         return
 
     if not any(gen_kernel_images(context)) and context.config.bootable == ConfigFeature.auto:
@@ -644,7 +644,7 @@ def install_systemd_boot(context: Context) -> None:
         return
 
     directory = context.root / "usr/lib/systemd/boot/efi"
-    signed = context.config.shim_bootloader == ShimBootloader.signed
+    signed = context.config.shim_bootloader == ShimBootloader.signed or context.config.bootloader.is_signed()
     if not directory.glob("*.efi.signed" if signed else "*.efi"):
         if context.config.bootable == ConfigFeature.enabled:
             die(
index 775d9b565c337ff083a941a31fd0b48329bee7aa..baa75c6dd8108c65c8549f7fb2928e3b5d0a06cd 100644 (file)
@@ -279,6 +279,21 @@ class Bootloader(StrEnum):
     uki = enum.auto()
     systemd_boot = enum.auto()
     grub = enum.auto()
+    uki_signed = enum.auto()
+    systemd_boot_signed = enum.auto()
+    grub_signed = enum.auto()
+
+    def is_uki(self) -> bool:
+        return self in (Bootloader.uki, Bootloader.uki_signed)
+
+    def is_systemd_boot(self) -> bool:
+        return self in (Bootloader.systemd_boot, Bootloader.systemd_boot_signed)
+
+    def is_grub(self) -> bool:
+        return self in (Bootloader.grub, Bootloader.grub_signed)
+
+    def is_signed(self) -> bool:
+        return self in (Bootloader.uki_signed, Bootloader.systemd_boot_signed, Bootloader.grub_signed)
 
 
 class BiosBootloader(StrEnum):
index 9cf098a292b519f4c842622088b2938c84981285..7a1f9789871174db52b71a2fb58b5e45fd7213d0 100644 (file)
@@ -872,7 +872,8 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
     added to the image if the disk output format is used.
 
 `Bootloader=`, `--bootloader=`
-:   Takes one of `none`, `systemd-boot`, `uki` or `grub`. Defaults to
+:   Takes one of `none`, `systemd-boot`, `uki`, `grub`,
+    `systemd-boot-signed`, `uki-signed` or `grub-signed`. Defaults to
     `systemd-boot`. If set to `none`, no EFI bootloader will be installed
     into the image. If set to `systemd-boot`, **systemd-boot** will be
     installed and for each installed kernel, a UKI will be generated and
@@ -887,6 +888,9 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
     in the ESP for compatibility with signed versions of grub which load
     the grub configuration from this location.
 
+    The `signed` variants will only install pre-signed EFI binaries
+    shipped by the distribution.
+
     Kernels need to be placed into the root filesystem (for example using
     `ExtraTrees=`) under `/usr/lib/modules/$version`, named `vmlinux` or
     `vmlinuz`. The `$version` is as produced by Kbuild's `kernelversion` make
index 3de163b6c600ff724707a2dca23dc76543468cd0..142933aa27954c44a28fb58f8ba3830aa568edd3 100644 (file)
@@ -67,7 +67,7 @@ def test_format(config: ImageConfig, format: OutputFormat) -> None:
 
 @pytest.mark.parametrize("bootloader", Bootloader)
 def test_bootloader(config: ImageConfig, bootloader: Bootloader) -> None:
-    if config.distribution == Distribution.rhel_ubi:
+    if config.distribution == Distribution.rhel_ubi or bootloader.is_signed():
         return
 
     firmware = Firmware.linux if bootloader == Bootloader.none else Firmware.auto