Nicholas Piggin <npig...@gmail.com> writes: > Excerpts from Nicholas Piggin's message of June 14, 2021 10:47 am: >> Excerpts from Michael Ellerman's message of June 8, 2021 11:46 pm: >>> In commit 96d7a4e06fab ("powerpc/signal64: Rewrite handle_rt_signal64() >>> to minimise uaccess switches") the 64-bit signal code was rearranged to >>> use user_write_access_begin/end(). >>> >>> As part of that change the call to copy_siginfo_to_user() was moved >>> later in the function, so that it could be done after the >>> user_write_access_end(). >>> >>> In particular it was moved after we modify regs->nip to point to the >>> signal trampoline. That means if copy_siginfo_to_user() fails we exit >>> handle_rt_signal64() with an error but with regs->nip modified, whereas >>> previously we would not modify regs->nip until the copy succeeded. >>> >>> Returning an error from signal delivery but with regs->nip updated >>> leaves the process in a sort of half-delivered state. We do immediately >>> force a SEGV in signal_setup_done(), called from do_signal(), so the >>> process should never run in the half-delivered state. >>> >>> However that SEGV is not delivered until we've gone around to >>> do_notify_resume() again, so it's possible some tracing could observe >>> the half-delivered state. >>> >>> There are other cases where we fail signal delivery with regs partly >>> updated, eg. the write to newsp and SA_SIGINFO, but the latter at least >>> is very unlikely to fail as it reads back from the frame we just wrote >>> to. >>> >>> Looking at other arches they seem to be more careful about leaving regs >>> unchanged until the copy operations have succeeded, and in general that >>> seems like good hygenie. >>> >>> So although the current behaviour is not cleary buggy, it's also not >>> clearly correct. So move the call to copy_siginfo_to_user() up prior to >>> the modification of regs->nip, which is closer to the old behaviour, and >>> easier to reason about. >> >> Good catch, should it still have a Fixes: tag though? Even if it's not >> clearly buggy we want it to be patched. > > Also... > >>> >>> Signed-off-by: Michael Ellerman <m...@ellerman.id.au> >>> --- >>> arch/powerpc/kernel/signal_64.c | 9 ++++----- >>> 1 file changed, 4 insertions(+), 5 deletions(-) >>> >>> diff --git a/arch/powerpc/kernel/signal_64.c >>> b/arch/powerpc/kernel/signal_64.c >>> index dca66481d0c2..f9e1f5428b9e 100644 >>> --- a/arch/powerpc/kernel/signal_64.c >>> +++ b/arch/powerpc/kernel/signal_64.c >>> @@ -902,6 +902,10 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t >>> *set, >>> unsafe_copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set), >>> badframe_block); >>> user_write_access_end(); >>> >>> + /* Save the siginfo outside of the unsafe block. */ >>> + if (copy_siginfo_to_user(&frame->info, &ksig->info)) >>> + goto badframe; >>> + >>> /* Make sure signal handler doesn't get spurious FP exceptions */ >>> tsk->thread.fp_state.fpscr = 0; >>> >>> @@ -915,11 +919,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t >>> *set, >>> regs->nip = (unsigned long) &frame->tramp[0]; >>> } >>> >>> - >>> - /* Save the siginfo outside of the unsafe block. */ >>> - if (copy_siginfo_to_user(&frame->info, &ksig->info)) >>> - goto badframe; >>> - >>> /* Allocate a dummy caller frame for the signal handler. */ >>> newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; >>> err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); > > Does the same reasoning apply to this one and the ELF V1 function > descriptor thing? It seems like you could move all of that block > up instead. With your other SA_SIGINFO get_user patch, there would > then be no possibility of error after you start modifying regs.
Yeah I think we should rework it further and eventually get to the point were we leave regs untouched until we're guaranteed to return success. It will need a bit more work though because of copy_siginfo_to_user(). cheers