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>
This commit is contained in:
Razvan Ghiorghe
2026-02-02 02:24:46 +02:00
committed by Helge Deller
parent 1fd5ff9d76
commit 2ff529c6f6

View File

@@ -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;
}
}
}
}