Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 375568
b: refs/heads/master
c: ba12eed
h: refs/heads/master
v: v3
  • Loading branch information
Li Zhong authored and Benjamin Herrenschmidt committed May 14, 2013
1 parent a18e516 commit e4aff51
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 46 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 22ecbe8dcef4f6bf80ed4358600e8f6e03105c5c
refs/heads/master: ba12eedee321eeb5baecaada285daeb3462c35f5
80 changes: 58 additions & 22 deletions trunk/arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/kdebug.h>
#include <linux/debugfs.h>
#include <linux/ratelimit.h>
#include <linux/context_tracking.h>

#include <asm/emulated_ops.h>
#include <asm/pgtable.h>
Expand Down Expand Up @@ -667,6 +668,7 @@ int machine_check_generic(struct pt_regs *regs)

void machine_check_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
int recover = 0;

__get_cpu_var(irq_stat).mce_exceptions++;
Expand All @@ -683,7 +685,7 @@ void machine_check_exception(struct pt_regs *regs)
recover = cur_cpu_spec->machine_check(regs);

if (recover > 0)
return;
goto bail;

#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
/* the qspan pci read routines can cause machine checks -- Cort
Expand All @@ -693,20 +695,23 @@ void machine_check_exception(struct pt_regs *regs)
* -- BenH
*/
bad_page_fault(regs, regs->dar, SIGBUS);
return;
goto bail;
#endif

if (debugger_fault_handler(regs))
return;
goto bail;

if (check_io_access(regs))
return;
goto bail;

die("Machine check", regs, SIGBUS);

/* Must die if the interrupt is not recoverable */
if (!(regs->msr & MSR_RI))
panic("Unrecoverable Machine check");

bail:
exception_exit(prev_state);
}

void SMIException(struct pt_regs *regs)
Expand All @@ -716,20 +721,29 @@ void SMIException(struct pt_regs *regs)

void unknown_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();

printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
regs->nip, regs->msr, regs->trap);

_exception(SIGTRAP, regs, 0, 0);

exception_exit(prev_state);
}

void instruction_breakpoint_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();

if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5,
5, SIGTRAP) == NOTIFY_STOP)
return;
goto bail;
if (debugger_iabr_match(regs))
return;
goto bail;
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);

bail:
exception_exit(prev_state);
}

void RunModeException(struct pt_regs *regs)
Expand All @@ -739,15 +753,20 @@ void RunModeException(struct pt_regs *regs)

void __kprobes single_step_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();

clear_single_step(regs);

if (notify_die(DIE_SSTEP, "single_step", regs, 5,
5, SIGTRAP) == NOTIFY_STOP)
return;
goto bail;
if (debugger_sstep(regs))
return;
goto bail;

_exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);

bail:
exception_exit(prev_state);
}

/*
Expand Down Expand Up @@ -1005,6 +1024,7 @@ int is_valid_bugaddr(unsigned long addr)

void __kprobes program_check_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
unsigned int reason = get_reason(regs);
extern int do_mathemu(struct pt_regs *regs);

Expand All @@ -1014,26 +1034,26 @@ void __kprobes program_check_exception(struct pt_regs *regs)
if (reason & REASON_FP) {
/* IEEE FP exception */
parse_fpe(regs);
return;
goto bail;
}
if (reason & REASON_TRAP) {
/* Debugger is first in line to stop recursive faults in
* rcu_lock, notify_die, or atomic_notifier_call_chain */
if (debugger_bpt(regs))
return;
goto bail;

/* trap exception */
if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP)
== NOTIFY_STOP)
return;
goto bail;

if (!(regs->msr & MSR_PR) && /* not user-mode */
report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
goto bail;
}
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
return;
goto bail;
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
if (reason & REASON_TM) {
Expand All @@ -1049,7 +1069,7 @@ void __kprobes program_check_exception(struct pt_regs *regs)
if (!user_mode(regs) &&
report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
goto bail;
}
/* If usermode caused this, it's done something illegal and
* gets a SIGILL slap on the wrist. We call it an illegal
Expand All @@ -1059,7 +1079,7 @@ void __kprobes program_check_exception(struct pt_regs *regs)
*/
if (user_mode(regs)) {
_exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
return;
goto bail;
} else {
printk(KERN_EMERG "Unexpected TM Bad Thing exception "
"at %lx (msr 0x%x)\n", regs->nip, reason);
Expand All @@ -1083,16 +1103,16 @@ void __kprobes program_check_exception(struct pt_regs *regs)
switch (do_mathemu(regs)) {
case 0:
emulate_single_step(regs);
return;
goto bail;
case 1: {
int code = 0;
code = __parse_fpscr(current->thread.fpscr.val);
_exception(SIGFPE, regs, code, regs->nip);
return;
goto bail;
}
case -EFAULT:
_exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
return;
goto bail;
}
/* fall through on any other errors */
#endif /* CONFIG_MATH_EMULATION */
Expand All @@ -1103,21 +1123,25 @@ void __kprobes program_check_exception(struct pt_regs *regs)
case 0:
regs->nip += 4;
emulate_single_step(regs);
return;
goto bail;
case -EFAULT:
_exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
return;
goto bail;
}
}

