[PATCH] powerpc/livepatch: Fix livepatch stack access

Kamalesh Babulal kamalesh at linux.vnet.ibm.com
Wed Sep 20 20:19:51 AEST 2017


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 at 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 at h
ori r2, r2, STACK_END_MAGIC at 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 <kamalesh at linux.vnet.ibm.com>
Cc: Balbir Singh <bsingharora at gmail.com>
Cc: Naveen N. Rao <naveen.n.rao at linux.vnet.ibm.com>
Cc: linuxppc-dev at 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 at h
 	ori     r12, r12, STACK_END_MAGIC at 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 at h
 	ori     r2,  r2, STACK_END_MAGIC at 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



More information about the Linuxppc-dev mailing list