Skip to content

Commit

Permalink
parisc: ratelimit userspace segfault printing
Browse files Browse the repository at this point in the history
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: Helge Deller <deller@gmx.de>
Cc: stable@vger.kernel.org # 3.13+
  • Loading branch information
Helge Deller committed May 15, 2014
1 parent 455c6fd commit fef47e2
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 43 deletions.
1 change: 1 addition & 0 deletions arch/parisc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ config PARISC
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
select SYSCTL_ARCH_UNALIGN_ALLOW
select SYSCTL_EXCEPTION_TRACE
select HAVE_MOD_ARCH_SPECIFIC
select VIRT_TO_BUS
select MODULES_USE_ELF_RELA
Expand Down
54 changes: 25 additions & 29 deletions arch/parisc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/console.h>
#include <linux/bug.h>
#include <linux/ratelimit.h>

#include <asm/assembly.h>
#include <asm/uaccess.h>
Expand All @@ -42,9 +43,6 @@

#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)
DEFINE_SPINLOCK(pa_dbit_lock);
#endif
Expand Down Expand Up @@ -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)
{
int i = 1;
Expand Down Expand Up @@ -229,12 +238,10 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
if (err == 0)
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]);
#ifdef PRINT_USER_FAULTS
/* XXX for debugging only */
show_regs(regs);
#endif

return;
}

Expand Down Expand Up @@ -321,14 +328,11 @@ static void handle_break(struct pt_regs *regs)
(tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
}

#ifdef PRINT_USER_FAULTS
if (unlikely(iir != GDB_BREAK_INSN)) {
printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
if (unlikely(iir != GDB_BREAK_INSN))
parisc_printk_ratelimited(0, regs,
KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
iir & 31, (iir>>13) & ((1<<13)-1),
task_pid_nr(current), current->comm);
show_regs(regs);
}
#endif

/* send standard GDB signal */
handle_gdb_break(regs, TRAP_BRKPT);
Expand Down Expand Up @@ -758,11 +762,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)

default:
if (user_mode(regs)) {
#ifdef PRINT_USER_FAULTS
printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n",
task_pid_nr(current), current->comm);
show_regs(regs);
#endif
parisc_printk_ratelimited(0, regs, KERN_DEBUG
"handle_interruption() pid=%d command='%s'\n",
task_pid_nr(current), current->comm);
/* SIGBUS, for lack of a better one. */
si.si_signo = SIGBUS;
si.si_code = BUS_OBJERR;
Expand All @@ -779,16 +781,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs)

if (user_mode(regs)) {
if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
#ifdef PRINT_USER_FAULTS
if (fault_space == 0)
printk(KERN_DEBUG "User Fault on Kernel Space ");
else
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
parisc_printk_ratelimited(0, regs, KERN_DEBUG
"User fault %d on space 0x%08lx, pid=%d command='%s'\n",
code, fault_space,
task_pid_nr(current), current->comm);
si.si_signo = SIGSEGV;
si.si_errno = 0;
si.si_code = SEGV_MAPERR;
Expand Down
44 changes: 30 additions & 14 deletions arch/parisc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
#include <asm/uaccess.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 */
#define bit22set(x) (x & 0x00000200)
#define bits23_25set(x) (x & 0x000001c0)
Expand All @@ -34,6 +30,8 @@

DEFINE_PER_CPU(struct exception_data, exception_data);

int show_unhandled_signals = 1;

/*
* parisc_acctyp(unsigned int inst) --
* Given a PA-RISC memory access instruction, determine if the
Expand Down Expand Up @@ -173,6 +171,32 @@ int fixup_exception(struct pt_regs *regs)
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,
unsigned long address)
{
Expand Down Expand Up @@ -270,16 +294,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
if (user_mode(regs)) {
struct siginfo si;

#ifdef PRINT_USER_FAULTS
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
show_signal_msg(regs, code, address, tsk, vma);

switch (code) {
case 15: /* Data TLB miss fault/Data page fault */
/* send SIGSEGV when outside of vma */
Expand Down

0 comments on commit fef47e2

Please sign in to comment.