aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-02-03 19:28:23 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-03 19:28:23 -0500
commit9b02605826903203d5301049c1f52e722584785c (patch)
tree9f4c04e822ab9fff151d9d7aeb907915d8c79b20 /arch/sparc/mm
parent47a4a0e766e3152dee667ea8fcca8465c8a0759f (diff)
sparc64: Kill bogus TPC/address truncation during 32-bit faults.
This builds upon eeabac7386ca13bfe1a58afeb04326a9e1a3a20e ("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>
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r--arch/sparc/mm/fault_64.c49
1 files changed, 35 insertions, 14 deletions
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index 1a786abdada3..4ab8993b0863 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -225,6 +225,30 @@ cannot_handle:
225 unhandled_fault (address, current, regs); 225 unhandled_fault (address, current, regs);
226} 226}
227 227
228static 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
240static 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
228asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) 252asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
229{ 253{
230 struct mm_struct *mm = current->mm; 254 struct mm_struct *mm = current->mm;
@@ -246,13 +270,20 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
246 BUG(); 270 BUG();
247 271
248 if (test_thread_flag(TIF_32BIT)) { 272 if (test_thread_flag(TIF_32BIT)) {
249 if (!(regs->tstate & TSTATE_PRIV)) 273 if (!(regs->tstate & TSTATE_PRIV)) {
250 regs->tpc &= 0xffffffff; 274 if (unlikely((regs->tpc >> 32) != 0)) {
251 address &= 0xffffffff; 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 }
252 } 283 }
253 284
254 if (regs->tstate & TSTATE_PRIV) { 285 if (regs->tstate & TSTATE_PRIV) {
255 unsigned long eaddr, tpc = regs->tpc; 286 unsigned long tpc = regs->tpc;
256 287
257 /* Sanity check the PC. */ 288 /* Sanity check the PC. */
258 if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) || 289 if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) ||
@@ -262,16 +293,6 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
262 bad_kernel_pc(regs, address); 293 bad_kernel_pc(regs, address);
263 return; 294 return;
264 } 295 }
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 }
275 } 296 }
276 297
277 /* 298 /*