diff --git a/kexec-tools-fix-kexec_file_load-error-handling.patch b/kexec-tools-fix-kexec_file_load-error-handling.patch new file mode 100644 index 0000000..e626fc4 --- /dev/null +++ b/kexec-tools-fix-kexec_file_load-error-handling.patch @@ -0,0 +1,230 @@ +From 0ec1fd23847ba103f967e3377e2a1b13712cff6e Mon Sep 17 00:00:00 2001 +From: Petr Tesarik +Date: Thu, 12 Mar 2020 20:12:12 +0100 +Upstream: not yet, patch sent 2020-03-12 +Subject: Fix kexec_file_load(2) error handling +References: bsc#1166105 + +The handling of kexec_file_load() error conditions needs some +improvement. + +First, on failure, the system call itself returns -1 and sets +errno. It is wrong to check the return value itself. + +Second, do_kexec_file_load() mixes different types of error +codes (-1, return value of a load method, negative kernel error +number). Let it always return one of the reason codes defined in +kexec/kexec.h. + +Third, the caller of do_kexec_file_load() cannot know what exactly +failed inside that function, so it should not check errno directly. +All it needs to know is whether it makes sense to fall back to the +other syscall. Add an error code for that purpose (EFALLBACK), and +let do_kexec_file_load() decide. + +Fourth, do_kexec_file_load() should not print any error message if +it returns EFALLBACK, because the fallback syscall may succeed +later, and the user is confused whether the command failed, or not. +Move the error message towards the end of main(). + +Signed-off-by: Petr Tesarik +--- + kexec/kexec.c | 114 ++++++++++++++++++++++++++++++---------------------------- + kexec/kexec.h | 1 + + 2 files changed, 61 insertions(+), 54 deletions(-) + +diff --git a/kexec/kexec.c b/kexec/kexec.c +index bc6ab3d..33c1b4b 100644 +--- a/kexec/kexec.c ++++ b/kexec/kexec.c +@@ -836,11 +836,21 @@ static int kexec_file_unload(unsigned long kexec_file_flags) + { + int ret = 0; + ++ if (!is_kexec_file_load_implemented()) ++ return EFALLBACK; ++ + ret = kexec_file_load(-1, -1, 0, NULL, kexec_file_flags); + if (ret != 0) { +- /* The unload failed, print some debugging information */ +- fprintf(stderr, "kexec_file_load(unload) failed\n: %s\n", +- strerror(errno)); ++ if (errno == ENOSYS) { ++ ret = EFALLBACK; ++ } else { ++ /* ++ * The unload failed, print some debugging ++ * information */ ++ fprintf(stderr, "kexec_file_load(unload) failed: %s\n", ++ strerror(errno)); ++ ret = EFAILED; ++ } + } + return ret; + } +@@ -1182,15 +1192,13 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, + info.file_mode = 1; + info.initrd_fd = -1; + +- if (!is_kexec_file_load_implemented()) { +- fprintf(stderr, "syscall kexec_file_load not available.\n"); +- return -ENOSYS; +- } ++ if (!is_kexec_file_load_implemented()) ++ return EFALLBACK; + + if (argc - fileind <= 0) { + fprintf(stderr, "No kernel specified\n"); + usage(); +- return -1; ++ return EFAILED; + } + + kernel = argv[fileind]; +@@ -1199,7 +1207,7 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, + if (kernel_fd == -1) { + fprintf(stderr, "Failed to open file %s:%s\n", kernel, + strerror(errno)); +- return -1; ++ return EFAILED; + } + + /* slurp in the input kernel */ +@@ -1225,7 +1233,7 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, + if (i == file_types) { + fprintf(stderr, "Cannot determine the file type " "of %s\n", + kernel); +- return -1; ++ return EFAILED; + } + + ret = file_type[i].load(argc, argv, kernel_buf, kernel_size, &info); +@@ -1243,9 +1251,43 @@ static int do_kexec_file_load(int fileind, int argc, char **argv, + + ret = kexec_file_load(kernel_fd, info.initrd_fd, info.command_line_len, + info.command_line, info.kexec_flags); +- if (ret != 0) +- fprintf(stderr, "kexec_file_load failed: %s\n", +- strerror(errno)); ++ if (ret != 0) { ++ switch (errno) { ++ /* ++ * Something failed with signature verification. ++ * Reject the image. ++ */ ++ case ELIBBAD: ++ case EKEYREJECTED: ++ case ENOPKG: ++ case ENOKEY: ++ case EBADMSG: ++ case EMSGSIZE: ++ /* Reject by default. */ ++ default: ++ ret = EFAILED; ++ break; ++ ++ /* Not implemented. */ ++ case ENOSYS: ++ /* ++ * 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. ++ */ ++ case EINVAL: ++ case ENOEXEC: ++ /* ++ * ENOTSUP can be unsupported image ++ * type or unsupported PE signature ++ * wrapper type, duh. ++ */ ++ case ENOTSUP: ++ ret = EFALLBACK; ++ break; ++ } ++ } + + close(kernel_fd); + return ret; +@@ -1496,7 +1538,7 @@ int main(int argc, char *argv[]) + if (do_unload) { + if (do_kexec_file_syscall) { + result = kexec_file_unload(kexec_file_flags); +- if ((result == -ENOSYS) && do_kexec_fallback) ++ if (result == EFALLBACK && do_kexec_fallback) + do_kexec_file_syscall = 0; + } + if (!do_kexec_file_syscall) +@@ -1506,46 +1548,8 @@ int main(int argc, char *argv[]) + if (do_kexec_file_syscall) { + result = do_kexec_file_load(fileind, argc, argv, + kexec_file_flags); +- if (do_kexec_fallback) switch (result) { +- /* +- * Something failed with signature verification. +- * Reject the image. +- */ +- case -ELIBBAD: +- case -EKEYREJECTED: +- case -ENOPKG: +- case -ENOKEY: +- case -EBADMSG: +- case -EMSGSIZE: +- /* +- * By default reject or do nothing if +- * succeded +- */ +- default: break; +- case -ENOSYS: /* not implemented */ +- /* +- * 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. +- */ +- case -EINVAL: +- case -ENOEXEC: +- /* +- * ENOTSUP can be unsupported image +- * type or unsupported PE signature +- * wrapper type, duh +- * +- * The kernel sometimes wrongly +- * returns ENOTSUPP (524) - ignore +- * that. It is not supposed to be seen +- * by userspace so seeing it is a +- * kernel bug +- */ +- case -ENOTSUP: +- do_kexec_file_syscall = 0; +- break; +- } ++ if (result == EFALLBACK && do_kexec_fallback) ++ do_kexec_file_syscall = 0; + } + if (!do_kexec_file_syscall) + result = my_load(type, fileind, argc, argv, +@@ -1570,6 +1574,8 @@ 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); + + fflush(stdout); + fflush(stderr); +diff --git a/kexec/kexec.h b/kexec/kexec.h +index a97b9ce..28fd129 100644 +--- a/kexec/kexec.h ++++ b/kexec/kexec.h +@@ -63,6 +63,7 @@ + */ + #define EFAILED -1 /* default error code */ + #define ENOCRASHKERNEL -2 /* no memory reserved for crashkernel */ ++#define EFALLBACK -3 /* fallback to kexec_load(2) may work */ + + /* + * This function doesn't actually exist. The idea is that when someone +-- +2.16.4 + diff --git a/kexec-tools-reset-getopt-before-falling-back-to-legacy.patch b/kexec-tools-reset-getopt-before-falling-back-to-legacy.patch new file mode 100644 index 0000000..9bcc96a --- /dev/null +++ b/kexec-tools-reset-getopt-before-falling-back-to-legacy.patch @@ -0,0 +1,54 @@ +From dadafc4664c7b78ea1561ccca33986c9639106ec Mon Sep 17 00:00:00 2001 +From: Petr Tesarik +Date: Fri, 13 Mar 2020 14:54:00 +0100 +Upstream: not yet, patch sent 2020-03-13 +Subject: Reset getopt before falling back to legacy syscall +References: bsc#1166105 + +The modules may need to parse the arguments again after +kexec_file_load(2) failed, but getopt is not reset. + +This change fixes the --initrd option on s390x. Without this patch, +it will fail to load the initrd on kernels that do not implement +kexec_file_load(2). + +Signed-off-by: Petr Tesarik +--- + kexec/kexec.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/kexec/kexec.c b/kexec/kexec.c +index 33c1b4b..6601f1f 100644 +--- a/kexec/kexec.c ++++ b/kexec/kexec.c +@@ -1538,8 +1538,12 @@ int main(int argc, char *argv[]) + if (do_unload) { + if (do_kexec_file_syscall) { + result = kexec_file_unload(kexec_file_flags); +- if (result == EFALLBACK && do_kexec_fallback) ++ if (result == EFALLBACK && do_kexec_fallback) { ++ /* Reset getopt for fallback */ ++ opterr = 1; ++ optind = 1; + do_kexec_file_syscall = 0; ++ } + } + if (!do_kexec_file_syscall) + result = k_unload(kexec_flags); +@@ -1548,8 +1552,12 @@ int main(int argc, char *argv[]) + if (do_kexec_file_syscall) { + result = do_kexec_file_load(fileind, argc, argv, + kexec_file_flags); +- if (result == EFALLBACK && do_kexec_fallback) ++ if (result == EFALLBACK && do_kexec_fallback) { ++ /* Reset getopt for fallback */ ++ opterr = 1; ++ optind = 1; + do_kexec_file_syscall = 0; ++ } + } + if (!do_kexec_file_syscall) + result = my_load(type, fileind, argc, argv, +-- +2.16.4 + diff --git a/kexec-tools.changes b/kexec-tools.changes index 8a17ebf..f473d24 100644 --- a/kexec-tools.changes +++ b/kexec-tools.changes @@ -1,3 +1,15 @@ +------------------------------------------------------------------- +Fri Mar 13 14:11:55 UTC 2020 - Petr Tesařík + +- kexec-tools-reset-getopt-before-falling-back-to-legacy.patch: + Reset getopt before falling back to legacy syscall (bsc#1166105). + +------------------------------------------------------------------- +Fri Mar 13 08:37:58 UTC 2020 - Petr Tesařík + +- kexec-tools-fix-kexec_file_load-error-handling.patch: Fix the + error handling if kexec_file_load() fails (bsc#1166105). + ------------------------------------------------------------------- Wed Jan 29 07:35:18 UTC 2020 - Petr Tesařík diff --git a/kexec-tools.spec b/kexec-tools.spec index 54849cd..3c1a1b0 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -36,6 +36,8 @@ Patch7: %{name}-arm64-kdump-deal-with-resource-entries-in-proc-iomem.pat Patch8: %{name}-build-multiboot2-for-i386.patch Patch9: %{name}-video-capability.patch Patch10: %{name}-SYS_getrandom.patch +Patch11: %{name}-fix-kexec_file_load-error-handling.patch +Patch12: %{name}-reset-getopt-before-falling-back-to-legacy.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: systemd-rpm-macros @@ -68,6 +70,8 @@ the loaded kernel after it panics. %patch8 -p1 %patch9 -p1 %patch10 -p1 +%patch11 -p1 +%patch12 -p1 %build autoreconf -fvi