From: Daan De Meyer Date: Tue, 21 Jan 2025 11:58:28 +0000 (+0100) Subject: Add support for pre-signed Bootloader variants without shim X-Git-Tag: v25~15^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F3397%2Fhead;p=thirdparty%2Fmkosi.git Add support for pre-signed Bootloader variants without shim 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. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 55c8ccb9b..dad8609d8 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -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 diff --git a/mkosi/bootloader.py b/mkosi/bootloader.py index 0829212ea..68f56aaba 100644 --- a/mkosi/bootloader.py +++ b/mkosi/bootloader.py @@ -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( diff --git a/mkosi/config.py b/mkosi/config.py index 775d9b565..baa75c6dd 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -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): diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index 9cf098a29..7a1f97898 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -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 diff --git a/tests/test_boot.py b/tests/test_boot.py index 3de163b6c..142933aa2 100644 --- a/tests/test_boot.py +++ b/tests/test_boot.py @@ -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