Skip to content

Commit

Permalink
sparc64: Kill bogus TPC/address truncation during 32-bit faults.
Browse files Browse the repository at this point in the history
This builds upon eeabac7
("sparc64: Validate kernel generated fault addresses on sparc64.")

Upon further consideration, we actually should never see any
fault addresses for 32-bit tasks with the upper 32-bits set.

If it does every happen, by definition it's a bug.  Whatever
context created that fault would only have that fault satisfied
if we used the full 64-bit address.  If we truncate it, we'll
always fault the wrong address and we'll always loop faulting
forever.

So catch such conditions and mark them as errors always.  Log
the error and fail the fault.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 4, 2009
1 parent 47a4a0e commit 9b02605
Showing 1 changed file with 35 additions and 14 deletions.
49 changes: 35 additions & 14 deletions arch/sparc/mm/fault_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,30 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
unhandled_fault (address, current, regs);
}

static void noinline bogus_32bit_fault_tpc(struct pt_regs *regs)
{
static int times;

if (times++ < 10)
printk(KERN_ERR "FAULT[%s:%d]: 32-bit process reports "
"64-bit TPC [%lx]\n",
current->comm, current->pid,
regs->tpc);
show_regs(regs);
}

static void noinline bogus_32bit_fault_address(struct pt_regs *regs,
unsigned long addr)
{
static int times;

if (times++ < 10)
printk(KERN_ERR "FAULT[%s:%d]: 32-bit process "
"reports 64-bit fault address [%lx]\n",
current->comm, current->pid, addr);
show_regs(regs);
}

asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
{
struct mm_struct *mm = current->mm;
Expand All @@ -246,13 +270,20 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
BUG();

if (test_thread_flag(TIF_32BIT)) {
if (!(regs->tstate & TSTATE_PRIV))
regs->tpc &= 0xffffffff;
address &= 0xffffffff;
if (!(regs->tstate & TSTATE_PRIV)) {
if (unlikely((regs->tpc >> 32) != 0)) {
bogus_32bit_fault_tpc(regs);
goto intr_or_no_mm;
}
}
if (unlikely((address >> 32) != 0)) {
bogus_32bit_fault_address(regs, address);
goto intr_or_no_mm;
}
}

if (regs->tstate & TSTATE_PRIV) {
unsigned long eaddr, tpc = regs->tpc;
unsigned long tpc = regs->tpc;

/* Sanity check the PC. */
if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) ||
Expand All @@ -262,16 +293,6 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
bad_kernel_pc(regs, address);
return;
}

insn = get_fault_insn(regs, insn);
eaddr = compute_effective_address(regs, insn, 0);
if (WARN_ON_ONCE((eaddr & PAGE_MASK) != (address & PAGE_MASK))){
printk(KERN_ERR "FAULT: Mismatch kernel fault "
"address: addr[%lx] eaddr[%lx] TPC[%lx]\n",
address, eaddr, tpc);
show_regs(regs);
goto handle_kernel_fault;
}
}

/*
Expand Down

0 comments on commit 9b02605

Please sign in to comment.