Commit bb3ba35f authored by Peter Maydell's avatar Peter Maydell
Browse files

linux-user: check that all of AArch64 SVE extended sigframe is writable



In commit 8c5931de we added support for SVE extended
sigframe records.  These mean that the signal frame might now be
larger than the size of the target_rt_sigframe record, so make sure
we call lock_user on the entire frame size when we're creating it.
(The code for restoring the signal frame already correctly handles
the extended records by locking the 'extra' section separately to the
main section.)

In particular, this fixes a bug even for non-SVE signal frames,
because it extends the locked section to cover the
target_rt_frame_record. Previously this was part of 'struct
target_rt_sigframe', but in commit e1eecd1d we pulled
it out into its own struct, and so locking the target_rt_sigframe
alone doesn't cover it. This bug would mean that we would fail
to correctly handle the case where a signal was taken with
SP pointing 16 bytes into an unwritable page, with the page
immediately below it in memory being writable.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
parent 0df21216
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -1858,7 +1858,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,

    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)) {
    frame = lock_user(VERIFY_WRITE, frame_addr, layout.total_size, 0);
    if (!frame) {
        goto give_sigsegv;
    }

@@ -1904,11 +1905,11 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
        env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
    }

    unlock_user_struct(frame, frame_addr, 1);
    unlock_user(frame, frame_addr, layout.total_size);
    return;

 give_sigsegv:
    unlock_user_struct(frame, frame_addr, 1);
    unlock_user(frame, frame_addr, layout.total_size);
    force_sigsegv(usig);
}