Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fef47e2a authored by Helge Deller's avatar Helge Deller
Browse files

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+25 −29
Original line number Diff line number Diff line
@@ -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>
@@ -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
@@ -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;
@@ -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;
	}

@@ -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);
@@ -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",
			parisc_printk_ratelimited(0, regs, KERN_DEBUG
				"handle_interruption() pid=%d command='%s'\n",
				task_pid_nr(current), current->comm);
			show_regs(regs);
#endif
			/* SIGBUS, for lack of a better one. */
			si.si_signo = SIGBUS;
			si.si_code = BUS_OBJERR;
@@ -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",
		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);
		show_regs(regs);
#endif
		si.si_signo = SIGSEGV;
		si.si_errno = 0;
		si.si_code = SEGV_MAPERR;
+30 −14
Original line number Diff line number Diff line
@@ -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)
@@ -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
@@ -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)
{
@@ -270,16 +294,8 @@ bad_area:
	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 */