[PATCH] powerpc/kprobes: don't save r13 register in kprobe context

pangliyuan pangliyuan1 at huawei.com
Mon Dec 9 20:10:39 AEDT 2024


When CONFIG_STACKPROTECTOR_STRONG is enabled and FTRACE is disabled on
powerpc64, repeatedly triggering the kprobe process may cause stack check
failures and panic.

Case:
There is a kprobe(do nothing in handler) attached to the "shmem_get_inode",
and a process A is creating file on tmpfs.

                           CPU0
A |r13 = paca_ptrs[0], paca_ptrs[0]->canary=A->stack_canary
  |touch a file on tmpfs
  |shmem_mknod():
  |    load A's canary through r13 and stored it in A's stack
  |    shmem_get_inode():
  |        enter kprobe first
  |        optinsn_slot():
  |            stored r13 (paca_ptrs[0]) in stack

  ......

  ==> schedule,  B run on CPU0, A run on CPU1

			   CPU0
B |r13 = paca_ptrs[0], paca_ptrs[0]->canary=B->stack_canary
  |do something...
                           CPU1
A |            r13 = paca_ptrs[1], paca_ptrs[1]->canary=A->stack_canary
  |            about to leave 'optinsn_slot', restore r13 from A's stack
  |            r13 = paca_ptrs[0], paca_ptrs[0]->canary=B->stack_canary
  |            leave optinsn_slot, back to shmem_get_inode
  |        leave shmem_get_inode, back to shmem_mknod
  |    do canary check in shmem_mknod, but canary stored in A's stack (A's
       canary) doesn't match the canary loaded through r13 (B's canary),
       so panic

When A(on CPU0) entring optinsn_slot, it stored r13(paca_ptrs[0]) in stack,
then A is scheduled to CPU1 and restore r13 from A's stack when leaving
'optinsn_slot'. Now A is running on CPU1 but r13 point to CPU0's
paca_ptrs[0], at this time paca_ptrs[0]->__current points to another
process B, which cause A use B's canary to do stack check and panic.

This can be simply fixed by not saving and restoring the r13 register,
because on powerpc64, r13 is a special register that reserved to point
to the current process, no need to restore the outdated r13 if scheduled
had happened.

Fixes: 51c9c0843993 ("powerpc/kprobes: Implement Optprobes")
Signed-off-by: pangliyuan <pangliyuan1 at huawei.com>
---
 arch/powerpc/kernel/optprobes_head.S | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/kernel/optprobes_head.S b/arch/powerpc/kernel/optprobes_head.S
index 35932f45fb4e..bf0d77e62ba8 100644
--- a/arch/powerpc/kernel/optprobes_head.S
+++ b/arch/powerpc/kernel/optprobes_head.S
@@ -10,12 +10,12 @@
 #include <asm/asm-offsets.h>
 
 #ifdef CONFIG_PPC64
-#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base)
-#define REST_30GPRS(base) REST_GPRS(2, 31, base)
+#define SAVE_NEEDED_GPRS(base) SAVE_GPRS(2, 12, base); SAVE_GPRS(14, 31, base)
+#define REST_NEEDED_GPRS(base) REST_GPRS(2, 12, base); REST_GPRS(14, 31, base)
 #define TEMPLATE_FOR_IMM_LOAD_INSNS	nop; nop; nop; nop; nop
 #else
-#define SAVE_30GPRS(base) stmw	r2, GPR2(base)
-#define REST_30GPRS(base) lmw	r2, GPR2(base)
+#define SAVE_NEEDED_GPRS(base) stmw	r2, GPR2(base)
+#define REST_NEEDED_GPRS(base) lmw	r2, GPR2(base)
 #define TEMPLATE_FOR_IMM_LOAD_INSNS	nop; nop; nop
 #endif
 
@@ -45,7 +45,7 @@ optprobe_template_entry:
 	/* Save the previous SP into stack */
 	addi	r0,r1,INT_FRAME_SIZE
 	PPC_STL	r0,GPR1(r1)
-	SAVE_30GPRS(r1)
+	SAVE_NEEDED_GPRS(r1)
 	/* Save SPRS */
 	mfmsr	r5
 	PPC_STL	r5,_MSR(r1)
@@ -123,7 +123,7 @@ optprobe_template_call_emulate:
 	PPC_LL	r5,_CCR(r1)
 	mtcr	r5
 	REST_GPR(0,r1)
-	REST_30GPRS(r1)
+	REST_NEEDED_GPRS(r1)
 	/* Restore the previous SP */
 	addi	r1,r1,INT_FRAME_SIZE
 
-- 
2.37.7



More information about the Linuxppc-dev mailing list