While running stress test with livepatch module loaded, kernel
bug was triggered.

cpu 0x5: Vector: 400 (Instruction Access) at [c0000000eb9d3b60]
    pc: c0000000eb9d3e30
    lr: c0000000eb9d3e30
    sp: c0000000eb9d3de0
   msr: 800000001280b033
  current = 0xc0000000dbd38700
  paca    = 0xc00000000fe01400   softe: 0        irq_happened: 0x01
    pid   = 8618, comm = make
Linux version 4.13.0+ (root@ubuntu) (gcc version 6.3.0 20170406 (Ubuntu 
6.3.0-12ubuntu2)) #1 SMP Wed Sep 13 03:49:27 EDT 2017

5:mon> t
[c0000000eb9d3de0] c0000000eb9d3e30 (unreliable)
[c0000000eb9d3e30] c000000000008ab4 hardware_interrupt_common+0x114/0x120
 --- Exception: 501 (Hardware Interrupt) at c000000000053040 
livepatch_handler+0x4c/0x74
[c0000000eb9d4120] 0000000057ac6e9d (unreliable)
[d0000000089d9f78] 2e0965747962382e
SP (965747962342e09) is in userspace

When an interrupt is served in between the livepatch_handler execution,
there are chances of the livepatch_stack/task task getting corrupted.

                    CPU 1
                 =============
Task A                          Interrupt Handler
=========                       =================
livepatch_handler:
 mr r0, r1
 ld r1, TI_livepatch_sp(r12)
                                hardware_interrupt_common
                                |_do_IRQ
                                  |_ call_do_irq:
                                        mflr r0
                                        std  r0,16(r1)
                                        stdu 
r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
                                            ...
lis r2, STACK_END_MAGIC@h
ori r2, r2, STACK_END_MAGIC@l
ld  r12, -8(r1)      <- livepatch stack is corrupted.

Fix the corruption by using r11 register for livepatch stack manipulation,
instead of shuffling task stack and livepatch stack into r1 register.
Using r11 register also avoids disabling/enabling irq's while setting
up the livepatch stack.

Signed-off-by: Kamalesh Babulal <kamal...@linux.vnet.ibm.com>
Cc: Balbir Singh <bsinghar...@gmail.com>
Cc: Naveen N. Rao <naveen.n....@linux.vnet.ibm.com>
Cc: linuxppc-dev@lists.ozlabs.org
---
 arch/powerpc/kernel/trace/ftrace_64_mprofile.S | 45 +++++++++-----------------
 1 file changed, 15 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S 
b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
index c98e90b..b4e2b71 100644
--- a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
+++ b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
@@ -181,34 +181,25 @@ _GLOBAL(ftrace_stub)
         *  - we have no stack frame and can not allocate one
         *  - LR points back to the original caller (in A)
         *  - CTR holds the new NIP in C
-        *  - r0 & r12 are free
-        *
-        * r0 can't be used as the base register for a DS-form load or store, so
-        * we temporarily shuffle r1 (stack pointer) into r0 and then put it 
back.
+        *  - r0, r11 & r12 are free
         */
 livepatch_handler:
        CURRENT_THREAD_INFO(r12, r1)

-       /* Save stack pointer into r0 */
-       mr      r0, r1
-
        /* Allocate 3 x 8 bytes */
-       ld      r1, TI_livepatch_sp(r12)
-       addi    r1, r1, 24
-       std     r1, TI_livepatch_sp(r12)
+       ld      r11, TI_livepatch_sp(r12)
+       addi    r11, r11, 24
+       std     r11, TI_livepatch_sp(r12)

        /* Save toc & real LR on livepatch stack */
-       std     r2,  -24(r1)
+       std     r2,  -24(r11)
        mflr    r12
-       std     r12, -16(r1)
+       std     r12, -16(r11)

        /* Store stack end marker */
        lis     r12, STACK_END_MAGIC@h
        ori     r12, r12, STACK_END_MAGIC@l
-       std     r12, -8(r1)
-
-       /* Restore real stack pointer */
-       mr      r1, r0
+       std     r12, -8(r11)

        /* Put ctr in r12 for global entry and branch there */
        mfctr   r12
@@ -216,36 +207,30 @@ livepatch_handler:

        /*
         * Now we are returning from the patched function to the original
-        * caller A. We are free to use r0 and r12, and we can use r2 until we
+        * caller A. We are free to use r11, r12 and we can use r2 until we
         * restore it.
         */

        CURRENT_THREAD_INFO(r12, r1)

-       /* Save stack pointer into r0 */
-       mr      r0, r1
-
-       ld      r1, TI_livepatch_sp(r12)
+       ld      r11, TI_livepatch_sp(r12)

        /* Check stack marker hasn't been trashed */
        lis     r2,  STACK_END_MAGIC@h
        ori     r2,  r2, STACK_END_MAGIC@l
-       ld      r12, -8(r1)
+       ld      r12, -8(r11)
 1:     tdne    r12, r2
        EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0

        /* Restore LR & toc from livepatch stack */
-       ld      r12, -16(r1)
+       ld      r12, -16(r11)
        mtlr    r12
-       ld      r2,  -24(r1)
+       ld      r2,  -24(r11)

        /* Pop livepatch stack frame */
-       CURRENT_THREAD_INFO(r12, r0)
-       subi    r1, r1, 24
-       std     r1, TI_livepatch_sp(r12)
-
-       /* Restore real stack pointer */
-       mr      r1, r0
+       CURRENT_THREAD_INFO(r12, r1)
+       subi    r11, r11, 24
+       std     r11, TI_livepatch_sp(r12)

        /* Return to original caller of live patched function */
        blr
--
2.7.4

Reply via email to