aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-11-20 22:45:49 +0100
committerAdrian Bunk <bunk@stusta.de>2006-11-20 22:45:49 +0100
commit371899a77a7a4e8d7f973846d2f8c16bf0722825 (patch)
treeacfa0969982f568630b21cd9960026a96f297a51
parent70c505610f4cda24c28b018db8c260c02f533a4f (diff)
downloadlinux-linaro-stable-371899a77a7a4e8d7f973846d2f8c16bf0722825.tar.gz
POWERPC: Make alignment exception always check exception table
The alignment exception used to only check the exception table for -EFAULT, not for other errors. That opens an oops window if we can coerce the kernel into getting an alignment exception for other reasons in what would normally be a user-protected accessor, which can be done via some of the futex ops. This fixes it by always checking the exception tables. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Adrian Bunk <bunk@stusta.de>
-rw-r--r--arch/powerpc/kernel/traps.c18
-rw-r--r--arch/ppc/kernel/traps.c18
2 files changed, 20 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 98660aedeeb7..c9506e226dd0 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -837,7 +837,7 @@ void __kprobes program_check_exception(struct pt_regs *regs)
void alignment_exception(struct pt_regs *regs)
{
- int fixed;
+ int sig, code, fixed;
fixed = fix_alignment(regs);
@@ -849,14 +849,16 @@ void alignment_exception(struct pt_regs *regs)
/* Operand address was bad */
if (fixed == -EFAULT) {
- if (user_mode(regs))
- _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
- else
- /* Search exception table */
- bad_page_fault(regs, regs->dar, SIGSEGV);
- return;
+ sig = SIGSEGV;
+ code = SEGV_ACCERR;
+ } else {
+ sig = SIGBUS;
+ code = BUS_ADRALN;
}
- _exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
+ if (user_mode(regs))
+ _exception(sig, regs, code, regs->dar);
+ else
+ bad_page_fault(regs, regs->dar, sig);
}
void StackOverflow(struct pt_regs *regs)
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 6d0a1838d94c..aa9dd0d07ec9 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -711,7 +711,7 @@ void single_step_exception(struct pt_regs *regs)
void alignment_exception(struct pt_regs *regs)
{
- int fixed;
+ int sig, code, fixed = 0;
fixed = fix_alignment(regs);
if (fixed == 1) {
@@ -720,14 +720,16 @@ void alignment_exception(struct pt_regs *regs)
return;
}
if (fixed == -EFAULT) {
- /* fixed == -EFAULT means the operand address was bad */
- if (user_mode(regs))
- _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
- else
- bad_page_fault(regs, regs->dar, SIGSEGV);
- return;
+ sig = SIGSEGV;
+ code = SEGV_ACCERR;
+ } else {
+ sig = SIGBUS;
+ code = BUS_ADRALN;
}
- _exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
+ if (user_mode(regs))
+ _exception(sig, regs, code, regs->dar);
+ else
+ bad_page_fault(regs, regs->dar, sig);
}
void StackOverflow(struct pt_regs *regs)