diff options
author | Shi Weihua <shiwh@cn.fujitsu.com> | 2008-02-19 02:25:09 (GMT) |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2008-03-04 22:10:59 (GMT) |
commit | d7a6c68a2f991b18e61ebfe0251ab42c054d9a1d (patch) | |
tree | 8d4a949d0852656ed54e0610d6a316987117be71 /arch/ia64/kernel/signal.c | |
parent | bd3be240cb4e513c3d5e7d773ab9a8ce646befbd (diff) | |
download | linux-fsl-qoriq-d7a6c68a2f991b18e61ebfe0251ab42c054d9a1d.tar.xz |
[IA64] signal(ia64): add a signal stack overflow check
The similar check has been added to x86_32(i386) in commit
id 83bd01024b1fdfc41d9b758e5669e80fca72df66.
So we add this check to ia64 and improve it a liitle bit in that
we need to check for stack overflow only when the signal is on stack.
Signed-off-by: Shi Weihua <shiwh@cn.fujitsu.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/kernel/signal.c')
-rw-r--r-- | arch/ia64/kernel/signal.c | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 309da35..5740296 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -342,15 +342,33 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, new_sp = scr->pt.r12; tramp_addr = (unsigned long) __kernel_sigtramp; - if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(new_sp) == 0) { - new_sp = current->sas_ss_sp + current->sas_ss_size; - /* - * We need to check for the register stack being on the signal stack - * separately, because it's switched separately (memory stack is switched - * in the kernel, register stack is switched in the signal trampoline). - */ - if (!rbs_on_sig_stack(scr->pt.ar_bspstore)) - new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); + if (ka->sa.sa_flags & SA_ONSTACK) { + int onstack = sas_ss_flags(new_sp); + + if (onstack == 0) { + new_sp = current->sas_ss_sp + current->sas_ss_size; + /* + * We need to check for the register stack being on the + * signal stack separately, because it's switched + * separately (memory stack is switched in the kernel, + * register stack is switched in the signal trampoline). + */ + if (!rbs_on_sig_stack(scr->pt.ar_bspstore)) + new_rbs = ALIGN(current->sas_ss_sp, + sizeof(long)); + } else if (onstack == SS_ONSTACK) { + unsigned long check_sp; + + /* + * If we are on the alternate signal stack and would + * overflow it, don't. Return an always-bogus address + * instead so we will die with SIGSEGV. + */ + check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN; + if (!likely(on_sig_stack(check_sp))) + return force_sigsegv_info(sig, (void __user *) + check_sp); + } } frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN); |