[Stable-11.1.1 19/42] pc-bios/s390-ccw: bounds-check zipl menu entry index before array write
Michael Tokarev <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu,gmane.comp.emulators.qemu.stable |
|---|---|
| Message-ID | <[email protected]> |
From: Joshua Daley <[email protected]> menu_get_zipl_boot_index() iterates NUL-separated strings from the zipl stage-2 boot-menu block, passes each to zipl_print_entry() which converts EBCDIC to ASCII and returns atoi(), then writes true into valid_entries[entry]. valid_entries is a MAX_BOOT_ENTRIES element stack array, but entry was never bounds-checked, so a crafted on-disk value could index arbitrarily beyond the array. Fix this in two places: - zipl_print_entry() now validates that the first significant character (after an optional leading space) is a digit. Entries that fail this check return -1 without printing. - menu_get_zipl_boot_index() skips any entry whose index is outside [0, MAX_BOOT_ENTRIES) before writing to valid_entries[]. Fixes: 7385e947fc65 ("pc-bios/s390-ccw: fix non-sequential boot entries (eckd)") Cc: [email protected] Signed-off-by: Joshua Daley <[email protected]> Reviewed-by: Matthew Rosato <[email protected]> Reviewed-by: Eric Farman <[email protected]> Link: https://lore.kernel.org/qemu-devel/[email protected] [[email protected]: Added qemu-stable] Signed-off-by: Eric Farman <[email protected]> (cherry picked from commit 33909d4ebd5c197626c3142550ee11f4bdb1df48) Signed-off-by: Michael Tokarev <[email protected]> diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index eeaff78f870..b6a9a56d462 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -176,18 +176,24 @@ int menu_get_boot_index(bool *valid_entries) return boot_index; } -/* Returns the entry number that was printed */ +/* Returns the entry number that was printed, or -1 on invalid entry */ static int zipl_print_entry(const char *data, size_t len) { char buf[len + 2]; + const char *p; ebcdic_to_ascii(data, buf, len); buf[len] = '\n'; buf[len + 1] = '\0'; + p = (buf[0] == ' ') ? buf + 1 : buf; + if (!isdigit((unsigned char)*p)) { + return -1; + } + printf("%s", buf); - return buf[0] == ' ' ? atoi(buf + 1) : atoi(buf); + return atoi(p); } int menu_get_zipl_boot_index(const char *menu_data) @@ -216,6 +222,9 @@ int menu_get_zipl_boot_index(const char *menu_data) entry = zipl_print_entry(menu_data, len); menu_data += len + 1; + if (entry < 0 || entry >= MAX_BOOT_ENTRIES) { + continue; + } valid_entries[entry] = true; if (entry == 0) { -- 2.47.3