Skip to content

Commit a3b4647

Browse files
kevin-brodsky-armctmarinas
authored andcommitted
arm64: signal: Ensure signal delivery failure is recoverable
Commit eaf62ce ("arm64/signal: Set up and restore the GCS context for signal handlers") introduced a potential failure point at the end of setup_return(). This is unfortunate as it is too late to deliver a SIGSEGV: if that SIGSEGV is handled, the subsequent sigreturn will end up returning to the original handler, which is not the intention (since we failed to deliver that signal). Make sure this does not happen by calling gcs_signal_entry() at the very beginning of setup_return(), and add a comment just after to discourage error cases being introduced from that point onwards. While at it, also take care of copy_siginfo_to_user(): since it may fail, we shouldn't be calling it after setup_return() either. Call it before setup_return() instead, and move the setting of X1/X2 inside setup_return() where it belongs (after the "point of no failure"). Background: the first part of setup_rt_frame(), including setup_sigframe(), has no impact on the execution of the interrupted thread. The signal frame is written to the stack, but the stack pointer remains unchanged. Failure at this stage can be recovered by a SIGSEGV handler, and sigreturn will restore the original context, at the point where the original signal occurred. On the other hand, once setup_return() has updated registers including SP, the thread's control flow has been modified and we must deliver the original signal. Fixes: eaf62ce ("arm64/signal: Set up and restore the GCS context for signal handlers") Signed-off-by: Kevin Brodsky <[email protected]> Reviewed-by: Dave Martin <[email protected]> Reviewed-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 65ac33b commit a3b4647

File tree

1 file changed

+33
-15
lines changed

1 file changed

+33
-15
lines changed

arch/arm64/kernel/signal.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,10 +1462,33 @@ static int setup_return(struct pt_regs *regs, struct ksignal *ksig,
14621462
struct rt_sigframe_user_layout *user, int usig)
14631463
{
14641464
__sigrestore_t sigtramp;
1465+
int err;
1466+
1467+
if (ksig->ka.sa.sa_flags & SA_RESTORER)
1468+
sigtramp = ksig->ka.sa.sa_restorer;
1469+
else
1470+
sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
1471+
1472+
err = gcs_signal_entry(sigtramp, ksig);
1473+
if (err)
1474+
return err;
1475+
1476+
/*
1477+
* We must not fail from this point onwards. We are going to update
1478+
* registers, including SP, in order to invoke the signal handler. If
1479+
* we failed and attempted to deliver a nested SIGSEGV to a handler
1480+
* after that point, the subsequent sigreturn would end up restoring
1481+
* the (partial) state for the original signal handler.
1482+
*/
14651483

14661484
regs->regs[0] = usig;
1485+
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
1486+
regs->regs[1] = (unsigned long)&user->sigframe->info;
1487+
regs->regs[2] = (unsigned long)&user->sigframe->uc;
1488+
}
14671489
regs->sp = (unsigned long)user->sigframe;
14681490
regs->regs[29] = (unsigned long)&user->next_frame->fp;
1491+
regs->regs[30] = (unsigned long)sigtramp;
14691492
regs->pc = (unsigned long)ksig->ka.sa.sa_handler;
14701493

14711494
/*
@@ -1506,14 +1529,7 @@ static int setup_return(struct pt_regs *regs, struct ksignal *ksig,
15061529
sme_smstop();
15071530
}
15081531

1509-
if (ksig->ka.sa.sa_flags & SA_RESTORER)
1510-
sigtramp = ksig->ka.sa.sa_restorer;
1511-
else
1512-
sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
1513-
1514-
regs->regs[30] = (unsigned long)sigtramp;
1515-
1516-
return gcs_signal_entry(sigtramp, ksig);
1532+
return 0;
15171533
}
15181534

15191535
static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
@@ -1537,14 +1553,16 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
15371553

15381554
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
15391555
err |= setup_sigframe(&user, regs, set, &ua_state);
1540-
if (err == 0) {
1556+
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
1557+
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
1558+
1559+
if (err == 0)
15411560
err = setup_return(regs, ksig, &user, usig);
1542-
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
1543-
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
1544-
regs->regs[1] = (unsigned long)&frame->info;
1545-
regs->regs[2] = (unsigned long)&frame->uc;
1546-
}
1547-
}
1561+
1562+
/*
1563+
* We must not fail if setup_return() succeeded - see comment at the
1564+
* beginning of setup_return().
1565+
*/
15481566

15491567
if (err == 0)
15501568
set_handler_user_access_state();

0 commit comments

Comments
 (0)