Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/mm: Preserve CFAR value on SLB miss caused by access to bogus address

Currently, if userspace or the kernel accesses a completely bogus address,
for example with any of bits 46-59 set, we first take an SLB miss interrupt,
install a corresponding SLB entry with VSID 0, retry the instruction, then
take a DSI/ISI interrupt because there is no HPT entry mapping the address.
However, by the time of the second interrupt, the Come-From Address Register
(CFAR) has been overwritten by the rfid instruction at the end of the SLB
miss interrupt handler. Since bogus accesses can often be caused by a
function return after the stack has been overwritten, the CFAR value would
be very useful as it could indicate which function it was whose return had
led to the bogus address.

This patch adds code to create a full exception frame in the SLB miss handler
in the case of a bogus address, rather than inserting an SLB entry with a
zero VSID field. Then we call a new slb_miss_bad_addr() function in C code,
which delivers a signal for a user access or creates an oops for a kernel
access. In the latter case the oops message will show the CFAR value at the
time of the access.

In the case of the radix MMU, a segment miss interrupt indicates an access
outside the ranges mapped by the page tables. Previously this was handled
by the code for an unrecoverable SLB miss (one with MSR[RI] = 0), which is
not really correct. With this patch, we now handle these interrupts with
slb_miss_bad_addr(), which is much more consistent.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Paul Mackerras and committed by
Michael Ellerman
f0f558b1 b42d9023

+49 -11
+34 -6
arch/powerpc/kernel/exceptions-64s.S
··· 175 175 std r3,PACA_EXSLB+EX_R3(r13) 176 176 mfspr r3,SPRN_DAR 177 177 mfspr r12,SPRN_SRR1 178 + crset 4*cr6+eq 178 179 #ifndef CONFIG_RELOCATABLE 179 180 b slb_miss_realmode 180 181 #else ··· 202 201 std r3,PACA_EXSLB+EX_R3(r13) 203 202 mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ 204 203 mfspr r12,SPRN_SRR1 204 + crclr 4*cr6+eq 205 205 #ifndef CONFIG_RELOCATABLE 206 206 b slb_miss_realmode 207 207 #else ··· 785 783 std r3,PACA_EXSLB+EX_R3(r13) 786 784 mfspr r3,SPRN_DAR 787 785 mfspr r12,SPRN_SRR1 786 + crset 4*cr6+eq 788 787 #ifndef CONFIG_RELOCATABLE 789 788 b slb_miss_realmode 790 789 #else ··· 811 808 std r3,PACA_EXSLB+EX_R3(r13) 812 809 mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ 813 810 mfspr r12,SPRN_SRR1 811 + crclr 4*cr6+eq 814 812 #ifndef CONFIG_RELOCATABLE 815 813 b slb_miss_realmode 816 814 #else ··· 1412 1408 * r3 has the faulting address 1413 1409 * r9 - r13 are saved in paca->exslb. 1414 1410 * r3 is saved in paca->slb_r3 1411 + * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss 1415 1412 * We assume we aren't going to take any exceptions during this procedure. 1416 1413 */ 1417 1414 slb_miss_realmode: ··· 1423 1418 1424 1419 stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ 1425 1420 std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ 1421 + std r3,PACA_EXSLB+EX_DAR(r13) 1426 1422 1423 + crset 4*cr0+eq 1427 1424 #ifdef CONFIG_PPC_STD_MMU_64 1428 1425 BEGIN_MMU_FTR_SECTION 1429 1426 bl slb_allocate_realmode 1430 1427 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) 1431 1428 #endif 1432 - /* All done -- return from exception. */ 1433 1429 1434 1430 ld r10,PACA_EXSLB+EX_LR(r13) 1435 1431 ld r3,PACA_EXSLB+EX_R3(r13) 1436 1432 lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ 1437 - 1438 1433 mtlr r10 1434 + 1435 + beq 8f /* if bad address, make full stack frame */ 1436 + 1439 1437 andi. r10,r12,MSR_RI /* check for unrecoverable exception */ 1440 - BEGIN_MMU_FTR_SECTION 1441 1438 beq- 2f 1442 - FTR_SECTION_ELSE 1443 - b 2f 1444 - ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) 1439 + 1440 + /* All done -- return from exception. */ 1445 1441 1446 1442 .machine push 1447 1443 .machine "power4" 1448 1444 mtcrf 0x80,r9 1445 + mtcrf 0x02,r9 /* I/D indication is in cr6 */ 1449 1446 mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ 1450 1447 .machine pop 1451 1448 ··· 1477 1470 bl unrecoverable_exception 1478 1471 b 1b 1479 1472 1473 + 8: mfspr r11,SPRN_SRR0 1474 + ld r10,PACAKBASE(r13) 1475 + LOAD_HANDLER(r10,bad_addr_slb) 1476 + mtspr SPRN_SRR0,r10 1477 + ld r10,PACAKMSR(r13) 1478 + mtspr SPRN_SRR1,r10 1479 + rfid 1480 + b . 1481 + 1482 + bad_addr_slb: 1483 + EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) 1484 + RECONCILE_IRQ_STATE(r10, r11) 1485 + ld r3, PACA_EXSLB+EX_DAR(r13) 1486 + std r3, _DAR(r1) 1487 + beq cr6, 2f 1488 + li r10, 0x480 /* fix trap number for I-SLB miss */ 1489 + std r10, _TRAP(r1) 1490 + 2: bl save_nvgprs 1491 + addi r3, r1, STACK_FRAME_OVERHEAD 1492 + bl slb_miss_bad_addr 1493 + b ret_from_except 1480 1494 1481 1495 #ifdef CONFIG_PPC_970_NAP 1482 1496 power4_fixup_nap:
+12
arch/powerpc/kernel/traps.c
··· 1310 1310 exception_exit(prev_state); 1311 1311 } 1312 1312 1313 + void slb_miss_bad_addr(struct pt_regs *regs) 1314 + { 1315 + enum ctx_state prev_state = exception_enter(); 1316 + 1317 + if (user_mode(regs)) 1318 + _exception(SIGSEGV, regs, SEGV_BNDERR, regs->dar); 1319 + else 1320 + bad_page_fault(regs, regs->dar, SIGSEGV); 1321 + 1322 + exception_exit(prev_state); 1323 + } 1324 + 1313 1325 void StackOverflow(struct pt_regs *regs) 1314 1326 { 1315 1327 printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
+3 -5
arch/powerpc/mm/slb_low.S
··· 173 173 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) 174 174 b slb_finish_load 175 175 176 - 8: /* invalid EA */ 177 - li r10,0 /* BAD_VSID */ 178 - li r9,0 /* BAD_VSID */ 179 - li r11,SLB_VSID_USER /* flags don't much matter */ 180 - b slb_finish_load 176 + 8: /* invalid EA - return an error indication */ 177 + crset 4*cr0+eq /* indicate failure */ 178 + blr 181 179 182 180 /* 183 181 * Finish loading of an SLB entry and return