Excerpts from Christophe Leroy's message of June 14, 2021 5:22 pm: > > > Le 14/06/2021 à 07:55, Nicholas Piggin a écrit : >> Excerpts from Christophe Leroy's message of June 14, 2021 3:31 pm: >>> >>> >>> Le 14/06/2021 à 03:29, Nicholas Piggin a écrit : >>>> 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. >>>> >>> >>> To move the above in the user access block, we need to open a larger >>> window. At the time being the >>> window opened only contains the 'frame'. 'newsp' points before the 'frame'. >>> >> >> Only by 64/128 bytes though. Is that a problem? Not for 64s. Could it >> cause more overhead than it saves on other platforms? > > No it is not a problem at all, just need to not be forgotten, on ppc64 it may > go unnoticed, on 32s > it will blew up if we forget to enlarge the access window and the access > involves a different 256M > segment (Very unlikely for sure but ...)
Okay, and it's a good point. Would be nice if there was some sanitizer that could check this to byte granularity. Thanks, Nick >> For protection, it looks like all the important control data is in the >> signal frame anyway, this frame is just for stack unwinding? > > That's my understanding as well.