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 <noreply@anthropic.com>
This commit is contained in:
committed by
Luca Boccassi
parent
7f5503f15d
commit
a52e0f87f5
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user