From 2ff529c6f64b706213339d4bbce76c7788243ddb Mon Sep 17 00:00:00 2001 From: Razvan Ghiorghe Date: Mon, 2 Feb 2026 02:24:46 +0200 Subject: [PATCH] linux-user: Fix zero_bss for RX PT_LOAD segments zero_bss() incorrectly assumed that any PT_LOAD containing .bss must be writable, rejecting valid ELF binaries where .bss overlaps the tail of an RX file-backed page. Instead of failing, temporarily enable write access on the overlapping page to zero the fractional bss range, then restore the original page permissions once initialization is complete. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3179 Signed-off-by: Razvan Ghiorghe Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/elfload.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 35471c0c9a..59b543f740 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -449,12 +449,6 @@ static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss, { abi_ulong align_bss; - /* We only expect writable bss; the code segment shouldn't need this. */ - if (!(prot & PROT_WRITE)) { - error_setg(errp, "PT_LOAD with non-writable bss"); - return false; - } - align_bss = TARGET_PAGE_ALIGN(start_bss); end_bss = TARGET_PAGE_ALIGN(end_bss); @@ -472,20 +466,35 @@ static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss, */ align_bss -= TARGET_PAGE_SIZE; } else { + abi_ulong start_page_aligned = start_bss & TARGET_PAGE_MASK; /* - * The start of the bss shares a page with something. - * The only thing that we expect is the data section, - * which would already be marked writable. - * Overlapping the RX code segment seems malformed. + * The logical OR between flags and PAGE_WRITE works because + * in include/exec/page-protection.h they are defined as PROT_* + * values, matching mprotect(). + * Temporarily enable write access to zero the fractional bss. + * target_mprotect() handles TB invalidation if needed. */ if (!(flags & PAGE_WRITE)) { - error_setg(errp, "PT_LOAD with bss overlapping " - "non-writable page"); - return false; + if (target_mprotect(start_page_aligned, + TARGET_PAGE_SIZE, + prot | PAGE_WRITE) == -1) { + error_setg_errno(errp, errno, + "Error enabling write access for bss"); + return false; + } } - /* The page is already mapped and writable. */ + /* The page is already mapped and now guaranteed writable. */ memset(g2h_untagged(start_bss), 0, align_bss - start_bss); + + if (!(flags & PAGE_WRITE)) { + if (target_mprotect(start_page_aligned, + TARGET_PAGE_SIZE, prot) == -1) { + error_setg_errno(errp, errno, + "Error restoring bss first permissions"); + return false; + } + } } }