]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Look for .sdmagic before we consider a PE binary a UKI/addon
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 15 Oct 2025 19:39:02 +0000 (21:39 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 16 Oct 2025 12:54:04 +0000 (14:54 +0200)
In ubuntu devel they started using the stubble bootloader for their
kernel images which includes a .linux and a .osrel section which means
it identifies as a UKI so we skip it. Let's additionally look for
.sdmagic as a workaround to fix this for now.

To implement this we can't make use of bootctl kernel-identify anymore
so we reimplement the logic ourselves with pefile. While we're at it,
we move KernelType to bootloader.py as it makes more sense to live there
than in qemu.py.

mkosi/__init__.py
mkosi/bootloader.py
mkosi/qemu.py

index be4338ee7f66a64bed54a47fca66e2c6a217300c..bbe56b1ae314b0ac475f9d9437033805b98d7950 100644 (file)
@@ -29,6 +29,7 @@ from typing import Any, Optional, Union, cast
 
 from mkosi.archive import can_extract_tar, extract_tar, make_cpio, make_tar
 from mkosi.bootloader import (
+    KernelType,
     efi_boot_binary,
     extract_pe_section,
     gen_kernel_images,
@@ -106,7 +107,6 @@ from mkosi.mounts import (
 from mkosi.pager import page
 from mkosi.partition import Partition, finalize_root, finalize_roothash
 from mkosi.qemu import (
-    KernelType,
     copy_ephemeral,
     finalize_credentials,
     finalize_kernel_command_line_extra,
index c7af8a8bdda0db11178ccb1d0eb7cda4e4cc0db7..4ebf1d8f5c2679cd61b64b004adb7077437f149f 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
+import enum
 import itertools
 import logging
 import os
@@ -30,13 +31,52 @@ from mkosi.context import Context
 from mkosi.distributions import Distribution
 from mkosi.log import complete_step, die, log_step
 from mkosi.partition import Partition
-from mkosi.qemu import KernelType
 from mkosi.run import CompletedProcess, run, workdir
 from mkosi.sandbox import umask
-from mkosi.util import _FILE, PathString, flatten
+from mkosi.util import _FILE, PathString, StrEnum, flatten
 from mkosi.versioncomp import GenericVersion
 
 
+class KernelType(StrEnum):
+    pe = enum.auto()
+    uki = enum.auto()
+    addon = enum.auto()
+    unknown = enum.auto()
+
+    @classmethod
+    def identify(cls, config: Config, path: Path) -> "KernelType":
+        pefile = textwrap.dedent(
+            f"""\
+            import pefile
+
+            try:
+                pe = pefile.PE("{workdir(path)}", fast_load=True)
+                sections = {{s.Name.decode().strip("\\0") for s in pe.sections}}
+
+                if all(s in sections for s in (".linux", ".sdmagic", ".osrel")):
+                    print("{KernelType.uki}")
+                elif (
+                    all(s in sections for s in (".linux", ".sdmagic")) and
+                    any(s in sections for s in (".cmdline", ".dtb", ".initrd", ".ucode"))
+                ):
+                    print("{KernelType.addon}")
+                else:
+                    print("{KernelType.pe}")
+            except pefile.PEFormatError:
+                print("{KernelType.unknown}")
+            """
+        )
+
+        result = run(
+            [python_binary(config)],
+            input=pefile,
+            stdout=subprocess.PIPE,
+            sandbox=config.sandbox(options=["--ro-bind", path, workdir(path)]),
+        )
+
+        return KernelType(result.stdout.strip())
+
+
 def want_efi(config: Config) -> bool:
     # Do we want to make the image bootable on EFI firmware?
     # Note that this returns True also in the case where autodetection might later cause the system to not be
index c3d3a7b2d32e756a653fb1708305b147f52ab9cb..d3ea1924d87c0e1eb0d718086528935b29f1b7c0 100644 (file)
@@ -28,6 +28,7 @@ from collections.abc import Iterator, Sequence
 from pathlib import Path
 from typing import Optional
 
+from mkosi.bootloader import KernelType
 from mkosi.config import (
     Args,
     Config,
@@ -157,34 +158,6 @@ def find_unused_vsock_cid(config: Config, vfd: int) -> int:
     die("Failed to find an unused VSock connection ID")
 
 
-class KernelType(StrEnum):
-    pe = enum.auto()
-    uki = enum.auto()
-    unknown = enum.auto()
-
-    @classmethod
-    def identify(cls, config: Config, path: Path) -> "KernelType":
-        if not config.find_binary("bootctl"):
-            logging.warning("bootctl is not installed, assuming 'unknown' kernel type")
-            return KernelType.unknown
-
-        if (v := systemd_tool_version("bootctl", sandbox=config.sandbox)) < 253:
-            logging.warning(f"bootctl {v} doesn't know kernel-identify verb, assuming 'unknown' kernel type")
-            return KernelType.unknown
-
-        type = run(
-            ["bootctl", "kernel-identify", workdir(path)],
-            stdout=subprocess.PIPE,
-            sandbox=config.sandbox(options=["--ro-bind", path, workdir(path)]),
-        ).stdout.strip()
-
-        try:
-            return cls(type)
-        except ValueError:
-            logging.warning(f"Unknown kernel type '{type}', assuming 'unknown'")
-            return KernelType.unknown
-
-
 def find_qemu_binary(config: Config) -> Path:
     options = [f"qemu-system-{config.architecture.to_qemu()}"]