if (reason & REASON_PRIVILEGED)
_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
else
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);

bail:
exception_exit(prev_state);
}

void alignment_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
int sig, code, fixed = 0;

/* We restore the interrupt state now */
Expand All @@ -1131,7 +1155,7 @@ void alignment_exception(struct pt_regs *regs)
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */
emulate_single_step(regs);
return;
goto bail;
}

/* Operand address was bad */
Expand All @@ -1146,6 +1170,9 @@ void alignment_exception(struct pt_regs *regs)
_exception(sig, regs, code, regs->dar);
else
bad_page_fault(regs, regs->dar, sig);

bail:
exception_exit(prev_state);
}

void StackOverflow(struct pt_regs *regs)
Expand Down Expand Up @@ -1174,23 +1201,32 @@ void trace_syscall(struct pt_regs *regs)

void kernel_fp_unavailable_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();

printk(KERN_EMERG "Unrecoverable FP Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);

exception_exit(prev_state);
}

void altivec_unavailable_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();

if (user_mode(regs)) {
/* A user program has executed an altivec instruction,
but this kernel doesn't support altivec. */
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
goto bail;
}

printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);

bail:
exception_exit(prev_state);
}

void vsx_unavailable_exception(struct pt_regs *regs)
Expand Down
41 changes: 27 additions & 14 deletions trunk/arch/powerpc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/perf_event.h>
#include <linux/magic.h>
#include <linux/ratelimit.h>
#include <linux/context_tracking.h>

#include <asm/firmware.h>
#include <asm/page.h>
Expand Down Expand Up @@ -196,6 +197,7 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
enum ctx_state prev_state = exception_enter();
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
Expand All @@ -204,6 +206,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
int trap = TRAP(regs);
int is_exec = trap == 0x400;
int fault;
int rc = 0;

#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
/*
Expand All @@ -230,28 +233,30 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
* look at it
*/
if (error_code & ICSWX_DSI_UCT) {
int rc = acop_handle_fault(regs, address, error_code);
rc = acop_handle_fault(regs, address, error_code);
if (rc)
return rc;
goto bail;
}
#endif /* CONFIG_PPC_ICSWX */

if (notify_page_fault(regs))
return 0;
goto bail;

if (unlikely(debugger_fault_handler(regs)))
return 0;
goto bail;

/* On a kernel SLB miss we can only check for a valid exception entry */
if (!user_mode(regs) && (address >= TASK_SIZE))
return SIGSEGV;
if (!user_mode(regs) && (address >= TASK_SIZE)) {
rc = SIGSEGV;
goto bail;
}

#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \
defined(CONFIG_PPC_BOOK3S_64))
if (error_code & DSISR_DABRMATCH) {
/* breakpoint match */
do_break(regs, address, error_code);
return 0;
goto bail;
}
#endif

Expand All @@ -260,8 +265,10 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
local_irq_enable();

if (in_atomic() || mm == NULL) {
if (!user_mode(regs))
return SIGSEGV;
if (!user_mode(regs)) {
rc = SIGSEGV;
goto bail;
}
/* in_atomic() in user mode is really bad,
as is current->mm == NULL. */
printk(KERN_EMERG "Page fault in user mode with "
Expand Down Expand Up @@ -417,9 +424,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
*/
fault = handle_mm_fault(mm, vma, address, flags);
if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
int rc = mm_fault_error(regs, address, fault);
rc = mm_fault_error(regs, address, fault);
if (rc >= MM_FAULT_RETURN)
return rc;
goto bail;
else
rc = 0;
}

/*
Expand Down Expand Up @@ -454,7 +463,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
}

up_read(&mm->mmap_sem);
return 0;
goto bail;

bad_area:
up_read(&mm->mmap_sem);
Expand All @@ -463,15 +472,19 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
/* User mode accesses cause a SIGSEGV */
if (user_mode(regs)) {
_exception(SIGSEGV, regs, code, address);
return 0;
goto bail;
}

if (is_exec && (error_code & DSISR_PROTFAULT))
printk_ratelimited(KERN_CRIT "kernel tried to execute NX-protected"
" page (%lx) - exploit attempt? (uid: %d)\n",
address, from_kuid(&init_user_ns, current_uid()));

return SIGSEGV;
rc = SIGSEGV;

bail:
exception_exit(prev_state);
return rc;

}

Expand Down
Loading

0 comments on commit e4aff51

Please sign in to comment.