Skip to content

Commit

Permalink
parisc: fix kernel crash (protection id trap) when compiling ruby1.9
Browse files Browse the repository at this point in the history
On Wed, Dec 17, 2008 at 11:46:05PM +0100, Helge Deller wrote:
>

Honestly, I can't decide whether to apply this. It really should never
happen in the kernel, since the kernel can guarantee it won't get the
access rights failure (highest privilege level, and can set %sr and
%protid to whatever it wants.)

It really genuinely is a bug that probably should panic the kernel. The
only precedent I can easily see is x86 fixing up a bad iret with a
general protection fault, which is more or less analogous to code 27
here.

On the other hand, taking the exception on a userspace access really
isn't all that critical, and there's fundamentally little reason for the
kernel not to SIGSEGV the process, and continue...

Argh.

(btw, I've instrumented my do_sys_poll with a pile of assertions that
 %cr8 << 1 == %sr3 == current->mm.context... let's see if where we're
 getting corrupted is deterministic, though, I would guess that it won't
 be.)

Signed-off-by: Kyle McMartin <[email protected]>
  • Loading branch information
jkkm committed Jan 5, 2009
1 parent aefa8b6 commit c61c25e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 27 deletions.
2 changes: 2 additions & 0 deletions arch/parisc/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,6 @@ unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned lo
#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user

int fixup_exception(struct pt_regs *regs);

#endif /* __PARISC_UACCESS_H */
4 changes: 4 additions & 0 deletions arch/parisc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,10 @@ void handle_interruption(int code, struct pt_regs *regs)
/* Fall Through */
case 27:
/* Data memory protection ID trap */
if (code == 27 && !user_mode(regs) &&
fixup_exception(regs))
return;

die_if_kernel("Protection id trap", regs, code);
si.si_code = SEGV_MAPERR;
si.si_signo = SIGSEGV;
Expand Down
58 changes: 31 additions & 27 deletions arch/parisc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,41 @@ parisc_acctyp(unsigned long code, unsigned int inst)
}
#endif

int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fix;

fix = search_exception_tables(regs->iaoq[0]);
if (fix) {
struct exception_data *d;
d = &__get_cpu_var(exception_data);
d->fault_ip = regs->iaoq[0];
d->fault_space = regs->isr;
d->fault_addr = regs->ior;

regs->iaoq[0] = ((fix->fixup) & ~3);
/*
* NOTE: In some cases the faulting instruction
* may be in the delay slot of a branch. We
* don't want to take the branch, so we don't
* increment iaoq[1], instead we set it to be
* iaoq[0]+4, and clear the B bit in the PSW
*/
regs->iaoq[1] = regs->iaoq[0] + 4;
regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */

return 1;
}

return 0;
}

void do_page_fault(struct pt_regs *regs, unsigned long code,
unsigned long address)
{
struct vm_area_struct *vma, *prev_vma;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
const struct exception_table_entry *fix;
unsigned long acc_type;
int fault;

Expand Down Expand Up @@ -229,32 +257,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,

no_context:

if (!user_mode(regs)) {
fix = search_exception_tables(regs->iaoq[0]);

if (fix) {
struct exception_data *d;

d = &__get_cpu_var(exception_data);
d->fault_ip = regs->iaoq[0];
d->fault_space = regs->isr;
d->fault_addr = regs->ior;

regs->iaoq[0] = ((fix->fixup) & ~3);

/*
* NOTE: In some cases the faulting instruction
* may be in the delay slot of a branch. We
* don't want to take the branch, so we don't
* increment iaoq[1], instead we set it to be
* iaoq[0]+4, and clear the B bit in the PSW
*/

regs->iaoq[1] = regs->iaoq[0] + 4;
regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */

return;
}
if (!user_mode(regs) && fixup_exception(regs)) {
return;
}

parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
Expand Down

0 comments on commit c61c25e

Please sign in to comment.