Message ID | 20220125012947.14974-36-imp@bsdimp.com |
---|---|
State | New |
Headers | show |
Series | bsd-user: upstream our signal implementation | expand |
> On Jan 24, 2022, at 6:29 PM, Warner Losh <imp@bsdimp.com> wrote: > > Implements the meat of a sigreturn(2) system call via do_sigreturn, and > helper reset_signal_mask. Fix the prototype of do_sigreturn in qemu.h > and remove do_rt_sigreturn since it's linux only. > > Signed-off-by: Stacey Son <sson@FreeBSD.org> > Signed-off-by: Kyle Evans <kevans@freebsd.org> > Signed-off-by: Warner Losh <imp@bsdimp.com> > > PENDING COMMENTS: from Peter Maydell <peter.maydell@linaro.org> > > do_sigreturn() itself shouldn't be setting the active signal > mask, at least if you follow the linux-user design. It just > sets the thread's signal_mask field in the TaskState by > calling set_sigmask(), and then on our way out in the > main cpu loop we'll call process_pending_signals() which > sets the real thread signal mask to that value. (This, together > with do_sigreturn() calling block_signals() before it starts > work, avoids some race conditions where a host signal is delivered > as soon as we unblock, I think.) I think this is correct. We’re already setting the signal_mask element in a mostly similar way to linux-user, so all I need to do is to remove the setting the actual signal mask. The rest of this is already in place. I’ll included in v3. Warner > --- > bsd-user/signal-common.h | 2 +- > bsd-user/signal.c | 56 ++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 57 insertions(+), 1 deletion(-) > > diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h > index ee819266f54..786ec592d18 100644 > --- a/bsd-user/signal-common.h > +++ b/bsd-user/signal-common.h > @@ -11,7 +11,7 @@ > > long do_rt_sigreturn(CPUArchState *env); > abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); > -long do_sigreturn(CPUArchState *env); > +long do_sigreturn(CPUArchState *env, abi_ulong addr); > void force_sig_fault(int sig, int code, abi_ulong addr); > int host_to_target_signal(int sig); > void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); > diff --git a/bsd-user/signal.c b/bsd-user/signal.c > index 9ec4354d232..05caf812ccb 100644 > --- a/bsd-user/signal.c > +++ b/bsd-user/signal.c > @@ -626,6 +626,62 @@ static void setup_frame(int sig, int code, struct target_sigaction *ka, > unlock_user_struct(frame, frame_addr, 1); > } > > +static int reset_signal_mask(target_ucontext_t *ucontext) > +{ > + int i; > + sigset_t blocked; > + target_sigset_t target_set; > + TaskState *ts = (TaskState *)thread_cpu->opaque; > + > + for (i = 0; i < TARGET_NSIG_WORDS; i++) > + if (__get_user(target_set.__bits[i], > + &ucontext->uc_sigmask.__bits[i])) { > + return -TARGET_EFAULT; > + } > + target_to_host_sigset_internal(&blocked, &target_set); > + ts->signal_mask = blocked; > + sigprocmask(SIG_SETMASK, &ts->signal_mask, NULL); > + > + return 0; > +} > + > +/* See sys/$M/$M/exec_machdep.c sigreturn() */ > +long do_sigreturn(CPUArchState *env, abi_ulong addr) > +{ > + long ret; > + abi_ulong target_ucontext; > + target_ucontext_t *ucontext = NULL; > + > + /* Get the target ucontext address from the stack frame */ > + ret = get_ucontext_sigreturn(env, addr, &target_ucontext); > + if (is_error(ret)) { > + return ret; > + } > + trace_user_do_sigreturn(env, addr); > + if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) { > + goto badframe; > + } > + > + /* Set the register state back to before the signal. */ > + if (set_mcontext(env, &ucontext->uc_mcontext, 1)) { > + goto badframe; > + } > + > + /* And reset the signal mask. */ > + if (reset_signal_mask(ucontext)) { > + goto badframe; > + } > + > + unlock_user_struct(ucontext, target_ucontext, 0); > + return -TARGET_EJUSTRETURN; > + > +badframe: > + if (ucontext != NULL) { > + unlock_user_struct(ucontext, target_ucontext, 0); > + } > + return -TARGET_EFAULT; > +} > + > void signal_init(void) > { > TaskState *ts = (TaskState *)thread_cpu->opaque; > -- > 2.33.1 >
diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h index ee819266f54..786ec592d18 100644 --- a/bsd-user/signal-common.h +++ b/bsd-user/signal-common.h @@ -11,7 +11,7 @@ long do_rt_sigreturn(CPUArchState *env); abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); -long do_sigreturn(CPUArchState *env); +long do_sigreturn(CPUArchState *env, abi_ulong addr); void force_sig_fault(int sig, int code, abi_ulong addr); int host_to_target_signal(int sig); void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 9ec4354d232..05caf812ccb 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -626,6 +626,62 @@ static void setup_frame(int sig, int code, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); } +static int reset_signal_mask(target_ucontext_t *ucontext) +{ + int i; + sigset_t blocked; + target_sigset_t target_set; + TaskState *ts = (TaskState *)thread_cpu->opaque; + + for (i = 0; i < TARGET_NSIG_WORDS; i++) + if (__get_user(target_set.__bits[i], + &ucontext->uc_sigmask.__bits[i])) { + return -TARGET_EFAULT; + } + target_to_host_sigset_internal(&blocked, &target_set); + ts->signal_mask = blocked; + sigprocmask(SIG_SETMASK, &ts->signal_mask, NULL); + + return 0; +} + +/* See sys/$M/$M/exec_machdep.c sigreturn() */ +long do_sigreturn(CPUArchState *env, abi_ulong addr) +{ + long ret; + abi_ulong target_ucontext; + target_ucontext_t *ucontext = NULL; + + /* Get the target ucontext address from the stack frame */ + ret = get_ucontext_sigreturn(env, addr, &target_ucontext); + if (is_error(ret)) { + return ret; + } + trace_user_do_sigreturn(env, addr); + if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) { + goto badframe; + } + + /* Set the register state back to before the signal. */ + if (set_mcontext(env, &ucontext->uc_mcontext, 1)) { + goto badframe; + } + + /* And reset the signal mask. */ + if (reset_signal_mask(ucontext)) { + goto badframe; + } + + unlock_user_struct(ucontext, target_ucontext, 0); + return -TARGET_EJUSTRETURN; + +badframe: + if (ucontext != NULL) { + unlock_user_struct(ucontext, target_ucontext, 0); + } + return -TARGET_EFAULT; +} + void signal_init(void) { TaskState *ts = (TaskState *)thread_cpu->opaque;