From a52e0f87f59b1ee2752ec22160d999838e9d0508 Mon Sep 17 00:00:00 2001 From: Rocker Zhang Date: Thu, 21 May 2026 23:47:48 +0800 Subject: [PATCH] systemctl: also attempt kexec image extraction on EINVAL load_kexec_kernel() retries kexec_file_load() with an extracted kernel (decompressed Image / ZBOOT PE / UKI) when the kernel rejects the image, but it only does so when kexec_file_load() failed with ENOEXEC. On arm64 that retry never happens: arm64's image_probe() (arch/arm64/kernel/kexec_image.c) returns -EINVAL on an ARM64_IMAGE_MAGIC mismatch, whereas x86's bzImage64_probe() and the generic kexec_image_probe_default() return -ENOEXEC. So `systemctl kexec` of a UKI on arm64 skips the extraction path and falls back to the /usr/sbin/kexec binary, which is no longer a dependency since e107c7ead0 ("systemctl: replace kexec-tools dependency with direct kexec_file_load() syscall") -- leaving kexec broken. Accept EINVAL in addition to ENOEXEC. This is safe: the extraction in kexec_maybe_decompress_kernel() re-gates on the actual file magic (MZ / compression headers) and is a no-op returning 0 for anything else, so an EINVAL that is not a format mismatch just falls through to the existing fallback as before. Fixing this in systemd (rather than only in the kernel) is appropriate: systemd must keep working with already-shipped arm64 kernels whose kexec_file_load() returns EINVAL for an unrecognized image magic. Relates to: https://github.com/systemd/systemd/issues/28538 Co-developed-by: Claude Opus 4.7 --- src/systemctl/systemctl-start-special.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c index fd38c678ea..a8702ad438 100644 --- a/src/systemctl/systemctl-start-special.c +++ b/src/systemctl/systemctl-start-special.c @@ -113,9 +113,14 @@ static int load_kexec_kernel(void) { int saved_errno = errno; - if (saved_errno == ENOEXEC) { + if (IN_SET(saved_errno, ENOEXEC, EINVAL)) { /* The kernel didn't recognize the image format. Try decompressing or extracting the - * kernel (e.g. compressed Image, ZBOOT PE, or UKI) and loading again. */ + * kernel (e.g. compressed Image, ZBOOT PE, or UKI) and loading again. + * + * Most architectures' kexec_file_load() returns ENOEXEC when no image loader matches + * (the default behavior of kexec_image_probe_default()), but arm64's image_probe() + * returns EINVAL for an unrecognized magic. Accept both, otherwise `systemctl kexec` + * of a UKI never reaches the extraction path on arm64. */ log_debug_errno(saved_errno, "Kernel rejected image, trying decompression/extraction: %m"); _cleanup_close_ int extracted_kernel_fd = -EBADF, extracted_initrd_fd = -EBADF;