diff mbox series

[v4,6/9] arm64: rethook: Add arm64 rethook implementation

Message ID 164304063053.1680787.17728029474747738793.stgit@devnote2 (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series fprobe: Introduce fprobe function entry/exit probe | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Masami Hiramatsu (Google) Jan. 24, 2022, 4:10 p.m. UTC
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 arch/arm64/Kconfig                            |    1 
 arch/arm64/kernel/probes/Makefile             |    1 
 arch/arm64/kernel/probes/rethook.c            |   25 +++++++
 arch/arm64/kernel/probes/rethook_trampoline.S |   87 +++++++++++++++++++++++++
 arch/arm64/kernel/stacktrace.c                |    3 +
 5 files changed, 117 insertions(+)
 create mode 100644 arch/arm64/kernel/probes/rethook.c
 create mode 100644 arch/arm64/kernel/probes/rethook_trampoline.S

Comments

kernel test robot Jan. 24, 2022, 10:23 p.m. UTC | #1
Hi Masami,

I love your patch! Yet something to improve:

[auto build test ERROR on rostedt-trace/for-next]
[also build test ERROR on arm64/for-next/core tip/x86/core linus/master v5.17-rc1 next-20220124]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Masami-Hiramatsu/fprobe-Introduce-fprobe-function-entry-exit-probe/20220125-001253
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git for-next
config: arm64-randconfig-r033-20220124 (https://download.01.org/0day-ci/archive/20220125/202201250403.5YnZvb4K-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/981b0378461c912ba2d7b10412dd6fe21c316055
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Masami-Hiramatsu/fprobe-Introduce-fprobe-function-entry-exit-probe/20220125-001253
        git checkout 981b0378461c912ba2d7b10412dd6fe21c316055
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm64 SHELL=/bin/bash arch/arm64/kernel/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   arch/arm64/kernel/stacktrace.c: In function 'unwind_frame':
>> arch/arm64/kernel/stacktrace.c:141:73: error: 'struct stackframe' has no member named 'kr_cur'
     141 |                 frame->pc = rethook_find_ret_addr(tsk, frame->fp, &frame->kr_cur);
         |                                                                         ^~


vim +141 arch/arm64/kernel/stacktrace.c

    59	
    60	/*
    61	 * Unwind from one frame record (A) to the next frame record (B).
    62	 *
    63	 * We terminate early if the location of B indicates a malformed chain of frame
    64	 * records (e.g. a cycle), determined based on the location and fp value of A
    65	 * and the location (but not the fp value) of B.
    66	 */
    67	int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
    68	{
    69		unsigned long fp = frame->fp;
    70		struct stack_info info;
    71	
    72		if (!tsk)
    73			tsk = current;
    74	
    75		/* Final frame; nothing to unwind */
    76		if (fp == (unsigned long)task_pt_regs(tsk)->stackframe)
    77			return -ENOENT;
    78	
    79		if (fp & 0x7)
    80			return -EINVAL;
    81	
    82		if (!on_accessible_stack(tsk, fp, 16, &info))
    83			return -EINVAL;
    84	
    85		if (test_bit(info.type, frame->stacks_done))
    86			return -EINVAL;
    87	
    88		/*
    89		 * As stacks grow downward, any valid record on the same stack must be
    90		 * at a strictly higher address than the prior record.
    91		 *
    92		 * Stacks can nest in several valid orders, e.g.
    93		 *
    94		 * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL
    95		 * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW
    96		 *
    97		 * ... but the nesting itself is strict. Once we transition from one
    98		 * stack to another, it's never valid to unwind back to that first
    99		 * stack.
   100		 */
   101		if (info.type == frame->prev_type) {
   102			if (fp <= frame->prev_fp)
   103				return -EINVAL;
   104		} else {
   105			set_bit(frame->prev_type, frame->stacks_done);
   106		}
   107	
   108		/*
   109		 * Record this frame record's values and location. The prev_fp and
   110		 * prev_type are only meaningful to the next unwind_frame() invocation.
   111		 */
   112		frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
   113		frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
   114		frame->prev_fp = fp;
   115		frame->prev_type = info.type;
   116	
   117		frame->pc = ptrauth_strip_insn_pac(frame->pc);
   118	
   119	#ifdef CONFIG_FUNCTION_GRAPH_TRACER
   120		if (tsk->ret_stack &&
   121			(frame->pc == (unsigned long)return_to_handler)) {
   122			unsigned long orig_pc;
   123			/*
   124			 * This is a case where function graph tracer has
   125			 * modified a return address (LR) in a stack frame
   126			 * to hook a function return.
   127			 * So replace it to an original value.
   128			 */
   129			orig_pc = ftrace_graph_ret_addr(tsk, NULL, frame->pc,
   130							(void *)frame->fp);
   131			if (WARN_ON_ONCE(frame->pc == orig_pc))
   132				return -EINVAL;
   133			frame->pc = orig_pc;
   134		}
   135	#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
   136	#ifdef CONFIG_KRETPROBES
   137		if (is_kretprobe_trampoline(frame->pc))
   138			frame->pc = kretprobe_find_ret_addr(tsk, (void *)frame->fp, &frame->kr_cur);
   139	#endif
   140		if (IS_ENABLED(CONFIG_RETHOOK) && is_rethook_trampoline(frame->pc))
 > 141			frame->pc = rethook_find_ret_addr(tsk, frame->fp, &frame->kr_cur);
   142	
   143		return 0;
   144	}
   145	NOKPROBE_SYMBOL(unwind_frame);
   146	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index c4207cf9bb17..c706ed25ea50 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -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
diff --git a/arch/arm64/kernel/probes/Makefile b/arch/arm64/kernel/probes/Makefile
index 8e4be92e25b1..24e689f44c32 100644
--- a/arch/arm64/kernel/probes/Makefile
+++ b/arch/arm64/kernel/probes/Makefile
@@ -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
diff --git a/arch/arm64/kernel/probes/rethook.c b/arch/arm64/kernel/probes/rethook.c
new file mode 100644
index 000000000000..38c33c81438b
--- /dev/null
+++ b/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);
diff --git a/arch/arm64/kernel/probes/rethook_trampoline.S b/arch/arm64/kernel/probes/rethook_trampoline.S
new file mode 100644
index 000000000000..610f520ee72b
--- /dev/null
+++ b/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)
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index b0f21677764d..d0883d0fa61c 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -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>
@@ -137,6 +138,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;
 }