aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2023-07-17 12:27:13 +0200
committerMichael Tokarev <mjt@tls.msk.ru>2023-07-31 08:52:38 +0300
commitc4a4731408aca296ad88770e8a545b42e40a5d56 (patch)
tree325fd3708e5ae32b497c6e48d70547994494ddae
parent0102c92a1c2736fc183bd464c1f899c96ca8faea (diff)
linux-user: Prohibit brk() to to shrink below initial heap address
Since commit 86f04735ac ("linux-user: Fix brk() to release pages") it's possible for userspace applications to reduce their memory footprint by calling brk() with a lower address and free up memory. Before that commit guest heap memory was never unmapped. But the Linux kernel prohibits to reduce brk() below the initial memory address which is set at startup by the set_brk() function in binfmt_elf.c. Such a range check was missed in commit 86f04735ac. This patch adds the missing check by storing the initial brk value in initial_target_brk and verify any new brk addresses against that value. Tested with the i386 upx binary from https://github.com/upx/upx/releases/download/v4.0.2/upx-4.0.2-i386_linux.tar.xz Signed-off-by: Helge Deller <deller@gmx.de> Tested-by: "Markus F.X.J. Oberhumer" <markus@oberhumer.com> Fixes: 86f04735ac ("linux-user: Fix brk() to release pages") Cc: qemu-stable@nongnu.org Buglink: https://github.com/upx/upx/issues/683 (cherry picked from commit dfe49864afb06e7e452a4366051697bc4fcfc1a5) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--linux-user/syscall.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c358f4fcbb..33814bae88 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -801,12 +801,13 @@ static inline int host_to_target_sock_type(int host_type)
return target_type;
}
-static abi_ulong target_brk;
+static abi_ulong target_brk, initial_target_brk;
static abi_ulong brk_page;
void target_set_brk(abi_ulong new_brk)
{
target_brk = TARGET_PAGE_ALIGN(new_brk);
+ initial_target_brk = target_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
}
@@ -824,6 +825,11 @@ abi_long do_brk(abi_ulong brk_val)
return target_brk;
}
+ /* do not allow to shrink below initial brk value */
+ if (brk_val < initial_target_brk) {
+ brk_val = initial_target_brk;
+ }
+
new_brk = TARGET_PAGE_ALIGN(brk_val);
new_host_brk_page = HOST_PAGE_ALIGN(brk_val);