From: Eric Farman <farman@linux.ibm.com>
To: qemu-devel@nongnu.org
Cc: qemu-s390x@nongnu.org, Matthew Rosato <mjrosato@linux.ibm.com>,
Cornelia Huck <cohuck@redhat.com>,
Joshua Daley <jdaley@linux.ibm.com>,
qemu-stable@nongnu.org, Eric Farman <farman@linux.ibm.com>
Subject: [PULL 09/15] pc-bios/s390-ccw: bound zipl menu strlen and replace VLA in zipl_print_entry
Date: Wed, 12 Aug 2026 13:17:01 -0400 [thread overview]
Message-ID: <20260812171707.1605637-10-farman@linux.ibm.com> (raw)
In-Reply-To: <20260812171707.1605637-1-farman@linux.ibm.com>
From: Joshua Daley <jdaley@linux.ibm.com>
menu_get_zipl_boot_index() calls strlen() on a pointer into the middle
of _s2 with no upper bound, so a stage-2 image whose blocks contain no
NUL bytes causes strlen() to walk beyond _s2. The resulting length
is then used to size a stack VLA in zipl_print_entry(), risking a stack
overflow.
Fix by:
- Implementing strnlen(), a bounded version of strlen(). s390-ccw uses
libc from SLOF, which includes strlen() but does not have an
implementation of strnlen(), so we must implement our own.
- Adding a menu_data_end parameter to menu_get_zipl_boot_index() and
replacing both strlen() calls with strnlen() bounded by the remaining
buffer space. The loop guard also checks that the pointer has not
reached menu_data_end. The function returns 0 (boot default) if
somehow menu_data reaches menu_data_end before printing any entries.
- Replacing the VLA char buf[len + 2] in zipl_print_entry() with a fixed
ZIPL_ENTRY_MAX + 2 (82-byte) buffer and truncating len before use.
- Passing s2_end (_s2 + sizeof(_s2)) as menu_data_end at the one call
site in eckd_get_boot_menu_index(), so the bound is exactly the end of
the buffer.
Fixes: f7178910845a ("s390-ccw: print zipl boot menu")
Cc: qemu-stable@nongnu.org
Signed-off-by: Joshua Daley <jdaley@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/qemu-devel/20260728134704.2924005-2-jdaley@linux.ibm.com
[farman@linux.ibm.com: Per list, add strnlen rationale to commit message
and added cc stable]
Signed-off-by: Eric Farman <farman@linux.ibm.com>
---
pc-bios/s390-ccw/bootmap.c | 4 +++-
pc-bios/s390-ccw/helper.h | 10 ++++++++++
| 29 +++++++++++++++++++++++------
pc-bios/s390-ccw/s390-ccw.h | 2 +-
4 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index ed6e8cbbc7..81512265ce 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -61,6 +61,7 @@ static uint8_t _s2[MAX_SECTOR_SIZE * 3] __attribute__((__aligned__(PAGE_SIZE)));
static void *s2_prev_blk = _s2;
static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
+static void *s2_end = _s2 + sizeof(_s2);
static inline int verify_boot_info(BootInfo *bip)
{
@@ -308,7 +309,8 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
}
}
- return menu_get_zipl_boot_index(s2_cur_blk + banner_offset);
+ return menu_get_zipl_boot_index(s2_cur_blk + banner_offset,
+ s2_end);
}
prev_block_nr = cur_block_nr;
diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h
index 8e3dfcb6d6..d9b7da444a 100644
--- a/pc-bios/s390-ccw/helper.h
+++ b/pc-bios/s390-ccw/helper.h
@@ -45,4 +45,14 @@ static inline void sleep(unsigned int seconds)
}
}
+static inline size_t strnlen(const char *s, size_t maxlen)
+{
+ size_t len = 0;
+
+ while (len < maxlen && s[len]) {
+ len++;
+ }
+ return len;
+}
+
#endif
--git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index b6a9a56d46..9b81154b0e 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -16,6 +16,7 @@
#include "s390-ccw.h"
#include "sclp.h"
#include "s390-time.h"
+#include "helper.h"
#define KEYCODE_NO_INP '\0'
#define KEYCODE_ESCAPE '\033'
@@ -26,6 +27,9 @@
#define ZIPL_TIMEOUT_OFFSET 138
#define ZIPL_FLAG_OFFSET 140
+/* Max printable chars for a zipl boot menu entry */
+#define ZIPL_ENTRY_MAX 80
+
#define TOD_CLOCK_MILLISECOND 0x3e8000
#define LOW_CORE_EXTERNAL_INT_ADDR 0x86
@@ -179,9 +183,13 @@ int menu_get_boot_index(bool *valid_entries)
/* 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];
+ char buf[ZIPL_ENTRY_MAX + 2];
const char *p;
+ if (len > ZIPL_ENTRY_MAX) {
+ len = ZIPL_ENTRY_MAX;
+ }
+
ebcdic_to_ascii(data, buf, len);
buf[len] = '\n';
buf[len + 1] = '\0';
@@ -196,7 +204,7 @@ static int zipl_print_entry(const char *data, size_t len)
return atoi(p);
}
-int menu_get_zipl_boot_index(const char *menu_data)
+int menu_get_zipl_boot_index(const char *menu_data, const char *menu_data_end)
{
size_t len;
int entry;
@@ -212,13 +220,22 @@ int menu_get_zipl_boot_index(const char *menu_data)
timeout = zipl_timeout * 1000;
}
- /* Print banner */
+ if (menu_data >= menu_data_end) {
+ return 0; /* Boot default */
+ }
+
+ /* Skip banner */
+ len = strnlen(menu_data, menu_data_end - menu_data);
+ menu_data += len + 1;
+ if (menu_data >= menu_data_end || !(*menu_data)) {
+ return 0; /* No entries, boot default */
+ }
+
puts("s390-ccw zIPL Boot Menu\n");
- menu_data += strlen(menu_data) + 1;
/* Print entries */
- while (*menu_data) {
- len = strlen(menu_data);
+ while (menu_data < menu_data_end && *menu_data) {
+ len = strnlen(menu_data, menu_data_end - menu_data);
entry = zipl_print_entry(menu_data, len);
menu_data += len + 1;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 1e1f71775e..f6030a6071 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -76,7 +76,7 @@ void jump_to_low_kernel(void);
/* menu.c */
void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
-int menu_get_zipl_boot_index(const char *menu_data);
+int menu_get_zipl_boot_index(const char *menu_data, const char *menu_data_end);
bool menu_is_enabled_zipl(void);
int menu_get_enum_boot_index(bool *valid_entries);
bool menu_is_enabled_enum(void);
--
2.55.0
next prev parent reply other threads:[~2026-08-12 17:19 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 17:16 [PULL 00/15] s390x queue Eric Farman
2026-08-12 17:16 ` [PULL 01/15] target/s390x: Make PRNO TRNG interruptible Eric Farman
2026-08-12 17:16 ` [PULL 02/15] tests/tcg/s390x: Test PRNO TRNG interruptibility Eric Farman
2026-08-12 17:16 ` [PULL 03/15] target/s390x: Fix DR/D INT64_MIN / -1 host crash Eric Farman
2026-08-12 17:16 ` [PULL 04/15] tests/tcg/s390x: Test DR overflow (INT64_MIN / -1) Eric Farman
2026-08-12 17:16 ` [PULL 05/15] hw/char/sclpconsole-lm: avoid guest triggerable assert Eric Farman
2026-08-12 17:16 ` [PULL 06/15] s390x/ipl: validate num_comp against iplb length before iterating Eric Farman
2026-08-12 17:16 ` [PULL 07/15] pc-bios/s390-ccw: fix out-of-bounds read in iso_get_file_size() Eric Farman
2026-08-12 17:17 ` [PULL 08/15] pc-bios/s390-ccw: bounds-check zipl menu entry index before array write Eric Farman
2026-08-12 17:17 ` Eric Farman [this message]
2026-08-12 17:17 ` [PULL 10/15] pc-bios/s390-ccw: Fix off-by-one errors with loadparm and boot entries Eric Farman
2026-08-12 17:17 ` [PULL 11/15] target/s390x/tcg: Set STCK/STCKF condition code after the store Eric Farman
2026-08-12 17:17 ` [PULL 12/15] tests/tcg/s390x: Test STCKF condition code on a faulting store Eric Farman
2026-08-12 17:17 ` [PULL 13/15] target/s390x: Allow 2G hugepages guest backing Eric Farman
2026-08-12 17:17 ` [PULL 14/15] hw: add compat machines for 11.2 Eric Farman
2026-08-12 17:17 ` [PULL 15/15] pc-bios/s390-ccw.img: update s390x bios Eric Farman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260812171707.1605637-10-farman@linux.ibm.com \
--to=farman@linux.ibm.com \
--cc=cohuck@redhat.com \
--cc=jdaley@linux.ibm.com \
--cc=mjrosato@linux.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=qemu-stable@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.