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: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
Reviewed-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Reviewed-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
			
			
This commit is contained in:
		
							parent
							
								
									53ecde0b91
								
							
						
					
					
						commit
						e36a82ee4c
					
				| @ -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 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user