aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-04-10 13:02:25 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-04-10 13:02:25 +0100
commit7f0f4208b3a96f2202e86bc3e58a4c20d390ce1b (patch)
tree31ecf2172ec7703c081089891339f9df703ff572
parentc52e7132d7c885841500f5277f7305f62767fe1d (diff)
linux-user/signal.c: Ensure AArch64 signal frame isn't too small
The AArch64 signal frame design was extended for SVE in commit 8c5931de0ac77388096d79ceb, so that instead of having a fixed setup we now add various records to the frame, with some of them possibly overflowing into an extra space outside the original 4K reserved block in the target_sigcontext. However, we failed to ensure that we always at least allocate the 4K reserved block. This is ABI, and some userspace programs rely on it. In particular the dash shell would segfault if the frame wasn't as big enough. (Compare the kernel's sigframe_size() function in arch/arm64/kernel/signal.c.) Reported-by: Richard Henwood <richard.henwood@arm.com> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20180409140714.26841-1-peter.maydell@linaro.org Fixes: https://bugs.launchpad.net/bugs/1761535 Fixes: 8c5931de0ac77388096d79ceb Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--linux-user/signal.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 046d4c8aa0..8d9e6e8410 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1850,6 +1850,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
fr_ofs = layout.total_size;
layout.total_size += sizeof(struct target_rt_frame_record);
+ /* We must always provide at least the standard 4K reserved space,
+ * even if we don't use all of it (this is part of the ABI)
+ */
+ layout.total_size = MAX(layout.total_size,
+ sizeof(struct target_rt_sigframe));
+
frame_addr = get_sigframe(ka, env, layout.total_size);
trace_user_setup_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {