qemu/linux-user-Honor-elf-alignment-when-placing-images.patch
Jiabo Feng 05fcc90d20 QEMU update to version 8.2.0-28:
- hw/misc/mos6522: Fix bad class definition of the MOS6522 device
- target/i386: Fix minor typo in NO_NESTED_DATA_BP feature bit
- cpu: ensure we don't call start_exclusive from cpu_exec
- Avoid unaligned fetch in ladr_match()
- audio/audio.c: remove trailing newline in error_setg
- acpi/tests/avocado/bits: wait for 200 seconds for SHUTDOWN event from bits VM
- linux-user: Tolerate CONFIG_LSM_MMAP_MIN_ADDR
- accel/tcg: Fix user-only probe_access_internal plugin
- linux-user: Honor elf alignment when placing images
- Reserve address for MSI mapping in the CVM scenario.

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
(cherry picked from commit 3ab56c27fe6b593be9a24f27b52b2730efa05304)
2025-02-21 17:42:47 +08:00

106 lines
3.8 KiB
Diff

From ad5b05def5521a9cbbdd750c915fccaba391f53b Mon Sep 17 00:00:00 2001
From: Richard Henderson <richard.henderson@linaro.org>
Date: Tue, 12 Nov 2024 11:32:01 -0800
Subject: [PATCH] linux-user: Honor elf alignment when placing images
Most binaries don't actually depend on more than page alignment,
but any binary can request it. Not honoring this was a bug.
This became obvious when gdb reported
Failed to read a valid object file image from memory
when examining some vdso which are marked as needing more
than page alignment.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Zhongrui Tang <tangzhongrui_yewu@cmss.chinamobile.com>
---
linux-user/elfload.c | 35 ++++++++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index cf9e74468b..2a82468079 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -3263,7 +3263,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
char **pinterp_name)
{
g_autofree struct elf_phdr *phdr = NULL;
- abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr, error, align;
+ size_t reserve_size, align_size;
int i, prot_exec;
Error *err = NULL;
@@ -3347,6 +3348,9 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
load_addr = loaddr;
+ align = pow2ceil(info->alignment);
+ info->alignment = align;
+
if (pinterp_name != NULL) {
if (ehdr->e_type == ET_EXEC) {
/*
@@ -3355,8 +3359,6 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
*/
probe_guest_base(image_name, loaddr, hiaddr);
} else {
- abi_ulong align;
-
/*
* The binary is dynamic, but we still need to
* select guest_base. In this case we pass a size.
@@ -3374,10 +3376,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
* Since we do not have complete control over the guest
* address space, we prefer the kernel to choose some address
* rather than force the use of LOAD_ADDR via MAP_FIXED.
- * But without MAP_FIXED we cannot guarantee alignment,
- * only suggest it.
*/
- align = pow2ceil(info->alignment);
if (align) {
load_addr &= -align;
}
@@ -3401,13 +3400,35 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
* In both cases, we will overwrite pages in this range with mappings
* from the executable.
*/
- load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
+ reserve_size = (size_t)hiaddr - loaddr + 1;
+ align_size = reserve_size;
+
+ if (ehdr->e_type != ET_EXEC && align > qemu_real_host_page_size()) {
+ align_size += align - 1;
+ }
+
+ load_addr = target_mmap(load_addr, align_size, PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
(ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
-1, 0);
if (load_addr == -1) {
goto exit_mmap;
}
+
+ if (align_size != reserve_size) {
+ abi_ulong align_addr = ROUND_UP(load_addr, align);
+ abi_ulong align_end = align_addr + reserve_size;
+ abi_ulong load_end = load_addr + align_size;
+
+ if (align_addr != load_addr) {
+ target_munmap(load_addr, align_addr - load_addr);
+ }
+ if (align_end != load_end) {
+ target_munmap(align_end, load_end - align_end);
+ }
+ load_addr = align_addr;
+ }
+
load_bias = load_addr - loaddr;
if (elf_is_fdpic(ehdr)) {
--
2.41.0.windows.1