* [Qemu-devel] [PATCH 1/2] linux-user: Add wrapper for guest uses of sigprocmask function
2014-03-14 14:36 [Qemu-devel] [PATCH 0/2] linux-user: Don't allow guest to block SIGSEGV Peter Maydell
@ 2014-03-14 14:36 ` Peter Maydell
2014-03-14 14:36 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for " Peter Maydell
2014-03-14 14:36 ` [Qemu-devel] [PATCH 2/2] linux-user: Don't allow guest to block SIGSEGV Peter Maydell
2 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2014-03-14 14:36 UTC (permalink / raw)
To: qemu-devel
Cc: Michael Matz, patches, Dann Frazier, Riku Voipio, Alexander Graf,
Alex Bennée
From: Alex Barcelo <abarcelo@ac.upc.edu>
Create a wrapper for signal mask changes initiated by the guest;
(this includes syscalls and also the sigreturns from signal.c)
this will give us a place to put code which prevents the guest
from changing the handling of signals used by QEMU itself
internally.
The wrapper is called from all the guest-initiated sigprocmask, but
is not called from internal qemu sigprocmask calls.
Signed-off-by: Alex Barcelo <abarcelo@ac.upc.edu>
[PMM: Added calls to wrapper for sigprocmask uses in signal.c
when setting the signal mask on entry and exit from signal
handlers, since these also are guest-provided signal masks.]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
linux-user/qemu.h | 1 +
linux-user/signal.c | 58 ++++++++++++++++++++++++++++++----------------------
linux-user/syscall.c | 14 ++++++-------
3 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index c2f74f3..4d24e74 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -235,6 +235,7 @@ int host_to_target_signal(int sig);
long do_sigreturn(CPUArchState *env);
long do_rt_sigreturn(CPUArchState *env);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
#ifdef TARGET_I386
/* vm86.c */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 24c91f3..c8df584 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -197,6 +197,16 @@ void target_to_host_old_sigset(sigset_t *sigset,
target_to_host_sigset(sigset, &d);
}
+/* Wrapper for sigprocmask function
+ * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
+ * are host signal set, not guest ones. This wraps the sigprocmask host calls
+ * that should be protected (calls originated from guest)
+ */
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+ return sigprocmask(how, set, oldset);
+}
+
/* siginfo conversion */
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
@@ -1056,7 +1066,7 @@ long do_sigreturn(CPUX86State *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
if (restore_sigcontext(env, &frame->sc, &eax))
@@ -1081,7 +1091,7 @@ long do_rt_sigreturn(CPUX86State *env)
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
goto badframe;
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
goto badframe;
@@ -1220,7 +1230,7 @@ static int target_restore_sigframe(CPUARMState *env,
uint64_t pstate;
target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
for (i = 0; i < 31; i++) {
__get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
@@ -1861,7 +1871,7 @@ static long do_sigreturn_v1(CPUARMState *env)
}
target_to_host_sigset_internal(&host_set, &set);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->sc))
goto badframe;
@@ -1942,7 +1952,7 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
abi_ulong *regspace;
target_to_host_sigset(&host_set, &uc->tuc_sigmask);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &uc->tuc_mcontext))
return 1;
@@ -2033,7 +2043,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
goto badframe;
target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
goto badframe;
@@ -2444,7 +2454,7 @@ long do_sigreturn(CPUSPARCState *env)
}
target_to_host_sigset_internal(&host_set, &set);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (err)
goto segv_and_exit;
@@ -2567,7 +2577,7 @@ void sparc64_set_context(CPUSPARCState *env)
goto do_sigsegv;
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
}
env->pc = pc;
env->npc = npc;
@@ -2656,7 +2666,7 @@ void sparc64_get_context(CPUSPARCState *env)
err = 0;
- sigprocmask(0, NULL, &set);
+ do_sigprocmask(0, NULL, &set);
host_to_target_sigset_internal(&target_set, &set);
if (TARGET_NSIG_WORDS == 1) {
err |= __put_user(target_set.sig[0],
@@ -2991,7 +3001,7 @@ long do_sigreturn(CPUMIPSState *regs)
}
target_to_host_sigset_internal(&blocked, &target_set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(regs, &frame->sf_sc))
goto badframe;
@@ -3095,7 +3105,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
goto badframe;
target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
goto badframe;
@@ -3385,7 +3395,7 @@ long do_sigreturn(CPUSH4State *regs)
goto badframe;
target_to_host_sigset_internal(&blocked, &target_set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(regs, &frame->sc, &r0))
goto badframe;
@@ -3414,7 +3424,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
goto badframe;
target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
goto badframe;
@@ -3644,7 +3654,7 @@ long do_sigreturn(CPUMBState *env)
goto badframe;
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
restore_sigcontext(&frame->uc.tuc_mcontext, env);
/* We got here through a sigreturn syscall, our path back is via an
@@ -3819,7 +3829,7 @@ long do_sigreturn(CPUCRISState *env)
goto badframe;
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
restore_sigcontext(&frame->sc, env);
unlock_user_struct(frame, frame_addr, 0);
@@ -4350,7 +4360,7 @@ long do_sigreturn(CPUS390XState *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+ do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
if (restore_sigregs(env, &frame->sregs)) {
goto badframe;
@@ -4378,7 +4388,7 @@ long do_rt_sigreturn(CPUS390XState *env)
}
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+ do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
goto badframe;
@@ -4906,7 +4916,7 @@ long do_sigreturn(CPUPPCState *env)
goto sigsegv;
#endif
target_to_host_sigset_internal(&blocked, &set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (__get_user(sr_addr, &sc->regs))
goto sigsegv;
@@ -4950,7 +4960,7 @@ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
return 1;
target_to_host_sigset_internal(&blocked, &set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_user_regs(env, mcp, sig))
goto sigsegv;
@@ -5324,7 +5334,7 @@ long do_sigreturn(CPUM68KState *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
@@ -5352,7 +5362,7 @@ long do_rt_sigreturn(CPUM68KState *env)
goto badframe;
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
@@ -5599,7 +5609,7 @@ long do_sigreturn(CPUAlphaState *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, sc)) {
goto badframe;
@@ -5622,7 +5632,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
goto badframe;
}
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
goto badframe;
@@ -5739,7 +5749,7 @@ void process_pending_signals(CPUArchState *cpu_env)
sigaddset(&set, target_to_host_signal(sig));
/* block signals in the handler using Linux */
- sigprocmask(SIG_BLOCK, &set, &old_set);
+ do_sigprocmask(SIG_BLOCK, &set, &old_set);
/* save the previous blocked signal state to restore it at the
end of the signal execution (see do_sigreturn) */
host_to_target_sigset_internal(&target_old_set, &old_set);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ffc11de..2a8b66c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5993,7 +5993,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
sigset_t cur_set;
abi_ulong target_set;
- sigprocmask(0, NULL, &cur_set);
+ do_sigprocmask(0, NULL, &cur_set);
host_to_target_old_sigset(&target_set, &cur_set);
ret = target_set;
}
@@ -6004,10 +6004,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
sigset_t set, oset, cur_set;
abi_ulong target_set = arg1;
- sigprocmask(0, NULL, &cur_set);
+ do_sigprocmask(0, NULL, &cur_set);
target_to_host_old_sigset(&set, &target_set);
sigorset(&set, &set, &cur_set);
- sigprocmask(SIG_SETMASK, &set, &oset);
+ do_sigprocmask(SIG_SETMASK, &set, &oset);
host_to_target_old_sigset(&target_set, &oset);
ret = target_set;
}
@@ -6038,7 +6038,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- ret = get_errno(sigprocmask(how, &set, &oldset));
+ ret = get_errno(do_sigprocmask(how, &set, &oldset));
if (!is_error(ret)) {
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
@@ -6072,7 +6072,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = 0;
set_ptr = NULL;
}
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+ ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
goto efault;
@@ -6112,7 +6112,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = 0;
set_ptr = NULL;
}
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+ ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
goto efault;
@@ -8125,7 +8125,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- sigprocmask(how, &set, &oldset);
+ do_sigprocmask(how, &set, &oldset);
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
}
--
1.9.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function
2014-03-14 14:36 [Qemu-devel] [PATCH 0/2] linux-user: Don't allow guest to block SIGSEGV Peter Maydell
2014-03-14 14:36 ` [Qemu-devel] [PATCH 1/2] linux-user: Add wrapper for guest uses of sigprocmask function Peter Maydell
@ 2014-03-14 14:36 ` Peter Maydell
2014-03-14 14:36 ` [Qemu-devel] [PATCH 2/2] linux-user: Don't allow guest to block SIGSEGV Peter Maydell
2 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2014-03-14 14:36 UTC (permalink / raw)
To: qemu-devel
Cc: Michael Matz, patches, Dann Frazier, Riku Voipio, Alexander Graf,
Alex Bennée
From: Alex Barcelo <abarcelo@ac.upc.edu>
Create a wrapper for signal mask changes initiated by the guest;
(this includes syscalls and also the sigreturns from signal.c)
this will give us a place to put code which prevents the guest
from changing the handling of signals used by QEMU itself
internally.
The wrapper is called from all the guest-initiated sigprocmask, but
is not called from internal qemu sigprocmask calls.
Signed-off-by: Alex Barcelo <abarcelo@ac.upc.edu>
[PMM: Added calls to wrapper for sigprocmask uses in signal.c
when setting the signal mask on entry and exit from signal
handlers, since these also are guest-provided signal masks.]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
linux-user/qemu.h | 1 +
linux-user/signal.c | 58 ++++++++++++++++++++++++++++++----------------------
linux-user/syscall.c | 14 ++++++-------
3 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index c2f74f3..4d24e74 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -235,6 +235,7 @@ int host_to_target_signal(int sig);
long do_sigreturn(CPUArchState *env);
long do_rt_sigreturn(CPUArchState *env);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
#ifdef TARGET_I386
/* vm86.c */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 24c91f3..c8df584 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -197,6 +197,16 @@ void target_to_host_old_sigset(sigset_t *sigset,
target_to_host_sigset(sigset, &d);
}
+/* Wrapper for sigprocmask function
+ * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
+ * are host signal set, not guest ones. This wraps the sigprocmask host calls
+ * that should be protected (calls originated from guest)
+ */
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+ return sigprocmask(how, set, oldset);
+}
+
/* siginfo conversion */
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
@@ -1056,7 +1066,7 @@ long do_sigreturn(CPUX86State *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
if (restore_sigcontext(env, &frame->sc, &eax))
@@ -1081,7 +1091,7 @@ long do_rt_sigreturn(CPUX86State *env)
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
goto badframe;
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
goto badframe;
@@ -1220,7 +1230,7 @@ static int target_restore_sigframe(CPUARMState *env,
uint64_t pstate;
target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
for (i = 0; i < 31; i++) {
__get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
@@ -1861,7 +1871,7 @@ static long do_sigreturn_v1(CPUARMState *env)
}
target_to_host_sigset_internal(&host_set, &set);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->sc))
goto badframe;
@@ -1942,7 +1952,7 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
abi_ulong *regspace;
target_to_host_sigset(&host_set, &uc->tuc_sigmask);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &uc->tuc_mcontext))
return 1;
@@ -2033,7 +2043,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
goto badframe;
target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
goto badframe;
@@ -2444,7 +2454,7 @@ long do_sigreturn(CPUSPARCState *env)
}
target_to_host_sigset_internal(&host_set, &set);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
+ do_sigprocmask(SIG_SETMASK, &host_set, NULL);
if (err)
goto segv_and_exit;
@@ -2567,7 +2577,7 @@ void sparc64_set_context(CPUSPARCState *env)
goto do_sigsegv;
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
}
env->pc = pc;
env->npc = npc;
@@ -2656,7 +2666,7 @@ void sparc64_get_context(CPUSPARCState *env)
err = 0;
- sigprocmask(0, NULL, &set);
+ do_sigprocmask(0, NULL, &set);
host_to_target_sigset_internal(&target_set, &set);
if (TARGET_NSIG_WORDS == 1) {
err |= __put_user(target_set.sig[0],
@@ -2991,7 +3001,7 @@ long do_sigreturn(CPUMIPSState *regs)
}
target_to_host_sigset_internal(&blocked, &target_set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(regs, &frame->sf_sc))
goto badframe;
@@ -3095,7 +3105,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
goto badframe;
target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
goto badframe;
@@ -3385,7 +3395,7 @@ long do_sigreturn(CPUSH4State *regs)
goto badframe;
target_to_host_sigset_internal(&blocked, &target_set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(regs, &frame->sc, &r0))
goto badframe;
@@ -3414,7 +3424,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
goto badframe;
target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
goto badframe;
@@ -3644,7 +3654,7 @@ long do_sigreturn(CPUMBState *env)
goto badframe;
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
restore_sigcontext(&frame->uc.tuc_mcontext, env);
/* We got here through a sigreturn syscall, our path back is via an
@@ -3819,7 +3829,7 @@ long do_sigreturn(CPUCRISState *env)
goto badframe;
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
restore_sigcontext(&frame->sc, env);
unlock_user_struct(frame, frame_addr, 0);
@@ -4350,7 +4360,7 @@ long do_sigreturn(CPUS390XState *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+ do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
if (restore_sigregs(env, &frame->sregs)) {
goto badframe;
@@ -4378,7 +4388,7 @@ long do_rt_sigreturn(CPUS390XState *env)
}
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+ do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
goto badframe;
@@ -4906,7 +4916,7 @@ long do_sigreturn(CPUPPCState *env)
goto sigsegv;
#endif
target_to_host_sigset_internal(&blocked, &set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (__get_user(sr_addr, &sc->regs))
goto sigsegv;
@@ -4950,7 +4960,7 @@ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
return 1;
target_to_host_sigset_internal(&blocked, &set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
+ do_sigprocmask(SIG_SETMASK, &blocked, NULL);
if (restore_user_regs(env, mcp, sig))
goto sigsegv;
@@ -5324,7 +5334,7 @@ long do_sigreturn(CPUM68KState *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
@@ -5352,7 +5362,7 @@ long do_rt_sigreturn(CPUM68KState *env)
goto badframe;
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
@@ -5599,7 +5609,7 @@ long do_sigreturn(CPUAlphaState *env)
}
target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, sc)) {
goto badframe;
@@ -5622,7 +5632,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
goto badframe;
}
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
goto badframe;
@@ -5739,7 +5749,7 @@ void process_pending_signals(CPUArchState *cpu_env)
sigaddset(&set, target_to_host_signal(sig));
/* block signals in the handler using Linux */
- sigprocmask(SIG_BLOCK, &set, &old_set);
+ do_sigprocmask(SIG_BLOCK, &set, &old_set);
/* save the previous blocked signal state to restore it at the
end of the signal execution (see do_sigreturn) */
host_to_target_sigset_internal(&target_old_set, &old_set);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ffc11de..2a8b66c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5993,7 +5993,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
sigset_t cur_set;
abi_ulong target_set;
- sigprocmask(0, NULL, &cur_set);
+ do_sigprocmask(0, NULL, &cur_set);
host_to_target_old_sigset(&target_set, &cur_set);
ret = target_set;
}
@@ -6004,10 +6004,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
sigset_t set, oset, cur_set;
abi_ulong target_set = arg1;
- sigprocmask(0, NULL, &cur_set);
+ do_sigprocmask(0, NULL, &cur_set);
target_to_host_old_sigset(&set, &target_set);
sigorset(&set, &set, &cur_set);
- sigprocmask(SIG_SETMASK, &set, &oset);
+ do_sigprocmask(SIG_SETMASK, &set, &oset);
host_to_target_old_sigset(&target_set, &oset);
ret = target_set;
}
@@ -6038,7 +6038,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- ret = get_errno(sigprocmask(how, &set, &oldset));
+ ret = get_errno(do_sigprocmask(how, &set, &oldset));
if (!is_error(ret)) {
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
@@ -6072,7 +6072,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = 0;
set_ptr = NULL;
}
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+ ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
goto efault;
@@ -6112,7 +6112,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = 0;
set_ptr = NULL;
}
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+ ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
goto efault;
@@ -8125,7 +8125,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- sigprocmask(how, &set, &oldset);
+ do_sigprocmask(how, &set, &oldset);
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
}
--
1.9.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 2/2] linux-user: Don't allow guest to block SIGSEGV
2014-03-14 14:36 [Qemu-devel] [PATCH 0/2] linux-user: Don't allow guest to block SIGSEGV Peter Maydell
2014-03-14 14:36 ` [Qemu-devel] [PATCH 1/2] linux-user: Add wrapper for guest uses of sigprocmask function Peter Maydell
2014-03-14 14:36 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for " Peter Maydell
@ 2014-03-14 14:36 ` Peter Maydell
2 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2014-03-14 14:36 UTC (permalink / raw)
To: qemu-devel
Cc: Michael Matz, patches, Dann Frazier, Riku Voipio, Alexander Graf,
Alex Bennée
Don't allow the linux-user guest to block SIGSEGV -- QEMU needs this
signal to detect accesses to pages which it has marked read-only
because it has cached translated code from them.
We implement this by making the do_sigprocmask() wrapper suppress
SIGSEGV when doing the host process signal mask manipulation; instead
we store the current state of SIGSEGV in the TaskState struct.
If we get a SIGSEGV for the guest when the guest has blocked the
signal, we treat it as if the default SEGV handler was in place,
as the kernel does for forced SIGSEGV delivery.
This patch is based on an idea by Alex Barcelo, but rather than
simply lying to the guest about the SIGSEGV state we track it.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reported-by: Alex Barcelo <abarcelo@ac.upc.edu>
---
linux-user/qemu.h | 1 +
linux-user/signal.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 4d24e74..36d4a73 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -126,6 +126,7 @@ typedef struct TaskState {
#endif
uint32_t stack_base;
int used; /* non zero if used */
+ bool sigsegv_blocked; /* SIGSEGV blocked by guest */
struct image_info *info;
struct linux_binprm *bprm;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c8df584..f18f3d3 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -204,7 +204,46 @@ void target_to_host_old_sigset(sigset_t *sigset,
*/
int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
{
- return sigprocmask(how, set, oldset);
+ int ret;
+ sigset_t val;
+ sigset_t *temp = NULL;
+ CPUState *cpu = thread_cpu;
+ TaskState *ts = (TaskState *)cpu->opaque;
+ bool segv_was_blocked = ts->sigsegv_blocked;
+
+ if (set) {
+ bool has_sigsegv = sigismember(set, SIGSEGV);
+ val = *set;
+ temp = &val;
+
+ sigdelset(temp, SIGSEGV);
+
+ switch (how) {
+ case SIG_BLOCK:
+ if (has_sigsegv) {
+ ts->sigsegv_blocked = true;
+ }
+ break;
+ case SIG_UNBLOCK:
+ if (has_sigsegv) {
+ ts->sigsegv_blocked = false;
+ }
+ break;
+ case SIG_SETMASK:
+ ts->sigsegv_blocked = has_sigsegv;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ ret = sigprocmask(how, temp, oldset);
+
+ if (oldset && segv_was_blocked) {
+ sigaddset(oldset, SIGSEGV);
+ }
+
+ return ret;
}
/* siginfo conversion */
@@ -468,6 +507,19 @@ int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
k = &ts->sigtab[sig - 1];
queue = gdb_queuesig ();
handler = sigact_table[sig - 1]._sa_handler;
+
+ if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
+ /* Guest has blocked SIGSEGV but we got one anyway. Assume this
+ * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
+ * because it got a real MMU fault). A blocked SIGSEGV in that
+ * situation is treated as if using the default handler. This is
+ * not correct if some other process has randomly sent us a SIGSEGV
+ * via kill(), but that is not easy to distinguish at this point,
+ * so we assume it doesn't happen.
+ */
+ handler = TARGET_SIG_DFL;
+ }
+
if (!queue && handler == TARGET_SIG_DFL) {
if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
kill(getpid(),SIGSTOP);
@@ -5726,6 +5778,14 @@ void process_pending_signals(CPUArchState *cpu_env)
handler = sa->_sa_handler;
}
+ if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
+ /* Guest has blocked SIGSEGV but we got one anyway. Assume this
+ * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
+ * because it got a real MMU fault), and treat as if default handler.
+ */
+ handler = TARGET_SIG_DFL;
+ }
+
if (handler == TARGET_SIG_DFL) {
/* default handler : ignore some signal. The other are job control or fatal */
if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
--
1.9.0
^ permalink raw reply related [flat|nested] 4+ messages in thread