sparc64: Make corrupted user stacks more debuggable.
Right now if we get a corrupted user stack frame we do a do_exit(SIGILL) which is not helpful. If under a debugger, this behavior causes the inferior process to exit. So the register and other state cannot be examined at the time of the event. Instead, conditionally log a rate limited kernel log message and then force a SIGSEGV. With bits and ideas borrowed (as usual) from powerpc. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
caf539cd10
commit
5b4fc3882a
|
@ -67,6 +67,7 @@ do { save_and_clear_fpu(); \
|
|||
} while(0)
|
||||
|
||||
void synchronize_user_stack(void);
|
||||
void fault_in_user_windows(void);
|
||||
struct pt_regs;
|
||||
void fault_in_user_windows(struct pt_regs *);
|
||||
|
||||
#endif /* __SPARC64_SWITCH_TO_64_H */
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/sysrq.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
|
@ -521,7 +522,12 @@ static void stack_unaligned(unsigned long sp)
|
|||
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *) sp, 0, current);
|
||||
}
|
||||
|
||||
void fault_in_user_windows(void)
|
||||
static const char uwfault32[] = KERN_INFO \
|
||||
"%s[%d]: bad register window fault: SP %08lx (orig_sp %08lx) TPC %08lx O7 %08lx\n";
|
||||
static const char uwfault64[] = KERN_INFO \
|
||||
"%s[%d]: bad register window fault: SP %016lx (orig_sp %016lx) TPC %08lx O7 %016lx\n";
|
||||
|
||||
void fault_in_user_windows(struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *t = current_thread_info();
|
||||
unsigned long window;
|
||||
|
@ -534,9 +540,9 @@ void fault_in_user_windows(void)
|
|||
do {
|
||||
struct reg_window *rwin = &t->reg_window[window];
|
||||
int winsize = sizeof(struct reg_window);
|
||||
unsigned long sp;
|
||||
unsigned long sp, orig_sp;
|
||||
|
||||
sp = t->rwbuf_stkptrs[window];
|
||||
orig_sp = sp = t->rwbuf_stkptrs[window];
|
||||
|
||||
if (test_thread_64bit_stack(sp))
|
||||
sp += STACK_BIAS;
|
||||
|
@ -547,8 +553,16 @@ void fault_in_user_windows(void)
|
|||
stack_unaligned(sp);
|
||||
|
||||
if (unlikely(copy_to_user((char __user *)sp,
|
||||
rwin, winsize)))
|
||||
rwin, winsize))) {
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(is_compat_task() ?
|
||||
uwfault32 : uwfault64,
|
||||
current->comm, current->pid,
|
||||
sp, orig_sp,
|
||||
regs->tpc,
|
||||
regs->u_regs[UREG_I7]);
|
||||
goto barf;
|
||||
}
|
||||
} while (window--);
|
||||
}
|
||||
set_thread_wsaved(0);
|
||||
|
@ -556,8 +570,7 @@ void fault_in_user_windows(void)
|
|||
|
||||
barf:
|
||||
set_thread_wsaved(window + 1);
|
||||
user_exit();
|
||||
do_exit(SIGILL);
|
||||
force_sig(SIGSEGV, current);
|
||||
}
|
||||
|
||||
asmlinkage long sparc_do_fork(unsigned long clone_flags,
|
||||
|
|
|
@ -39,6 +39,7 @@ __handle_preemption:
|
|||
wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
|
||||
|
||||
__handle_user_windows:
|
||||
add %sp, PTREGS_OFF, %o0
|
||||
call fault_in_user_windows
|
||||
661: wrpr %g0, RTRAP_PSTATE, %pstate
|
||||
/* If userspace is using ADI, it could potentially pass
|
||||
|
|
|
@ -371,7 +371,11 @@ static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs,
|
|||
get_sigframe(ksig, regs, sigframe_size);
|
||||
|
||||
if (invalid_frame_pointer(sf, sigframe_size)) {
|
||||
do_exit(SIGILL);
|
||||
if (show_unhandled_signals)
|
||||
pr_info("%s[%d] bad frame in setup_frame32: %08lx TPC %08lx O7 %08lx\n",
|
||||
current->comm, current->pid, (unsigned long)sf,
|
||||
regs->tpc, regs->u_regs[UREG_I7]);
|
||||
force_sigsegv(ksig->sig, current);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -501,7 +505,11 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
|
|||
get_sigframe(ksig, regs, sigframe_size);
|
||||
|
||||
if (invalid_frame_pointer(sf, sigframe_size)) {
|
||||
do_exit(SIGILL);
|
||||
if (show_unhandled_signals)
|
||||
pr_info("%s[%d] bad frame in setup_rt_frame32: %08lx TPC %08lx O7 %08lx\n",
|
||||
current->comm, current->pid, (unsigned long)sf,
|
||||
regs->tpc, regs->u_regs[UREG_I7]);
|
||||
force_sigsegv(ksig->sig, current);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -370,7 +370,11 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
|
|||
get_sigframe(ksig, regs, sf_size);
|
||||
|
||||
if (invalid_frame_pointer (sf)) {
|
||||
do_exit(SIGILL); /* won't return, actually */
|
||||
if (show_unhandled_signals)
|
||||
pr_info("%s[%d] bad frame in setup_rt_frame: %016lx TPC %016lx O7 %016lx\n",
|
||||
current->comm, current->pid, (unsigned long)sf,
|
||||
regs->tpc, regs->u_regs[UREG_I7]);
|
||||
force_sigsegv(ksig->sig, current);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue