Commit fef47e2a authored by Helge Deller's avatar Helge Deller

parisc: ratelimit userspace segfault printing

Ratelimit printing of userspace segfaults and make it runtime
configurable via the /proc/sys/debug/exception-trace variable. This
should resolve syslog from growing way too fast and thus prevents
possible system service attacks.
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
Cc: stable@vger.kernel.org # 3.13+
parent 455c6fdb
...@@ -22,6 +22,7 @@ config PARISC ...@@ -22,6 +22,7 @@ config PARISC
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select SYSCTL_ARCH_UNALIGN_ALLOW select SYSCTL_ARCH_UNALIGN_ALLOW
select SYSCTL_EXCEPTION_TRACE
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select VIRT_TO_BUS select VIRT_TO_BUS
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/ratelimit.h>
#include <asm/assembly.h> #include <asm/assembly.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -42,9 +43,6 @@ ...@@ -42,9 +43,6 @@
#include "../math-emu/math-emu.h" /* for handle_fpe() */ #include "../math-emu/math-emu.h" /* for handle_fpe() */
#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
/* dumped to the console via printk) */
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
DEFINE_SPINLOCK(pa_dbit_lock); DEFINE_SPINLOCK(pa_dbit_lock);
#endif #endif
...@@ -160,6 +158,17 @@ void show_regs(struct pt_regs *regs) ...@@ -160,6 +158,17 @@ void show_regs(struct pt_regs *regs)
} }
} }
static DEFINE_RATELIMIT_STATE(_hppa_rs,
DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
#define parisc_printk_ratelimited(critical, regs, fmt, ...) { \
if ((critical || show_unhandled_signals) && __ratelimit(&_hppa_rs)) { \
printk(fmt, ##__VA_ARGS__); \
show_regs(regs); \
} \
}
static void do_show_stack(struct unwind_frame_info *info) static void do_show_stack(struct unwind_frame_info *info)
{ {
int i = 1; int i = 1;
...@@ -229,12 +238,10 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) ...@@ -229,12 +238,10 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
if (err == 0) if (err == 0)
return; /* STFU */ return; /* STFU */
printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n", parisc_printk_ratelimited(1, regs,
KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",
current->comm, task_pid_nr(current), str, err, regs->iaoq[0]); current->comm, task_pid_nr(current), str, err, regs->iaoq[0]);
#ifdef PRINT_USER_FAULTS
/* XXX for debugging only */
show_regs(regs);
#endif
return; return;
} }
...@@ -321,14 +328,11 @@ static void handle_break(struct pt_regs *regs) ...@@ -321,14 +328,11 @@ static void handle_break(struct pt_regs *regs)
(tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
} }
#ifdef PRINT_USER_FAULTS if (unlikely(iir != GDB_BREAK_INSN))
if (unlikely(iir != GDB_BREAK_INSN)) { parisc_printk_ratelimited(0, regs,
printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
iir & 31, (iir>>13) & ((1<<13)-1), iir & 31, (iir>>13) & ((1<<13)-1),
task_pid_nr(current), current->comm); task_pid_nr(current), current->comm);
show_regs(regs);
}
#endif
/* send standard GDB signal */ /* send standard GDB signal */
handle_gdb_break(regs, TRAP_BRKPT); handle_gdb_break(regs, TRAP_BRKPT);
...@@ -758,11 +762,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs) ...@@ -758,11 +762,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
default: default:
if (user_mode(regs)) { if (user_mode(regs)) {
#ifdef PRINT_USER_FAULTS parisc_printk_ratelimited(0, regs, KERN_DEBUG
printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n", "handle_interruption() pid=%d command='%s'\n",
task_pid_nr(current), current->comm); task_pid_nr(current), current->comm);
show_regs(regs);
#endif
/* SIGBUS, for lack of a better one. */ /* SIGBUS, for lack of a better one. */
si.si_signo = SIGBUS; si.si_signo = SIGBUS;
si.si_code = BUS_OBJERR; si.si_code = BUS_OBJERR;
...@@ -779,16 +781,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs) ...@@ -779,16 +781,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
if (user_mode(regs)) { if (user_mode(regs)) {
if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) { if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
#ifdef PRINT_USER_FAULTS parisc_printk_ratelimited(0, regs, KERN_DEBUG
if (fault_space == 0) "User fault %d on space 0x%08lx, pid=%d command='%s'\n",
printk(KERN_DEBUG "User Fault on Kernel Space "); code, fault_space,
else task_pid_nr(current), current->comm);
printk(KERN_DEBUG "User Fault (long pointer) (fault %d) ",
code);
printk(KERN_CONT "pid=%d command='%s'\n",
task_pid_nr(current), current->comm);
show_regs(regs);
#endif
si.si_signo = SIGSEGV; si.si_signo = SIGSEGV;
si.si_errno = 0; si.si_errno = 0;
si.si_code = SEGV_MAPERR; si.si_code = SEGV_MAPERR;
......
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/traps.h> #include <asm/traps.h>
#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
/* dumped to the console via printk) */
/* Various important other fields */ /* Various important other fields */
#define bit22set(x) (x & 0x00000200) #define bit22set(x) (x & 0x00000200)
#define bits23_25set(x) (x & 0x000001c0) #define bits23_25set(x) (x & 0x000001c0)
...@@ -34,6 +30,8 @@ ...@@ -34,6 +30,8 @@
DEFINE_PER_CPU(struct exception_data, exception_data); DEFINE_PER_CPU(struct exception_data, exception_data);
int show_unhandled_signals = 1;
/* /*
* parisc_acctyp(unsigned int inst) -- * parisc_acctyp(unsigned int inst) --
* Given a PA-RISC memory access instruction, determine if the * Given a PA-RISC memory access instruction, determine if the
...@@ -173,6 +171,32 @@ int fixup_exception(struct pt_regs *regs) ...@@ -173,6 +171,32 @@ int fixup_exception(struct pt_regs *regs)
return 0; return 0;
} }
/*
* Print out info about fatal segfaults, if the show_unhandled_signals
* sysctl is set:
*/
static inline void
show_signal_msg(struct pt_regs *regs, unsigned long code,
unsigned long address, struct task_struct *tsk,
struct vm_area_struct *vma)
{
if (!unhandled_signal(tsk, SIGSEGV))
return;
if (!printk_ratelimit())
return;
pr_warn("\n");
pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx",
tsk->comm, code, address);
print_vma_addr(KERN_CONT " in ", regs->iaoq[0]);
if (vma)
pr_warn(" vm_start = 0x%08lx, vm_end = 0x%08lx\n",
vma->vm_start, vma->vm_end);
show_regs(regs);
}
void do_page_fault(struct pt_regs *regs, unsigned long code, void do_page_fault(struct pt_regs *regs, unsigned long code,
unsigned long address) unsigned long address)
{ {
...@@ -270,16 +294,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long code, ...@@ -270,16 +294,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
if (user_mode(regs)) { if (user_mode(regs)) {
struct siginfo si; struct siginfo si;
#ifdef PRINT_USER_FAULTS show_signal_msg(regs, code, address, tsk, vma);
printk(KERN_DEBUG "\n");
printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n",
task_pid_nr(tsk), tsk->comm, code, address);
if (vma) {
printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n",
vma->vm_start, vma->vm_end);
}
show_regs(regs);
#endif
switch (code) { switch (code) {
case 15: /* Data TLB miss fault/Data page fault */ case 15: /* Data TLB miss fault/Data page fault */
/* send SIGSEGV when outside of vma */ /* send SIGSEGV when outside of vma */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment