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 <razvanghiorghe16@gmail.com> Reviewed-by: Helge Deller <deller@gmx.de> Signed-off-by: Helge Deller <deller@gmx.de>
Razvan Ghiorghe committed
Feb 2, 2026 at 02:24 UTC
2ff529c6f64b706213339d4bbce76c7788243ddb
1 file changed
+23
-14
linux-user/elfload.c
+23
-14
@@ -449,12 +449,6 @@ static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
449
{
450
abi_ulong align_bss;
451
452
- /* We only expect writable bss; the code segment shouldn't need this. */
453
- if (!(prot & PROT_WRITE)) {
454
- error_setg(errp, "PT_LOAD with non-writable bss");
455
- return false;
456
- }
457
-
452
align_bss = TARGET_PAGE_ALIGN(start_bss);
453
end_bss = TARGET_PAGE_ALIGN(end_bss);
454
@@ -472,20 +466,35 @@ static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
466
*/
467
align_bss -= TARGET_PAGE_SIZE;
468
} else {
469
+ abi_ulong start_page_aligned = start_bss & TARGET_PAGE_MASK;
470
/*
476
- * The start of the bss shares a page with something.
477
- * The only thing that we expect is the data section,
478
- * which would already be marked writable.
479
- * Overlapping the RX code segment seems malformed.
471
+ * The logical OR between flags and PAGE_WRITE works because
472
+ * in include/exec/page-protection.h they are defined as PROT_*
473
+ * values, matching mprotect().
474
+ * Temporarily enable write access to zero the fractional bss.
475
+ * target_mprotect() handles TB invalidation if needed.
476
*/
477
if (!(flags & PAGE_WRITE)) {
482
- error_setg(errp, "PT_LOAD with bss overlapping "
483
- "non-writable page");
484
- return false;
478
+ if (target_mprotect(start_page_aligned,
479
+ TARGET_PAGE_SIZE,
480
+ prot | PAGE_WRITE) == -1) {
481
+ error_setg_errno(errp, errno,
482
+ "Error enabling write access for bss");
483
+ return false;
484
+ }
485
}
486
487
- /* The page is already mapped and writable. */
487
+ /* The page is already mapped and now guaranteed writable. */
488
memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
489
+
490
+ if (!(flags & PAGE_WRITE)) {
491
+ if (target_mprotect(start_page_aligned,
492
+ TARGET_PAGE_SIZE, prot) == -1) {
493
+ error_setg_errno(errp, errno,
494
+ "Error restoring bss first permissions");
495
+ return false;
496
+ }
497
+ }
498
}
499
}
500