mirror of https://gitee.com/openkylin/linux.git
powerpc/signal64: Copy siginfo before changing regs->nip
In commit96d7a4e06f
("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. Fixes:96d7a4e06f
("powerpc/signal64: Rewrite handle_rt_signal64() to minimise uaccess switches") Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210608134605.2783677-1-mpe@ellerman.id.au
This commit is contained in:
parent
8e11d62e2e
commit
e41d6c3f4f
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue