Commit e36a82ee authored by Kamalesh Babulal's avatar Kamalesh Babulal Committed by Michael Ellerman

powerpc/livepatch: Fix livepatch stack access

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

  cpu 0x5: Vector: 400 (Instruction Access) at [c0000000eb9d3b60]
  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 occurs during the livepatch_handler execution, it's
possible for the livepatch_stack and/or thread_info to be corrupted.
eg:

  Task A                        Interrupt Handler
  =========                     =================
  livepatch_handler:
  mr r0, r1
  ld r1, TI_livepatch_sp(r12)
                                hardware_interrupt_common:
                                  do_IRQ+0x8:
                                    mflr    r0          <- saved stack pointer is overwritten
                                    bl      _mcount
                                    ...
                                    std     r27,-40(r1) <- overwrite of thread_info()

  lis r2, STACK_END_MAGIC@h
  ori r2, r2, STACK_END_MAGIC@l
  ld  r12, -8(r1)

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: default avatarKamalesh Babulal <kamalesh@linux.vnet.ibm.com>
Reviewed-by: default avatarNaveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Reviewed-by: default avatarBalbir Singh <bsingharora@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 53ecde0b
...@@ -181,34 +181,25 @@ _GLOBAL(ftrace_stub) ...@@ -181,34 +181,25 @@ _GLOBAL(ftrace_stub)
* - we have no stack frame and can not allocate one * - we have no stack frame and can not allocate one
* - LR points back to the original caller (in A) * - LR points back to the original caller (in A)
* - CTR holds the new NIP in C * - CTR holds the new NIP in C
* - r0 & r12 are free * - r0, r11 & 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.
*/ */
livepatch_handler: livepatch_handler:
CURRENT_THREAD_INFO(r12, r1) CURRENT_THREAD_INFO(r12, r1)
/* Save stack pointer into r0 */
mr r0, r1
/* Allocate 3 x 8 bytes */ /* Allocate 3 x 8 bytes */
ld r1, TI_livepatch_sp(r12) ld r11, TI_livepatch_sp(r12)
addi r1, r1, 24 addi r11, r11, 24
std r1, TI_livepatch_sp(r12) std r11, TI_livepatch_sp(r12)
/* Save toc & real LR on livepatch stack */ /* Save toc & real LR on livepatch stack */
std r2, -24(r1) std r2, -24(r11)
mflr r12 mflr r12
std r12, -16(r1) std r12, -16(r11)
/* Store stack end marker */ /* Store stack end marker */
lis r12, STACK_END_MAGIC@h lis r12, STACK_END_MAGIC@h
ori r12, r12, STACK_END_MAGIC@l ori r12, r12, STACK_END_MAGIC@l
std r12, -8(r1) std r12, -8(r11)
/* Restore real stack pointer */
mr r1, r0
/* Put ctr in r12 for global entry and branch there */ /* Put ctr in r12 for global entry and branch there */
mfctr r12 mfctr r12
...@@ -216,36 +207,30 @@ livepatch_handler: ...@@ -216,36 +207,30 @@ livepatch_handler:
/* /*
* Now we are returning from the patched function to the original * 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. * restore it.
*/ */
CURRENT_THREAD_INFO(r12, r1) CURRENT_THREAD_INFO(r12, r1)
/* Save stack pointer into r0 */ ld r11, TI_livepatch_sp(r12)
mr r0, r1
ld r1, TI_livepatch_sp(r12)
/* Check stack marker hasn't been trashed */ /* Check stack marker hasn't been trashed */
lis r2, STACK_END_MAGIC@h lis r2, STACK_END_MAGIC@h
ori r2, r2, STACK_END_MAGIC@l ori r2, r2, STACK_END_MAGIC@l
ld r12, -8(r1) ld r12, -8(r11)
1: tdne r12, r2 1: tdne r12, r2
EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0 EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0
/* Restore LR & toc from livepatch stack */ /* Restore LR & toc from livepatch stack */
ld r12, -16(r1) ld r12, -16(r11)
mtlr r12 mtlr r12
ld r2, -24(r1) ld r2, -24(r11)
/* Pop livepatch stack frame */ /* Pop livepatch stack frame */
CURRENT_THREAD_INFO(r12, r0) CURRENT_THREAD_INFO(r12, r1)
subi r1, r1, 24 subi r11, r11, 24
std r1, TI_livepatch_sp(r12) std r11, TI_livepatch_sp(r12)
/* Restore real stack pointer */
mr r1, r0
/* Return to original caller of live patched function */ /* Return to original caller of live patched function */
blr blr
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment