Skip to content

Commit 9b02605

Browse files
committed
sparc64: Kill bogus TPC/address truncation during 32-bit faults.
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 <[email protected]>
1 parent 47a4a0e commit 9b02605

File tree

1 file changed

+35
-14
lines changed

1 file changed

+35
-14
lines changed

arch/sparc/mm/fault_64.c

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,30 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
225225
unhandled_fault (address, current, regs);
226226
}
227227

228+
static void noinline bogus_32bit_fault_tpc(struct pt_regs *regs)
229+
{
230+
static int times;
231+
232+
if (times++ < 10)
233+
printk(KERN_ERR "FAULT[%s:%d]: 32-bit process reports "
234+
"64-bit TPC [%lx]\n",
235+
current->comm, current->pid,
236+
regs->tpc);
237+
show_regs(regs);
238+
}
239+
240+
static void noinline bogus_32bit_fault_address(struct pt_regs *regs,
241+
unsigned long addr)
242+
{
243+
static int times;
244+
245+
if (times++ < 10)
246+
printk(KERN_ERR "FAULT[%s:%d]: 32-bit process "
247+
"reports 64-bit fault address [%lx]\n",
248+
current->comm, current->pid, addr);
249+
show_regs(regs);
250+
}
251+
228252
asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
229253
{
230254
struct mm_struct *mm = current->mm;
@@ -246,13 +270,20 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
246270
BUG();
247271

248272
if (test_thread_flag(TIF_32BIT)) {
249-
if (!(regs->tstate & TSTATE_PRIV))
250-
regs->tpc &= 0xffffffff;
251-
address &= 0xffffffff;
273+
if (!(regs->tstate & TSTATE_PRIV)) {
274+
if (unlikely((regs->tpc >> 32) != 0)) {
275+
bogus_32bit_fault_tpc(regs);
276+
goto intr_or_no_mm;
277+
}
278+
}
279+
if (unlikely((address >> 32) != 0)) {
280+
bogus_32bit_fault_address(regs, address);
281+
goto intr_or_no_mm;
282+
}
252283
}
253284

254285
if (regs->tstate & TSTATE_PRIV) {
255-
unsigned long eaddr, tpc = regs->tpc;
286+
unsigned long tpc = regs->tpc;
256287

257288
/* Sanity check the PC. */
258289
if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) ||
@@ -262,16 +293,6 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
262293
bad_kernel_pc(regs, address);
263294
return;
264295
}
265-
266-
insn = get_fault_insn(regs, insn);
267-
eaddr = compute_effective_address(regs, insn, 0);
268-
if (WARN_ON_ONCE((eaddr & PAGE_MASK) != (address & PAGE_MASK))){
269-
printk(KERN_ERR "FAULT: Mismatch kernel fault "
270-
"address: addr[%lx] eaddr[%lx] TPC[%lx]\n",
271-
address, eaddr, tpc);
272-
show_regs(regs);
273-
goto handle_kernel_fault;
274-
}
275296
}
276297

277298
/*

0 commit comments

Comments
 (0)