* [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user @ 2012-09-29 16:11 Alex Barcelo 2012-09-29 16:11 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function Alex Barcelo ` (2 more replies) 0 siblings, 3 replies; 9+ messages in thread From: Alex Barcelo @ 2012-09-29 16:11 UTC (permalink / raw) To: qemu-devel; +Cc: Riku Voipio, Alex Barcelo The first patch creates a sigprocmask wrapper on signal.c for its use in syscall.c The second patch changes the wrapper to protect sigsegv bit on the signal mask. Alex Barcelo (2): signal: added a wrapper for sigprocmask function signal: sigsegv protection on do_sigprocmask linux-user/qemu.h | 1 + linux-user/signal.c | 15 +++++++++++++++ linux-user/syscall.c | 20 ++++++++++---------- 3 files changed, 26 insertions(+), 10 deletions(-) -- 1.7.5.4 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function 2012-09-29 16:11 [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo @ 2012-09-29 16:11 ` Alex Barcelo 2012-10-10 15:48 ` Peter Maydell 2012-09-29 16:11 ` [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask Alex Barcelo 2012-10-08 18:42 ` [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo 2 siblings, 1 reply; 9+ messages in thread From: Alex Barcelo @ 2012-09-29 16:11 UTC (permalink / raw) To: qemu-devel; +Cc: Riku Voipio, Alex Barcelo A transparent wrapper for sigprocmask function. --- linux-user/qemu.h | 1 + linux-user/signal.c | 8 ++++++++ linux-user/syscall.c | 20 ++++++++++---------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index fc4cc00..e2dd6a6 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -237,6 +237,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 7869147..b8b8268 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -5463,6 +5463,14 @@ long do_rt_sigreturn(CPUArchState *env) #endif +/* Wrapper for sigprocmask function + * Emulates a sigprocmask in a safe way for the guest + */ +int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) +{ + return sigprocmask(how, set, oldset); +} + void process_pending_signals(CPUArchState *cpu_env) { int sig; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 471d060..1117bbe 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4260,7 +4260,7 @@ static void *clone_func(void *arg) if (info->parent_tidptr) put_user_u32(info->tid, info->parent_tidptr); /* Enable signals. */ - sigprocmask(SIG_SETMASK, &info->sigmask, NULL); + do_sigprocmask(SIG_SETMASK, &info->sigmask, NULL); /* Signal to the parent that we're ready. */ pthread_mutex_lock(&info->mutex); pthread_cond_broadcast(&info->cond); @@ -4351,12 +4351,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, /* It is not safe to deliver signals until the child has finished initializing, so temporarily block all signals. */ sigfillset(&sigmask); - sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); + do_sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); ret = pthread_create(&info.thread, &attr, clone_func, &info); /* TODO: Free new CPU state if thread creation failed. */ - sigprocmask(SIG_SETMASK, &info.sigmask, NULL); + do_sigprocmask(SIG_SETMASK, &info.sigmask, NULL); pthread_attr_destroy(&attr); if (ret == 0) { /* Wait for the child to initialize. */ @@ -5875,7 +5875,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; } @@ -5886,10 +5886,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; } @@ -5920,7 +5920,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; @@ -5954,7 +5954,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; @@ -5994,7 +5994,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; @@ -7870,7 +7870,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.7.5.4 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function 2012-09-29 16:11 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function Alex Barcelo @ 2012-10-10 15:48 ` Peter Maydell 0 siblings, 0 replies; 9+ messages in thread From: Peter Maydell @ 2012-10-10 15:48 UTC (permalink / raw) To: Alex Barcelo; +Cc: Riku Voipio, qemu-devel On 29 September 2012 17:11, Alex Barcelo <abarcelo@ac.upc.edu> wrote: Hi; thanks for this patch. > A transparent wrapper for sigprocmask function. As I mentioned in my reply to the cover letter, this needs a Signed-off-by: line. The commit message could also be a bit more verbose, for instance something like: Create a wrapper for signal mask changes initiated by the guest; this will give us a place to put code which prevents the guest from changing the handling of signals used by QEMU itself internally. (To some extent this is a personal style thing, but I tend to favour fairly verbose commentary and commit messages rather than terseness.) > > --- > linux-user/qemu.h | 1 + > linux-user/signal.c | 8 ++++++++ > linux-user/syscall.c | 20 ++++++++++---------- > 3 files changed, 19 insertions(+), 10 deletions(-) > > diff --git a/linux-user/qemu.h b/linux-user/qemu.h > index fc4cc00..e2dd6a6 100644 > --- a/linux-user/qemu.h > +++ b/linux-user/qemu.h > @@ -237,6 +237,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 7869147..b8b8268 100644 > --- a/linux-user/signal.c > +++ b/linux-user/signal.c > @@ -5463,6 +5463,14 @@ long do_rt_sigreturn(CPUArchState *env) > > #endif > > +/* Wrapper for sigprocmask function > + * Emulates a sigprocmask in a safe way for the guest You might like to add: * Note that set and oldset are host signal sets, not guest ones. > + */ > +int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) > +{ > + return sigprocmask(how, set, oldset); > +} > + > void process_pending_signals(CPUArchState *cpu_env) > { > int sig; > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 471d060..1117bbe 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -4260,7 +4260,7 @@ static void *clone_func(void *arg) > if (info->parent_tidptr) > put_user_u32(info->tid, info->parent_tidptr); > /* Enable signals. */ > - sigprocmask(SIG_SETMASK, &info->sigmask, NULL); > + do_sigprocmask(SIG_SETMASK, &info->sigmask, NULL); > /* Signal to the parent that we're ready. */ > pthread_mutex_lock(&info->mutex); > pthread_cond_broadcast(&info->cond); > @@ -4351,12 +4351,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, > /* It is not safe to deliver signals until the child has finished > initializing, so temporarily block all signals. */ > sigfillset(&sigmask); > - sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); > + do_sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); > > ret = pthread_create(&info.thread, &attr, clone_func, &info); > /* TODO: Free new CPU state if thread creation failed. */ > > - sigprocmask(SIG_SETMASK, &info.sigmask, NULL); > + do_sigprocmask(SIG_SETMASK, &info.sigmask, NULL); > pthread_attr_destroy(&attr); > if (ret == 0) { > /* Wait for the child to initialize. */ The three sigprocmask() calls above are all QEMU itself manipulating its own signal mask (to block signals temporarily across a thread creation). They're not the guest asking for a signal mask change. So these three can all just use sigprocmask() and shouldn't go via do_sigprocmask() I think. > @@ -5875,7 +5875,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; > } > @@ -5886,10 +5886,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; > } > @@ -5920,7 +5920,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; > @@ -5954,7 +5954,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; > @@ -5994,7 +5994,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; > @@ -7870,7 +7870,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; > } I think all the uses of sigprocmask() in linux-user/signal.c also need to be do_sigprocmask(), as they are the guest trying to control its signal mask (via the mask it specifies for running signal handlers, or the mask it passes back when restoring context on return from a signal handler). -- PMM ^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask 2012-09-29 16:11 [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo 2012-09-29 16:11 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function Alex Barcelo @ 2012-09-29 16:11 ` Alex Barcelo 2012-10-10 15:54 ` Peter Maydell 2012-10-08 18:42 ` [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo 2 siblings, 1 reply; 9+ messages in thread From: Alex Barcelo @ 2012-09-29 16:11 UTC (permalink / raw) To: qemu-devel; +Cc: Riku Voipio, Alex Barcelo The sigsegv protection is done by forcing the catch (needed in qemu-user) and then taking it off from the return mask (well, adding it in fact) --- linux-user/signal.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index b8b8268..8764f57 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -5468,7 +5468,14 @@ long do_rt_sigreturn(CPUArchState *env) */ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { - return sigprocmask(how, set, oldset); + int ret; + sigset_t temp = *set; + if (set) { + sigdelset(&temp, SIGSEGV); + } + ret = sigprocmask(how, &temp, oldset); + sigaddset(oldset, SIGSEGV); + return ret; } void process_pending_signals(CPUArchState *cpu_env) -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask 2012-09-29 16:11 ` [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask Alex Barcelo @ 2012-10-10 15:54 ` Peter Maydell 0 siblings, 0 replies; 9+ messages in thread From: Peter Maydell @ 2012-10-10 15:54 UTC (permalink / raw) To: Alex Barcelo; +Cc: Riku Voipio, qemu-devel On 29 September 2012 17:11, Alex Barcelo <abarcelo@ac.upc.edu> wrote: > Re: [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask The convention for the initial summary line of a patch is that it starts with an indication of the subsystem being patched. For instance, here it might be: "linux-user: Don't allow guest to block SIGSEGV" > The sigsegv protection is done by forcing the catch (needed in qemu-user) > and then taking it off from the return mask (well, adding it in fact) I'm afraid I couldn't really understand what you're trying to say in this commit message. Perhaps you could expand it a bit? (missing Signed-off-by:.) > > --- > linux-user/signal.c | 9 ++++++++- > 1 files changed, 8 insertions(+), 1 deletions(-) > > diff --git a/linux-user/signal.c b/linux-user/signal.c > index b8b8268..8764f57 100644 > --- a/linux-user/signal.c > +++ b/linux-user/signal.c > @@ -5468,7 +5468,14 @@ long do_rt_sigreturn(CPUArchState *env) > */ > int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) > { > - return sigprocmask(how, set, oldset); > + int ret; > + sigset_t temp = *set; This is dereferencing set, which will crash if it is NULL. > + if (set) { > + sigdelset(&temp, SIGSEGV); > + } > + ret = sigprocmask(how, &temp, oldset); You need to pass NULL in here rather than &temp if the 'set' argument was NULL. > + sigaddset(oldset, SIGSEGV); > + return ret; > } So, we don't permit the guest to block SIGSEGV; that makes sense. Does it make sense to always tell the guest SIGSEGV is blocked? (what this patch currently does). The other options would be "tell the guest SIGSEGV is never blocked" and "actually maintain somewhere the state of whether the guest thinks SIGSEGV is blocked so we can return the right answer". I'm just wondering which would be generally better for guests and why you picked this approach rather than one of the other options. (it might be the best, I haven't thought too hard about it...) thanks -- PMM ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user 2012-09-29 16:11 [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo 2012-09-29 16:11 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function Alex Barcelo 2012-09-29 16:11 ` [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask Alex Barcelo @ 2012-10-08 18:42 ` Alex Barcelo 2012-10-10 15:37 ` Peter Maydell 2 siblings, 1 reply; 9+ messages in thread From: Alex Barcelo @ 2012-10-08 18:42 UTC (permalink / raw) To: qemu-devel; +Cc: Riku Voipio, Alex Barcelo okay, now I see that this lacks a lot of "presentation". This is a patch to fix a problem on signal masks, and solves a certain problem when the client is "playing the game" of sigsegv mask/unmask. I will explain it a little more on a better patch. This should have been explained on the 00/00 cover. And, moreover, this is kinda the v2 of a single-mail patch. Before sending a v2, is there something more that I should correct? And one netiquete question, test-breaking code should be in the description (cover, 00/00)? On a next post in the same thread? Another thread? On Sat, Sep 29, 2012 at 6:11 PM, Alex Barcelo <abarcelo@ac.upc.edu> wrote: > The first patch creates a sigprocmask wrapper on signal.c for its use in syscall.c > > The second patch changes the wrapper to protect sigsegv bit on the signal mask. > > Alex Barcelo (2): > signal: added a wrapper for sigprocmask function > signal: sigsegv protection on do_sigprocmask > > linux-user/qemu.h | 1 + > linux-user/signal.c | 15 +++++++++++++++ > linux-user/syscall.c | 20 ++++++++++---------- > 3 files changed, 26 insertions(+), 10 deletions(-) > > -- > 1.7.5.4 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user 2012-10-08 18:42 ` [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo @ 2012-10-10 15:37 ` Peter Maydell 2012-10-17 14:22 ` Alex Barcelo 0 siblings, 1 reply; 9+ messages in thread From: Peter Maydell @ 2012-10-10 15:37 UTC (permalink / raw) To: Alex Barcelo; +Cc: Riku Voipio, qemu-devel On 8 October 2012 19:42, Alex Barcelo <abarcelo@ac.upc.edu> wrote: > okay, now I see that this lacks a lot of "presentation". > Before sending a v2, is there something more that I should correct? Well, yes, your cover letter could be a little more verbose, but I think mostly it's just that nobody's got round to reviewing the patches yet. I'll have a look at them in a moment. One thing that is definitely missing and is critical is that you need to include a Signed-off-by: line in your patches' commit messages: we cannot commit them without one. (http://wiki.qemu.org/Contribute/SubmitAPatch mentions this and has some other hints, if you haven't read it.) > And one netiquete question, test-breaking code should be in the > description (cover, 00/00)? On a next post in the same thread? Another > thread? In the cover letter is fine. -- PMM ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user 2012-10-10 15:37 ` Peter Maydell @ 2012-10-17 14:22 ` Alex Barcelo 0 siblings, 0 replies; 9+ messages in thread From: Alex Barcelo @ 2012-10-17 14:22 UTC (permalink / raw) To: Peter Maydell; +Cc: Riku Voipio, qemu-devel Thanks Peter for all the feedback! I have just sent the v2 (have been on holiday this weekend, a bit offline). I hope that this one is a better patch. Sorry Riku, I have doubleposted the new patch to you, I slipped on the git send-email command, and sent the patch only to you at first (not to the list). I corrected it but now you may have received twice. Next time I will double check my git output :( On Wed, Oct 10, 2012 at 5:37 PM, Peter Maydell <peter.maydell@linaro.org> wrote: > On 8 October 2012 19:42, Alex Barcelo <abarcelo@ac.upc.edu> wrote: >> okay, now I see that this lacks a lot of "presentation". > >> Before sending a v2, is there something more that I should correct? > > Well, yes, your cover letter could be a little more verbose, but I > think mostly it's just that nobody's got round to reviewing the > patches yet. I'll have a look at them in a moment. > > One thing that is definitely missing and is critical is that > you need to include a Signed-off-by: line in your patches' > commit messages: we cannot commit them without one. > (http://wiki.qemu.org/Contribute/SubmitAPatch mentions this and > has some other hints, if you haven't read it.) > >> And one netiquete question, test-breaking code should be in the >> description (cover, 00/00)? On a next post in the same thread? Another >> thread? > > In the cover letter is fine. > > -- PMM ^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 0/2] linux-user: Don't allow guest to block SIGSEGV @ 2014-03-14 14:36 Peter Maydell 2014-03-14 14:36 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function Peter Maydell 0 siblings, 1 reply; 9+ 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 QEMU uses SIGSEGV for its own purposes (notably for detection of guest writes to pages marked read-only because we have cached translated code from them), so allowing the guest to block SIGSEGV is a bad idea. Instead we wrap sigprocmask() uses for guest-derived signal masks and just track whether the guest thinks SIGSEGV is blocked rather than really blocking it. This is an updated version of a patchset sent by Alex Barcelo a year or so ago; changes are: * use the wrapper for sigprocmask uses in signal.c where we set the signal mask on entry and exit from a guest signal handler * rather than just dropping SIGSEGV from the signal mask, track the guest state in a TaskState flag Although the need for this patchset is more noticable with AArch64 guests (because at the moment we use trampoline code on the stack for handling return from signal, which means that pages in the stack are often marked read-only because we translate the trampoline code and then written to in the normal course of guest execution) it is generally applicable to all architectures. [Eventually we should implement emulation of the vdso for AArch64, at which point we can put the signal-return trampoline in that, as the real kernel does; then there will be less of these SEGVs.] Alex Barcelo (1): linux-user: Add wrapper for guest uses of sigprocmask function Peter Maydell (1): linux-user: Don't allow guest to block SIGSEGV linux-user/qemu.h | 2 + linux-user/signal.c | 118 ++++++++++++++++++++++++++++++++++++++++----------- linux-user/syscall.c | 14 +++--- 3 files changed, 103 insertions(+), 31 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 9+ 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 ` Peter Maydell 0 siblings, 0 replies; 9+ 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] 9+ messages in thread
end of thread, other threads:[~2014-03-14 14:37 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-09-29 16:11 [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo 2012-09-29 16:11 ` [Qemu-devel] [PATCH 1/2] signal: added a wrapper for sigprocmask function Alex Barcelo 2012-10-10 15:48 ` Peter Maydell 2012-09-29 16:11 ` [Qemu-devel] [PATCH 2/2] signal: sigsegv protection on do_sigprocmask Alex Barcelo 2012-10-10 15:54 ` Peter Maydell 2012-10-08 18:42 ` [Qemu-devel] [PATCH 0/2] signal: Preparing safe sigprocmask wrapper on qemu-user Alex Barcelo 2012-10-10 15:37 ` Peter Maydell 2012-10-17 14:22 ` Alex Barcelo 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] signal: added a wrapper for sigprocmask function Peter Maydell
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.