Skip to content

Commit

Permalink
arm64: rethook: Add arm64 rethook implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
  • Loading branch information
mhiramat authored and intel-lab-lkp committed Jan 24, 2022
1 parent df6df88 commit 981b037
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/arm64/Kconfig
Expand Up @@ -201,6 +201,7 @@ config ARM64
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_RETHOOK
select HAVE_GENERIC_VDSO
select IOMMU_DMA if IOMMU_SUPPORT
select IRQ_DOMAIN
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/kernel/probes/Makefile
Expand Up @@ -4,3 +4,4 @@ obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o \
simulate-insn.o
obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o \
simulate-insn.o
obj-$(CONFIG_RETHOOK) += rethook.o rethook_trampoline.o
25 changes: 25 additions & 0 deletions arch/arm64/kernel/probes/rethook.c
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic return hook for arm64.
* Most of the code is copied from arch/arm64/kernel/probes/kprobes.c
*/

#include <linux/kprobes.h>
#include <linux/rethook.h>

/* This is called from arch_rethook_trampoline() */
unsigned long __used arch_rethook_trampoline_callback(struct pt_regs *regs)
{
return rethook_trampoline_handler(regs, regs->regs[29]);
}
NOKPROBE_SYMBOL(arch_rethook_trampoline_callback);

void arch_rethook_prepare(struct rethook_node *rhn, struct pt_regs *regs)
{
rhn->ret_addr = regs->regs[30];
rhn->frame = regs->regs[29];

/* replace return addr (x30) with trampoline */
regs->regs[30] = (u64)arch_rethook_trampoline;
}
NOKPROBE_SYMBOL(arch_rethook_prepare);
87 changes: 87 additions & 0 deletions arch/arm64/kernel/probes/rethook_trampoline.S
@@ -0,0 +1,87 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* trampoline entry and return code for rethook.
* Copied from arch/arm64/kernel/probes/kprobes_trampoline.S
*/

#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/assembler.h>

.text

.macro save_all_base_regs
stp x0, x1, [sp, #S_X0]
stp x2, x3, [sp, #S_X2]
stp x4, x5, [sp, #S_X4]
stp x6, x7, [sp, #S_X6]
stp x8, x9, [sp, #S_X8]
stp x10, x11, [sp, #S_X10]
stp x12, x13, [sp, #S_X12]
stp x14, x15, [sp, #S_X14]
stp x16, x17, [sp, #S_X16]
stp x18, x19, [sp, #S_X18]
stp x20, x21, [sp, #S_X20]
stp x22, x23, [sp, #S_X22]
stp x24, x25, [sp, #S_X24]
stp x26, x27, [sp, #S_X26]
stp x28, x29, [sp, #S_X28]
add x0, sp, #PT_REGS_SIZE
stp lr, x0, [sp, #S_LR]
/*
* Construct a useful saved PSTATE
*/
mrs x0, nzcv
mrs x1, daif
orr x0, x0, x1
mrs x1, CurrentEL
orr x0, x0, x1
mrs x1, SPSel
orr x0, x0, x1
stp xzr, x0, [sp, #S_PC]
.endm

.macro restore_all_base_regs
ldr x0, [sp, #S_PSTATE]
and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
msr nzcv, x0
ldp x0, x1, [sp, #S_X0]
ldp x2, x3, [sp, #S_X2]
ldp x4, x5, [sp, #S_X4]
ldp x6, x7, [sp, #S_X6]
ldp x8, x9, [sp, #S_X8]
ldp x10, x11, [sp, #S_X10]
ldp x12, x13, [sp, #S_X12]
ldp x14, x15, [sp, #S_X14]
ldp x16, x17, [sp, #S_X16]
ldp x18, x19, [sp, #S_X18]
ldp x20, x21, [sp, #S_X20]
ldp x22, x23, [sp, #S_X22]
ldp x24, x25, [sp, #S_X24]
ldp x26, x27, [sp, #S_X26]
ldp x28, x29, [sp, #S_X28]
.endm

SYM_CODE_START(arch_rethook_trampoline)
sub sp, sp, #PT_REGS_SIZE

save_all_base_regs

/* Setup a frame pointer. */
add x29, sp, #S_FP

mov x0, sp
bl arch_rethook_trampoline_callback
/*
* Replace trampoline address in lr with actual orig_ret_addr return
* address.
*/
mov lr, x0

/* The frame pointer (x29) is restored with other registers. */
restore_all_base_regs

add sp, sp, #PT_REGS_SIZE
ret

SYM_CODE_END(arch_rethook_trampoline)
3 changes: 3 additions & 0 deletions arch/arm64/kernel/stacktrace.c
Expand Up @@ -8,6 +8,7 @@
#include <linux/export.h>
#include <linux/ftrace.h>
#include <linux/kprobes.h>
#include <linux/rethook.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/task_stack.h>
Expand Down Expand Up @@ -136,6 +137,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
if (is_kretprobe_trampoline(frame->pc))
frame->pc = kretprobe_find_ret_addr(tsk, (void *)frame->fp, &frame->kr_cur);
#endif
if (IS_ENABLED(CONFIG_RETHOOK) && is_rethook_trampoline(frame->pc))
frame->pc = rethook_find_ret_addr(tsk, frame->fp, &frame->kr_cur);

return 0;
}
Expand Down

0 comments on commit 981b037

Please sign in to comment.