From: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
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 <razvanghiorghe16@gmail.com>
Reviewed-by: Helge Deller <deller@gmx.de>
Signed-off-by: Helge Deller <deller@gmx.de>
---
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;
+ }
+ }
}
}
--
2.53.0
© 2016 - 2026 Red Hat, Inc.