@samitouri / QOSamiQemu / commits / 33909d4ebd

pc-bios/s390-ccw: bounds-check zipl menu entry index before array write

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: qemu-stable@nongnu.org Signed-off-by: Joshua Daley <jdaley@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Reviewed-by: Eric Farman <farman@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260727115052.24289-5-borntraeger@linux.ibm.com [farman@linux.ibm.com: Added qemu-stable] Signed-off-by: Eric Farman <farman@linux.ibm.com>

Joshua Daley committed Jul 27, 2026 at 13:50 UTC 33909d4ebd5c197626c3142550ee11f4bdb1df48
1 file changed +11 -2
pc-bios/s390-ccw/menu.c
+11 -2
@@ -176,18 +176,24 @@ int menu_get_boot_index(bool *valid_entries)
176 return boot_index;
177 }
178
179 -/* Returns the entry number that was printed */
179 +/* Returns the entry number that was printed, or -1 on invalid entry */
180 static int zipl_print_entry(const char *data, size_t len)
181 {
182 char buf[len + 2];
183 + const char *p;
184
185 ebcdic_to_ascii(data, buf, len);
186 buf[len] = '\n';
187 buf[len + 1] = '\0';
188
189 + p = (buf[0] == ' ') ? buf + 1 : buf;
190 + if (!isdigit((unsigned char)*p)) {
191 + return -1;
192 + }
193 +
194 printf("%s", buf);
195
190 - return buf[0] == ' ' ? atoi(buf + 1) : atoi(buf);
196 + return atoi(p);
197 }
198
199 int menu_get_zipl_boot_index(const char *menu_data)
@@ -216,6 +222,9 @@ int menu_get_zipl_boot_index(const char *menu_data)
222 entry = zipl_print_entry(menu_data, len);
223 menu_data += len + 1;
224
225 + if (entry < 0 || entry >= MAX_BOOT_ENTRIES) {
226 + continue;
227 + }
228 valid_entries[entry] = true;
229
230 if (entry == 0) {