From a2663ec8d351e17e3aaa85690f5daf3eb8c30d97 Mon Sep 17 00:00:00 2001 From: Marc Hartmayer Date: Thu, 8 Jan 2026 11:26:06 +0000 Subject: [PATCH] zipl/boot: Fix unsigned long overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix two issues in boot menu input parsing: 1. ebcdic_strtoul returns unsigned long but the value was stored in an int. 2. ebcdic_strtoul could overflow if @value exceeds ULONG_MAX. Both problems are easy to trigger by entering an excessively large value in the boot menu, which can lead to unsigned long overflow and memory corruption. Use a checked addition to prevent overflow and change menu_read() return type to unsigned long. Suggested-by: Eduard Shishkin Reviewed-by: Eduard Shishkin Signed-off-by: Marc Hartmayer Signed-off-by: Jan Höppner --- zipl/boot/ebcdic.c | 9 ++++++--- zipl/boot/menu.c | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/zipl/boot/ebcdic.c b/zipl/boot/ebcdic.c index be3441b7..2d0bb536 100644 --- a/zipl/boot/ebcdic.c +++ b/zipl/boot/ebcdic.c @@ -8,11 +8,13 @@ * */ +#include + #include "ebcdic.h" - /* - * Convert ebcdic string to number with given base + * Convert EBCDIC string to number with given base. In case of an overflow, + * ULONG_MAX is returned and @endptr is not updated. */ unsigned long ebcdic_strtoul(char *nptr, char **endptr, int base) { @@ -21,7 +23,8 @@ unsigned long ebcdic_strtoul(char *nptr, char **endptr, int base) while (ebcdic_isdigit(*nptr)) { if (val != 0) val *= base; - val += *nptr - 0xf0; + if (__builtin_uaddl_overflow(val, *nptr - 0xf0, &val)) + return ULONG_MAX; nptr++; } if (endptr) diff --git a/zipl/boot/menu.c b/zipl/boot/menu.c index 6d30cf81..73bb11d2 100644 --- a/zipl/boot/menu.c +++ b/zipl/boot/menu.c @@ -27,12 +27,12 @@ static void menu_prompt(int timeout) printf("Please choose:"); } -static int menu_read(void) +static unsigned long menu_read(void) { char *temp_area = (char *)get_zeroed_page(); int timeout, rc, i, count = 0; + unsigned long value; char *endptr; - int value; timeout = __stage2_params.timeout;