remarkable-linux/arch/powerpc/kernel/optprobes_head.S
Naveen N. Rao f558b37bf4 powerpc/optprobes: Fix TOC handling in optprobes trampoline
Optprobes on powerpc are limited to kernel text area. We decided to also
optimize kretprobe_trampoline since that is also in kernel text area.
However,we failed to take into consideration the fact that the same
trampoline is also used to catch function returns from kernel modules.
As an example:

  $ sudo modprobe kobject-example
  $ sudo bash -c "echo 'r foo_show+8' > /sys/kernel/debug/tracing/kprobe_events"
  $ sudo bash -c "echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable"
  $ sudo cat /sys/kernel/debug/kprobes/list
  c000000000041350  k  kretprobe_trampoline+0x0    [OPTIMIZED]
  d000000000e00200  r  foo_show+0x8  kobject_example
  $ cat /sys/kernel/kobject_example/foo
  Segmentation fault

With the below (trimmed) splat in dmesg:

  Unable to handle kernel paging request for data at address 0xfec40000
  Faulting instruction address: 0xc000000000041540
  Oops: Kernel access of bad area, sig: 11 [#1]
  ...
  NIP [c000000000041540] optimized_callback+0x70/0xe0
  LR [c000000000041e60] optinsn_slot+0xf8/0x10000
  Call Trace:
  [c0000000c7327850] [c000000000289af4] alloc_set_pte+0x1c4/0x860 (unreliable)
  [c0000000c7327890] [c000000000041e60] optinsn_slot+0xf8/0x10000
  --- interrupt: 700 at 0xc0000000c7327a80
	       LR = kretprobe_trampoline+0x0/0x10
  [c0000000c7327ba0] [c0000000003a30d4] sysfs_kf_seq_show+0x104/0x1d0
  [c0000000c7327bf0] [c0000000003a0bb4] kernfs_seq_show+0x44/0x60
  [c0000000c7327c10] [c000000000330578] seq_read+0xf8/0x560
  [c0000000c7327cb0] [c0000000003a1e64] kernfs_fop_read+0x194/0x260
  [c0000000c7327d00] [c0000000002f9954] __vfs_read+0x44/0x1a0
  [c0000000c7327d90] [c0000000002fb4cc] vfs_read+0xbc/0x1b0
  [c0000000c7327de0] [c0000000002fd138] SyS_read+0x68/0x110
  [c0000000c7327e30] [c00000000000b8e0] system_call+0x38/0xfc

Fix this by loading up the kernel TOC before calling into the kernel.
The original TOC gets restored as part of the usual pt_regs restore.

Fixes: 762df10bad ("powerpc/kprobes: Optimize kprobe in kretprobe_trampoline()")
Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2017-02-23 08:23:30 +11:00

143 lines
2.9 KiB
ArmAsm

/*
* Code to prepare detour buffer for optprobes in Kernel.
*
* Copyright 2017, Anju T, IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <asm/ppc_asm.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
#define OPT_SLOT_SIZE 65536
.balign 4
/*
* Reserve an area to allocate slots for detour buffer.
* This is part of .text section (rather than vmalloc area)
* as this needs to be within 32MB of the probed address.
*/
.global optinsn_slot
optinsn_slot:
.space OPT_SLOT_SIZE
/*
* Optprobe template:
* This template gets copied into one of the slots in optinsn_slot
* and gets fixed up with real optprobe structures et al.
*/
.global optprobe_template_entry
optprobe_template_entry:
/* Create an in-memory pt_regs */
stdu r1,-INT_FRAME_SIZE(r1)
SAVE_GPR(0,r1)
/* Save the previous SP into stack */
addi r0,r1,INT_FRAME_SIZE
std r0,GPR1(r1)
SAVE_10GPRS(2,r1)
SAVE_10GPRS(12,r1)
SAVE_10GPRS(22,r1)
/* Save SPRS */
mfmsr r5
std r5,_MSR(r1)
li r5,0x700
std r5,_TRAP(r1)
li r5,0
std r5,ORIG_GPR3(r1)
std r5,RESULT(r1)
mfctr r5
std r5,_CTR(r1)
mflr r5
std r5,_LINK(r1)
mfspr r5,SPRN_XER
std r5,_XER(r1)
mfcr r5
std r5,_CCR(r1)
lbz r5,PACASOFTIRQEN(r13)
std r5,SOFTE(r1)
mfdar r5
std r5,_DAR(r1)
mfdsisr r5
std r5,_DSISR(r1)
/*
* We may get here from a module, so load the kernel TOC in r2.
* The original TOC gets restored when pt_regs is restored
* further below.
*/
ld r2,PACATOC(r13)
.global optprobe_template_op_address
optprobe_template_op_address:
/*
* Parameters to optimized_callback():
* 1. optimized_kprobe structure in r3
*/
nop
nop
nop
nop
nop
/* 2. pt_regs pointer in r4 */
addi r4,r1,STACK_FRAME_OVERHEAD
.global optprobe_template_call_handler
optprobe_template_call_handler:
/* Branch to optimized_callback() */
nop
/*
* Parameters for instruction emulation:
* 1. Pass SP in register r3.
*/
addi r3,r1,STACK_FRAME_OVERHEAD
.global optprobe_template_insn
optprobe_template_insn:
/* 2, Pass instruction to be emulated in r4 */
nop
nop
.global optprobe_template_call_emulate
optprobe_template_call_emulate:
/* Branch to emulate_step() */
nop
/*
* All done.
* Now, restore the registers...
*/
ld r5,_MSR(r1)
mtmsr r5
ld r5,_CTR(r1)
mtctr r5
ld r5,_LINK(r1)
mtlr r5
ld r5,_XER(r1)
mtxer r5
ld r5,_CCR(r1)
mtcr r5
ld r5,_DAR(r1)
mtdar r5
ld r5,_DSISR(r1)
mtdsisr r5
REST_GPR(0,r1)
REST_10GPRS(2,r1)
REST_10GPRS(12,r1)
REST_10GPRS(22,r1)
/* Restore the previous SP */
addi r1,r1,INT_FRAME_SIZE
.global optprobe_template_ret
optprobe_template_ret:
/* ... and jump back from trampoline */
nop
.global optprobe_template_end
optprobe_template_end: