[PATCH] kexec: fix kexec_file_load fallback error handling
Mukesh Pilaniya <[email protected]>
| Newsgroups | org.infradead.lists.kexec |
|---|---|
| Message-ID | <[email protected]> |
With the default -a (--kexec-syscall-auto) option, kexec-tools first tries kexec_file_load() and falls back to kexec_load() when the syscall is not implemented (ENOSYS) or the kernel does not have a loader for the image format (ENOEXEC/ENOTSUP). With -s (--kexec-file-syscall), kexec-tools uses only kexec_file_load() and does not fall back. Falling back on EINVAL hides the real error, because EINVAL means something went wrong during loading. Remove EINVAL from the fallback path. Print the actual errno for ENOEXEC/ENOTSUP before falling back and track it so the final message distinguishes a missing syscall from other failures. Several kexec_file_load() image probe functions incorrectly return -EINVAL rather than -ENOEXEC when encountering an unrecognized image format. This kernel patch fixes the issue: https://lore.kernel.org/all/[email protected]/ Signed-off-by: Mukesh Pilaniya <[email protected]> Reviewed-by: Tao Liu <[email protected]> Reviewed-by: Philipp Rudo <[email protected]> --- kernel patch: https://lore.kernel.org/all/[email protected]/ --- kexec/kexec.c | 63 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/kexec/kexec.c b/kexec/kexec.c index 4a49ad4..0726996 100644 --- a/kexec/kexec.c +++ b/kexec/kexec.c @@ -68,6 +68,8 @@ int do_hotplug = 0; static unsigned long kexec_flags = 0; /* Flags for kexec file (fd) based syscall */ static unsigned long kexec_file_flags = 0; +/* errno from kexec_file_load when it returned EFALLBACK */ +static int kexec_file_load_errno; /* initrd detected in probe phase */ int implicit_initrd_fd = -1; int kexec_debug = 0; @@ -869,12 +871,16 @@ static int my_load(const char *type, int fileind, int argc, char **argv, info.nr_segments, info.segment, info.kexec_flags); if (result != 0) { - /* The load failed, print some debugging information */ - fprintf(stderr, "kexec_load failed: %s\n", - strerror(errno)); - fprintf(stderr, "entry = %p flags = 0x%lx\n", - info.entry, info.kexec_flags); - print_segments(stderr, &info); + if (errno == ENOSYS) { + fprintf(stderr, + "syscall kexec_load is not available on this system.\n"); + } else { + fprintf(stderr, "kexec_load failed: %s\n", + strerror(errno)); + fprintf(stderr, "entry = %p flags = 0x%lx\n", + info.entry, info.kexec_flags); + print_segments(stderr, &info); + } } return result; } @@ -883,12 +889,15 @@ static int kexec_file_unload(unsigned long kexec_file_flags) { int ret = 0; - if (!is_kexec_file_load_implemented()) + if (!is_kexec_file_load_implemented()) { + kexec_file_load_errno = ENOSYS; return EFALLBACK; + } ret = kexec_file_load(-1, -1, 0, NULL, kexec_file_flags); if (ret != 0) { if (errno == ENOSYS) { + kexec_file_load_errno = ENOSYS; ret = EFALLBACK; } else { /* @@ -919,9 +928,12 @@ static int k_unload (unsigned long kexec_flags) else result = kexec_load(NULL, 0, NULL, kexec_flags); if (result != 0) { - /* The unload failed, print some debugging information */ - fprintf(stderr, "kexec unload failed: %s\n", - strerror(errno)); + if (errno == ENOSYS) + fprintf(stderr, + "syscall kexec_load is not available on this system.\n"); + else + fprintf(stderr, "kexec unload failed: %s\n", + strerror(errno)); } return result; } @@ -1336,8 +1348,10 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, info.kernel_fd = -1; info.initrd_fd = -1; - if (!is_kexec_file_load_implemented()) + if (!is_kexec_file_load_implemented()) { + kexec_file_load_errno = ENOSYS; return EFALLBACK; + } if (argc - fileind <= 0) { fprintf(stderr, "No kernel specified\n"); @@ -1441,13 +1455,14 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, /* Not implemented. */ case ENOSYS: + kexec_file_load_errno = ENOSYS; + ret = EFALLBACK; + break; + /* - * Parsing image or other options failed - * The image may be invalid or image - * type may not supported by kernel so - * retry parsing in kexec-tools. + * The kernel does not have a loader for this + * image format, retry parsing in kexec-tools. */ - case EINVAL: case ENOEXEC: /* * ENOTSUP can be unsupported image @@ -1455,6 +1470,9 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, * wrapper type, duh. */ case ENOTSUP: + kexec_file_load_errno = errno; + fprintf(stderr, "kexec_file_load failed: %s\n", + strerror(errno)); ret = EFALLBACK; break; } @@ -1823,8 +1841,17 @@ int main(int argc, char *argv[]) if ((result == 0) && do_load_jump_back_helper) { result = my_load_jump_back_helper(kexec_flags, entry); } - if (result == EFALLBACK) - fputs("syscall kexec_file_load not available.\n", stderr); + /* + * When fallback to kexec_load was attempted, my_load() + * already reported the kexec_load error and overwrote + * result with its own return value, so this condition + * is only true when no fallback was attempted and + * kexec_file_load does not exist. + */ + if (result == EFALLBACK && kexec_file_load_errno == ENOSYS) { + fputs("syscall kexec_file_load is not available on this system.\n", + stderr); + } fflush(stdout); fflush(stderr); -- 2.50.1 (Apple Git-155)