powerpc/book3s: Add stack overflow check in machine check handler.
authorMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Wed, 11 Jun 2014 08:48:02 +0000 (14:18 +0530)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 11 Jun 2014 09:15:13 +0000 (19:15 +1000)
Currently machine check handler does not check for stack overflow for
nested machine check. If we hit another MCE while inside the machine check
handler repeatedly from same address then we get into risk of stack
overflow which can cause huge memory corruption. This patch limits the
nested MCE level to 4 and panic when we cross level 4.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/exceptions-64s.S

index 274a86d..8a0292d 100644 (file)
@@ -439,9 +439,9 @@ BEGIN_FTR_SECTION
         * R9           = CR
         * Original R9 to R13 is saved on PACA_EXMC
         *
-        * Switch to mc_emergency stack and handle re-entrancy (though we
-        * currently don't test for overflow). Save MCE registers srr1,
-        * srr0, dar and dsisr and then set ME=1
+        * Switch to mc_emergency stack and handle re-entrancy (we limit
+        * the nested MCE upto level 4 to avoid stack overflow).
+        * Save MCE registers srr1, srr0, dar and dsisr and then set ME=1
         *
         * We use paca->in_mce to check whether this is the first entry or
         * nested machine check. We increment paca->in_mce to track nested
@@ -464,6 +464,9 @@ BEGIN_FTR_SECTION
 0:     subi    r1,r1,INT_FRAME_SIZE    /* alloc stack frame */
        addi    r10,r10,1               /* increment paca->in_mce */
        sth     r10,PACA_IN_MCE(r13)
+       /* Limit nested MCE to level 4 to avoid stack overflow */
+       cmpwi   r10,4
+       bgt     2f                      /* Check if we hit limit of 4 */
        std     r11,GPR1(r1)            /* Save r1 on the stack. */
        std     r11,0(r1)               /* make stack chain pointer */
        mfspr   r11,SPRN_SRR0           /* Save SRR0 */
@@ -482,10 +485,23 @@ BEGIN_FTR_SECTION
        ori     r11,r11,MSR_RI          /* turn on RI bit */
        ld      r12,PACAKBASE(r13)      /* get high part of &label */
        LOAD_HANDLER(r12, machine_check_handle_early)
-       mtspr   SPRN_SRR0,r12
+1:     mtspr   SPRN_SRR0,r12
        mtspr   SPRN_SRR1,r11
        rfid
        b       .       /* prevent speculative execution */
+2:
+       /* Stack overflow. Stay on emergency stack and panic.
+        * Keep the ME bit off while panic-ing, so that if we hit
+        * another machine check we checkstop.
+        */
+       addi    r1,r1,INT_FRAME_SIZE    /* go back to previous stack frame */
+       ld      r11,PACAKMSR(r13)
+       ld      r12,PACAKBASE(r13)
+       LOAD_HANDLER(r12, unrecover_mce)
+       li      r10,MSR_ME
+       andc    r11,r11,r10             /* Turn off MSR_ME */
+       b       1b
+       b       .       /* prevent speculative execution */
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
 
 machine_check_pSeries: