| From 4393c4f6788cee65095dd838cfeca6edefbfeb52 Mon Sep 17 00:00:00 2001 |
| From: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Message-Id: <1162416427.25682.429.camel@localhost.localdomain> |
| Date: Wed, 1 Nov 2006 15:11:39 +1100 |
| Subject: 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: Paul Mackerras <paulus@samba.org> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| --- |
| arch/powerpc/kernel/traps.c | 18 ++++++++++-------- |
| arch/ppc/kernel/traps.c | 18 ++++++++++-------- |
| 2 files changed, 20 insertions(+), 16 deletions(-) |
| |
| --- linux-2.6.18.2.orig/arch/powerpc/kernel/traps.c |
| +++ linux-2.6.18.2/arch/powerpc/kernel/traps.c |
| @@ -818,7 +818,7 @@ void __kprobes program_check_exception(s |
| |
| void alignment_exception(struct pt_regs *regs) |
| { |
| - int fixed = 0; |
| + int sig, code, fixed = 0; |
| |
| /* we don't implement logging of alignment exceptions */ |
| if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) |
| @@ -832,14 +832,16 @@ void alignment_exception(struct pt_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) |
| --- linux-2.6.18.2.orig/arch/ppc/kernel/traps.c |
| +++ linux-2.6.18.2/arch/ppc/kernel/traps.c |
| @@ -708,7 +708,7 @@ void single_step_exception(struct pt_reg |
| |
| void alignment_exception(struct pt_regs *regs) |
| { |
| - int fixed; |
| + int sig, code, fixed = 0; |
| |
| fixed = fix_alignment(regs); |
| if (fixed == 1) { |
| @@ -717,14 +717,16 @@ void alignment_exception(struct pt_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) |