aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandeepa Prabhu <sandeepa.s.prabhu@gmail.com>2016-07-08 12:35:48 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2016-07-19 10:03:20 -0400
commit2dd0e8d2d2a157dbc83295a78336c2217110f2f8 (patch)
treef65bd725c6e0168d0f6d8ca56b55d1dbf4024e75
parent2af3ec08b414ceb9c32fad2bb0f87252f3f18de8 (diff)
arm64: Kprobes with single stepping support
Add support for basic kernel probes(kprobes) and jump probes (jprobes) for ARM64. Kprobes utilizes software breakpoint and single step debug exceptions supported on ARM v8. A software breakpoint is placed at the probe address to trap the kernel execution into the kprobe handler. ARM v8 supports enabling single stepping before the break exception return (ERET), with next PC in exception return address (ELR_EL1). The kprobe handler prepares an executable memory slot for out-of-line execution with a copy of the original instruction being probed, and enables single stepping. The PC is set to the out-of-line slot address before the ERET. With this scheme, the instruction is executed with the exact same register context except for the PC (and DAIF) registers. Debug mask (PSTATE.D) is enabled only when single stepping a recursive kprobe, e.g.: during kprobes reenter so that probed instruction can be single stepped within the kprobe handler -exception- context. The recursion depth of kprobe is always 2, i.e. upon probe re-entry, any further re-entry is prevented by not calling handlers and the case counted as a missed kprobe). Single stepping from the x-o-l slot has a drawback for PC-relative accesses like branching and symbolic literals access as the offset from the new PC (slot address) may not be ensured to fit in the immediate value of the opcode. Such instructions need simulation, so reject probing them. Instructions generating exceptions or cpu mode change are rejected for probing. Exclusive load/store instructions are rejected too. Additionally, the code is checked to see if it is inside an exclusive load/store sequence (code from Pratyush). System instructions are mostly enabled for stepping, except MSR/MRS accesses to "DAIF" flags in PSTATE, which are not safe for probing. This also changes arch/arm64/include/asm/ptrace.h to use include/asm-generic/ptrace.h. Thanks to Steve Capper and Pratyush Anand for several suggested Changes. Signed-off-by: Sandeepa Prabhu <sandeepa.s.prabhu@gmail.com> Signed-off-by: David A. Long <dave.long@linaro.org> Signed-off-by: Pratyush Anand <panand@redhat.com> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/include/asm/debug-monitors.h5
-rw-r--r--arch/arm64/include/asm/insn.h2
-rw-r--r--arch/arm64/include/asm/kprobes.h60
-rw-r--r--arch/arm64/include/asm/probes.h34
-rw-r--r--arch/arm64/include/asm/ptrace.h14
-rw-r--r--arch/arm64/kernel/Makefile2
-rw-r--r--arch/arm64/kernel/debug-monitors.c16
-rw-r--r--arch/arm64/kernel/probes/Makefile1
-rw-r--r--arch/arm64/kernel/probes/decode-insn.c143
-rw-r--r--arch/arm64/kernel/probes/decode-insn.h34
-rw-r--r--arch/arm64/kernel/probes/kprobes.c525
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm64/mm/fault.c26
14 files changed, 859 insertions, 5 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fab133c18a09..1f7d644f7f36 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -88,6 +88,7 @@ config ARM64
88 select HAVE_REGS_AND_STACK_ACCESS_API 88 select HAVE_REGS_AND_STACK_ACCESS_API
89 select HAVE_RCU_TABLE_FREE 89 select HAVE_RCU_TABLE_FREE
90 select HAVE_SYSCALL_TRACEPOINTS 90 select HAVE_SYSCALL_TRACEPOINTS
91 select HAVE_KPROBES
91 select IOMMU_DMA if IOMMU_SUPPORT 92 select IOMMU_DMA if IOMMU_SUPPORT
92 select IRQ_DOMAIN 93 select IRQ_DOMAIN
93 select IRQ_FORCED_THREADING 94 select IRQ_FORCED_THREADING
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 2fcb9b7c876c..4b6b3f72a215 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -66,6 +66,11 @@
66 66
67#define CACHE_FLUSH_IS_SAFE 1 67#define CACHE_FLUSH_IS_SAFE 1
68 68
69/* kprobes BRK opcodes with ESR encoding */
70#define BRK64_ESR_MASK 0xFFFF
71#define BRK64_ESR_KPROBES 0x0004
72#define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5))
73
69/* AArch32 */ 74/* AArch32 */
70#define DBG_ESR_EVT_BKPT 0x4 75#define DBG_ESR_EVT_BKPT 0x4
71#define DBG_ESR_EVT_VECC 0x5 76#define DBG_ESR_EVT_VECC 0x5
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index a44abbd61382..1dbaa901d7e5 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -253,6 +253,8 @@ __AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
253__AARCH64_INSN_FUNCS(ldr_lit, 0xBF000000, 0x18000000) 253__AARCH64_INSN_FUNCS(ldr_lit, 0xBF000000, 0x18000000)
254__AARCH64_INSN_FUNCS(ldrsw_lit, 0xFF000000, 0x98000000) 254__AARCH64_INSN_FUNCS(ldrsw_lit, 0xFF000000, 0x98000000)
255__AARCH64_INSN_FUNCS(exclusive, 0x3F800000, 0x08000000) 255__AARCH64_INSN_FUNCS(exclusive, 0x3F800000, 0x08000000)
256__AARCH64_INSN_FUNCS(load_ex, 0x3F400000, 0x08400000)
257__AARCH64_INSN_FUNCS(store_ex, 0x3F400000, 0x08000000)
256__AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000) 258__AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000)
257__AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000) 259__AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000)
258__AARCH64_INSN_FUNCS(stp_pre, 0x7FC00000, 0x29800000) 260__AARCH64_INSN_FUNCS(stp_pre, 0x7FC00000, 0x29800000)
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
new file mode 100644
index 000000000000..79c9511612b5
--- /dev/null
+++ b/arch/arm64/include/asm/kprobes.h
@@ -0,0 +1,60 @@
1/*
2 * arch/arm64/include/asm/kprobes.h
3 *
4 * Copyright (C) 2013 Linaro Limited
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
16#ifndef _ARM_KPROBES_H
17#define _ARM_KPROBES_H
18
19#include <linux/types.h>
20#include <linux/ptrace.h>
21#include <linux/percpu.h>
22
23#define __ARCH_WANT_KPROBES_INSN_SLOT
24#define MAX_INSN_SIZE 1
25#define MAX_STACK_SIZE 128
26
27#define flush_insn_slot(p) do { } while (0)
28#define kretprobe_blacklist_size 0
29
30#include <asm/probes.h>
31
32struct prev_kprobe {
33 struct kprobe *kp;
34 unsigned int status;
35};
36
37/* Single step context for kprobe */
38struct kprobe_step_ctx {
39 unsigned long ss_pending;
40 unsigned long match_addr;
41};
42
43/* per-cpu kprobe control block */
44struct kprobe_ctlblk {
45 unsigned int kprobe_status;
46 unsigned long saved_irqflag;
47 struct prev_kprobe prev_kprobe;
48 struct kprobe_step_ctx ss_ctx;
49 struct pt_regs jprobe_saved_regs;
50 char jprobes_stack[MAX_STACK_SIZE];
51};
52
53void arch_remove_kprobe(struct kprobe *);
54int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
55int kprobe_exceptions_notify(struct notifier_block *self,
56 unsigned long val, void *data);
57int kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr);
58int kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr);
59
60#endif /* _ARM_KPROBES_H */
diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h
new file mode 100644
index 000000000000..1e8a21a96002
--- /dev/null
+++ b/arch/arm64/include/asm/probes.h
@@ -0,0 +1,34 @@
1/*
2 * arch/arm64/include/asm/probes.h
3 *
4 * Copyright (C) 2013 Linaro Limited
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15#ifndef _ARM_PROBES_H
16#define _ARM_PROBES_H
17
18struct kprobe;
19struct arch_specific_insn;
20
21typedef u32 kprobe_opcode_t;
22typedef unsigned long (kprobes_pstate_check_t)(unsigned long);
23typedef void (kprobes_handler_t) (u32 opcode, long addr, struct pt_regs *);
24
25/* architecture specific copy of original instruction */
26struct arch_specific_insn {
27 kprobe_opcode_t *insn;
28 kprobes_pstate_check_t *pstate_cc;
29 kprobes_handler_t *handler;
30 /* restore address after step xol */
31 unsigned long restore;
32};
33
34#endif
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 941e12d235be..baf938135986 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -147,9 +147,12 @@ struct pt_regs {
147#define fast_interrupts_enabled(regs) \ 147#define fast_interrupts_enabled(regs) \
148 (!((regs)->pstate & PSR_F_BIT)) 148 (!((regs)->pstate & PSR_F_BIT))
149 149
150#define user_stack_pointer(regs) \ 150#define GET_USP(regs) \
151 (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp) 151 (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
152 152
153#define SET_USP(ptregs, value) \
154 (!compat_user_mode(regs) ? ((regs)->sp = value) : ((regs)->compat_sp = value))
155
153extern int regs_query_register_offset(const char *name); 156extern int regs_query_register_offset(const char *name);
154extern const char *regs_query_register_name(unsigned int offset); 157extern const char *regs_query_register_name(unsigned int offset);
155extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, 158extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
@@ -206,8 +209,15 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
206struct task_struct; 209struct task_struct;
207int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task); 210int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);
208 211
209#define instruction_pointer(regs) ((unsigned long)(regs)->pc) 212#define GET_IP(regs) ((unsigned long)(regs)->pc)
213#define SET_IP(regs, value) ((regs)->pc = ((u64) (value)))
214
215#define GET_FP(ptregs) ((unsigned long)(ptregs)->regs[29])
216#define SET_FP(ptregs, value) ((ptregs)->regs[29] = ((u64) (value)))
217
218#include <asm-generic/ptrace.h>
210 219
220#undef profile_pc
211extern unsigned long profile_pc(struct pt_regs *regs); 221extern unsigned long profile_pc(struct pt_regs *regs);
212 222
213#endif /* __ASSEMBLY__ */ 223#endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 4653aca9bb61..367673e38700 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -46,7 +46,7 @@ arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o
46arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o 46arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
47arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o 47arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
48 48
49obj-y += $(arm64-obj-y) vdso/ 49obj-y += $(arm64-obj-y) vdso/ probes/
50obj-m += $(arm64-obj-m) 50obj-m += $(arm64-obj-m)
51head-y := head.o 51head-y := head.o
52extra-y += $(head-y) vmlinux.lds 52extra-y += $(head-y) vmlinux.lds
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 4fbf3c54275c..395de61108d8 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -23,6 +23,7 @@
23#include <linux/hardirq.h> 23#include <linux/hardirq.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/ptrace.h> 25#include <linux/ptrace.h>
26#include <linux/kprobes.h>
26#include <linux/stat.h> 27#include <linux/stat.h>
27#include <linux/uaccess.h> 28#include <linux/uaccess.h>
28 29
@@ -266,6 +267,10 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
266 */ 267 */
267 user_rewind_single_step(current); 268 user_rewind_single_step(current);
268 } else { 269 } else {
270#ifdef CONFIG_KPROBES
271 if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
272 return 0;
273#endif
269 if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED) 274 if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
270 return 0; 275 return 0;
271 276
@@ -322,8 +327,15 @@ static int brk_handler(unsigned long addr, unsigned int esr,
322{ 327{
323 if (user_mode(regs)) { 328 if (user_mode(regs)) {
324 send_user_sigtrap(TRAP_BRKPT); 329 send_user_sigtrap(TRAP_BRKPT);
325 } else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) { 330 }
326 pr_warning("Unexpected kernel BRK exception at EL1\n"); 331#ifdef CONFIG_KPROBES
332 else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) {
333 if (kprobe_breakpoint_handler(regs, esr) != DBG_HOOK_HANDLED)
334 return -EFAULT;
335 }
336#endif
337 else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
338 pr_warn("Unexpected kernel BRK exception at EL1\n");
327 return -EFAULT; 339 return -EFAULT;
328 } 340 }
329 341
diff --git a/arch/arm64/kernel/probes/Makefile b/arch/arm64/kernel/probes/Makefile
new file mode 100644
index 000000000000..bc159bf56992
--- /dev/null
+++ b/arch/arm64/kernel/probes/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o
diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c
new file mode 100644
index 000000000000..95c0c5281e7b
--- /dev/null
+++ b/arch/arm64/kernel/probes/decode-insn.c
@@ -0,0 +1,143 @@
1/*
2 * arch/arm64/kernel/probes/decode-insn.c
3 *
4 * Copyright (C) 2013 Linaro Limited.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
16#include <linux/kernel.h>
17#include <linux/kprobes.h>
18#include <linux/module.h>
19#include <asm/kprobes.h>
20#include <asm/insn.h>
21#include <asm/sections.h>
22
23#include "decode-insn.h"
24
25static bool __kprobes aarch64_insn_is_steppable(u32 insn)
26{
27 /*
28 * Branch instructions will write a new value into the PC which is
29 * likely to be relative to the XOL address and therefore invalid.
30 * Deliberate generation of an exception during stepping is also not
31 * currently safe. Lastly, MSR instructions can do any number of nasty
32 * things we can't handle during single-stepping.
33 */
34 if (aarch64_get_insn_class(insn) == AARCH64_INSN_CLS_BR_SYS) {
35 if (aarch64_insn_is_branch(insn) ||
36 aarch64_insn_is_msr_imm(insn) ||
37 aarch64_insn_is_msr_reg(insn) ||
38 aarch64_insn_is_exception(insn) ||
39 aarch64_insn_is_eret(insn))
40 return false;
41
42 /*
43 * The MRS instruction may not return a correct value when
44 * executing in the single-stepping environment. We do make one
45 * exception, for reading the DAIF bits.
46 */
47 if (aarch64_insn_is_mrs(insn))
48 return aarch64_insn_extract_system_reg(insn)
49 != AARCH64_INSN_SPCLREG_DAIF;
50
51 /*
52 * The HINT instruction is is problematic when single-stepping,
53 * except for the NOP case.
54 */
55 if (aarch64_insn_is_hint(insn))
56 return aarch64_insn_is_nop(insn);
57
58 return true;
59 }
60
61 /*
62 * Instructions which load PC relative literals are not going to work
63 * when executed from an XOL slot. Instructions doing an exclusive
64 * load/store are not going to complete successfully when single-step
65 * exception handling happens in the middle of the sequence.
66 */
67 if (aarch64_insn_uses_literal(insn) ||
68 aarch64_insn_is_exclusive(insn))
69 return false;
70
71 return true;
72}
73
74/* Return:
75 * INSN_REJECTED If instruction is one not allowed to kprobe,
76 * INSN_GOOD If instruction is supported and uses instruction slot,
77 */
78static enum kprobe_insn __kprobes
79arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
80{
81 /*
82 * Instructions reading or modifying the PC won't work from the XOL
83 * slot.
84 */
85 if (aarch64_insn_is_steppable(insn))
86 return INSN_GOOD;
87 else
88 return INSN_REJECTED;
89}
90
91static bool __kprobes
92is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end)
93{
94 while (scan_start > scan_end) {
95 /*
96 * atomic region starts from exclusive load and ends with
97 * exclusive store.
98 */
99 if (aarch64_insn_is_store_ex(le32_to_cpu(*scan_start)))
100 return false;
101 else if (aarch64_insn_is_load_ex(le32_to_cpu(*scan_start)))
102 return true;
103 scan_start--;
104 }
105
106 return false;
107}
108
109enum kprobe_insn __kprobes
110arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi)
111{
112 enum kprobe_insn decoded;
113 kprobe_opcode_t insn = le32_to_cpu(*addr);
114 kprobe_opcode_t *scan_start = addr - 1;
115 kprobe_opcode_t *scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE;
116#if defined(CONFIG_MODULES) && defined(MODULES_VADDR)
117 struct module *mod;
118#endif
119
120 if (addr >= (kprobe_opcode_t *)_text &&
121 scan_end < (kprobe_opcode_t *)_text)
122 scan_end = (kprobe_opcode_t *)_text;
123#if defined(CONFIG_MODULES) && defined(MODULES_VADDR)
124 else {
125 preempt_disable();
126 mod = __module_address((unsigned long)addr);
127 if (mod && within_module_init((unsigned long)addr, mod) &&
128 !within_module_init((unsigned long)scan_end, mod))
129 scan_end = (kprobe_opcode_t *)mod->init_layout.base;
130 else if (mod && within_module_core((unsigned long)addr, mod) &&
131 !within_module_core((unsigned long)scan_end, mod))
132 scan_end = (kprobe_opcode_t *)mod->core_layout.base;
133 preempt_enable();
134 }
135#endif
136 decoded = arm_probe_decode_insn(insn, asi);
137
138 if (decoded == INSN_REJECTED ||
139 is_probed_address_atomic(scan_start, scan_end))
140 return INSN_REJECTED;
141
142 return decoded;
143}
diff --git a/arch/arm64/kernel/probes/decode-insn.h b/arch/arm64/kernel/probes/decode-insn.h
new file mode 100644
index 000000000000..ad5ba9cc3d45
--- /dev/null
+++ b/arch/arm64/kernel/probes/decode-insn.h
@@ -0,0 +1,34 @@
1/*
2 * arch/arm64/kernel/probes/decode-insn.h
3 *
4 * Copyright (C) 2013 Linaro Limited.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
16#ifndef _ARM_KERNEL_KPROBES_ARM64_H
17#define _ARM_KERNEL_KPROBES_ARM64_H
18
19/*
20 * ARM strongly recommends a limit of 128 bytes between LoadExcl and
21 * StoreExcl instructions in a single thread of execution. So keep the
22 * max atomic context size as 32.
23 */
24#define MAX_ATOMIC_CONTEXT_SIZE (128 / sizeof(kprobe_opcode_t))
25
26enum kprobe_insn {
27 INSN_REJECTED,
28 INSN_GOOD,
29};
30
31enum kprobe_insn __kprobes
32arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi);
33
34#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
new file mode 100644
index 000000000000..44968019ce0d
--- /dev/null
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -0,0 +1,525 @@
1/*
2 * arch/arm64/kernel/probes/kprobes.c
3 *
4 * Kprobes support for ARM64
5 *
6 * Copyright (C) 2013 Linaro Limited.
7 * Author: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 */
19#include <linux/kernel.h>
20#include <linux/kprobes.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/stop_machine.h>
24#include <linux/stringify.h>
25#include <asm/traps.h>
26#include <asm/ptrace.h>
27#include <asm/cacheflush.h>
28#include <asm/debug-monitors.h>
29#include <asm/system_misc.h>
30#include <asm/insn.h>
31#include <asm/uaccess.h>
32#include <asm/irq.h>
33
34#include "decode-insn.h"
35
36#define MIN_STACK_SIZE(addr) (on_irq_stack(addr, raw_smp_processor_id()) ? \
37 min((unsigned long)IRQ_STACK_SIZE, \
38 IRQ_STACK_PTR(raw_smp_processor_id()) - (addr)) : \
39 min((unsigned long)MAX_STACK_SIZE, \
40 (unsigned long)current_thread_info() + THREAD_START_SP - (addr)))
41
42void jprobe_return_break(void);
43
44DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
45DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
46
47static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
48{
49 /* prepare insn slot */
50 p->ainsn.insn[0] = cpu_to_le32(p->opcode);
51
52 flush_icache_range((uintptr_t) (p->ainsn.insn),
53 (uintptr_t) (p->ainsn.insn) +
54 MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
55
56 /*
57 * Needs restoring of return address after stepping xol.
58 */
59 p->ainsn.restore = (unsigned long) p->addr +
60 sizeof(kprobe_opcode_t);
61}
62
63int __kprobes arch_prepare_kprobe(struct kprobe *p)
64{
65 unsigned long probe_addr = (unsigned long)p->addr;
66 extern char __start_rodata[];
67 extern char __end_rodata[];
68
69 if (probe_addr & 0x3)
70 return -EINVAL;
71
72 /* copy instruction */
73 p->opcode = le32_to_cpu(*p->addr);
74
75 if (in_exception_text(probe_addr))
76 return -EINVAL;
77 if (probe_addr >= (unsigned long) __start_rodata &&
78 probe_addr <= (unsigned long) __end_rodata)
79 return -EINVAL;
80
81 /* decode instruction */
82 switch (arm_kprobe_decode_insn(p->addr, &p->ainsn)) {
83 case INSN_REJECTED: /* insn not supported */
84 return -EINVAL;
85
86 case INSN_GOOD: /* instruction uses slot */
87 p->ainsn.insn = get_insn_slot();
88 if (!p->ainsn.insn)
89 return -ENOMEM;
90 break;
91 };
92
93 /* prepare the instruction */
94 arch_prepare_ss_slot(p);
95
96 return 0;
97}
98
99static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
100{
101 void *addrs[1];
102 u32 insns[1];
103
104 addrs[0] = (void *)addr;
105 insns[0] = (u32)opcode;
106
107 return aarch64_insn_patch_text(addrs, insns, 1);
108}
109
110/* arm kprobe: install breakpoint in text */
111void __kprobes arch_arm_kprobe(struct kprobe *p)
112{
113 patch_text(p->addr, BRK64_OPCODE_KPROBES);
114}
115
116/* disarm kprobe: remove breakpoint from text */
117void __kprobes arch_disarm_kprobe(struct kprobe *p)
118{
119 patch_text(p->addr, p->opcode);
120}
121
122void __kprobes arch_remove_kprobe(struct kprobe *p)
123{
124 if (p->ainsn.insn) {
125 free_insn_slot(p->ainsn.insn, 0);
126 p->ainsn.insn = NULL;
127 }
128}
129
130static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
131{
132 kcb->prev_kprobe.kp = kprobe_running();
133 kcb->prev_kprobe.status = kcb->kprobe_status;
134}
135
136static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
137{
138 __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
139 kcb->kprobe_status = kcb->prev_kprobe.status;
140}
141
142static void __kprobes set_current_kprobe(struct kprobe *p)
143{
144 __this_cpu_write(current_kprobe, p);
145}
146
147/*
148 * The D-flag (Debug mask) is set (masked) upon debug exception entry.
149 * Kprobes needs to clear (unmask) D-flag -ONLY- in case of recursive
150 * probe i.e. when probe hit from kprobe handler context upon
151 * executing the pre/post handlers. In this case we return with
152 * D-flag clear so that single-stepping can be carried-out.
153 *
154 * Leave D-flag set in all other cases.
155 */
156static void __kprobes
157spsr_set_debug_flag(struct pt_regs *regs, int mask)
158{
159 unsigned long spsr = regs->pstate;
160
161 if (mask)
162 spsr |= PSR_D_BIT;
163 else
164 spsr &= ~PSR_D_BIT;
165
166 regs->pstate = spsr;
167}
168
169/*
170 * Interrupts need to be disabled before single-step mode is set, and not
171 * reenabled until after single-step mode ends.
172 * Without disabling interrupt on local CPU, there is a chance of
173 * interrupt occurrence in the period of exception return and start of
174 * out-of-line single-step, that result in wrongly single stepping
175 * into the interrupt handler.
176 */
177static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
178 struct pt_regs *regs)
179{
180 kcb->saved_irqflag = regs->pstate;
181 regs->pstate |= PSR_I_BIT;
182}
183
184static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
185 struct pt_regs *regs)
186{
187 if (kcb->saved_irqflag & PSR_I_BIT)
188 regs->pstate |= PSR_I_BIT;
189 else
190 regs->pstate &= ~PSR_I_BIT;
191}
192
193static void __kprobes
194set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr)
195{
196 kcb->ss_ctx.ss_pending = true;
197 kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
198}
199
200static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb)
201{
202 kcb->ss_ctx.ss_pending = false;
203 kcb->ss_ctx.match_addr = 0;
204}
205
206static void __kprobes setup_singlestep(struct kprobe *p,
207 struct pt_regs *regs,
208 struct kprobe_ctlblk *kcb, int reenter)
209{
210 unsigned long slot;
211
212 if (reenter) {
213 save_previous_kprobe(kcb);
214 set_current_kprobe(p);
215 kcb->kprobe_status = KPROBE_REENTER;
216 } else {
217 kcb->kprobe_status = KPROBE_HIT_SS;
218 }
219
220 BUG_ON(!p->ainsn.insn);
221
222 /* prepare for single stepping */
223 slot = (unsigned long)p->ainsn.insn;
224
225 set_ss_context(kcb, slot); /* mark pending ss */
226
227 if (kcb->kprobe_status == KPROBE_REENTER)
228 spsr_set_debug_flag(regs, 0);
229
230 /* IRQs and single stepping do not mix well. */
231 kprobes_save_local_irqflag(kcb, regs);
232 kernel_enable_single_step(regs);
233 instruction_pointer_set(regs, slot);
234}
235
236static int __kprobes reenter_kprobe(struct kprobe *p,
237 struct pt_regs *regs,
238 struct kprobe_ctlblk *kcb)
239{
240 switch (kcb->kprobe_status) {
241 case KPROBE_HIT_SSDONE:
242 case KPROBE_HIT_ACTIVE:
243 kprobes_inc_nmissed_count(p);
244 setup_singlestep(p, regs, kcb, 1);
245 break;
246 case KPROBE_HIT_SS:
247 case KPROBE_REENTER:
248 pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr);
249 dump_kprobe(p);
250 BUG();
251 break;
252 default:
253 WARN_ON(1);
254 return 0;
255 }
256
257 return 1;
258}
259
260static void __kprobes
261post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
262{
263 struct kprobe *cur = kprobe_running();
264
265 if (!cur)
266 return;
267
268 /* return addr restore if non-branching insn */
269 if (cur->ainsn.restore != 0)
270 instruction_pointer_set(regs, cur->ainsn.restore);
271
272 /* restore back original saved kprobe variables and continue */
273 if (kcb->kprobe_status == KPROBE_REENTER) {
274 restore_previous_kprobe(kcb);
275 return;
276 }
277 /* call post handler */
278 kcb->kprobe_status = KPROBE_HIT_SSDONE;
279 if (cur->post_handler) {
280 /* post_handler can hit breakpoint and single step
281 * again, so we enable D-flag for recursive exception.
282 */
283 cur->post_handler(cur, regs, 0);
284 }
285
286 reset_current_kprobe();
287}
288
289int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
290{
291 struct kprobe *cur = kprobe_running();
292 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
293
294 switch (kcb->kprobe_status) {
295 case KPROBE_HIT_SS:
296 case KPROBE_REENTER:
297 /*
298 * We are here because the instruction being single
299 * stepped caused a page fault. We reset the current
300 * kprobe and the ip points back to the probe address
301 * and allow the page fault handler to continue as a
302 * normal page fault.
303 */
304 instruction_pointer_set(regs, (unsigned long) cur->addr);
305 if (!instruction_pointer(regs))
306 BUG();
307
308 kernel_disable_single_step();
309 if (kcb->kprobe_status == KPROBE_REENTER)
310 spsr_set_debug_flag(regs, 1);
311
312 if (kcb->kprobe_status == KPROBE_REENTER)
313 restore_previous_kprobe(kcb);
314 else
315 reset_current_kprobe();
316
317 break;
318 case KPROBE_HIT_ACTIVE:
319 case KPROBE_HIT_SSDONE:
320 /*
321 * We increment the nmissed count for accounting,
322 * we can also use npre/npostfault count for accounting
323 * these specific fault cases.
324 */
325 kprobes_inc_nmissed_count(cur);
326
327 /*
328 * We come here because instructions in the pre/post
329 * handler caused the page_fault, this could happen
330 * if handler tries to access user space by
331 * copy_from_user(), get_user() etc. Let the
332 * user-specified handler try to fix it first.
333 */
334 if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
335 return 1;
336
337 /*
338 * In case the user-specified fault handler returned
339 * zero, try to fix up.
340 */
341 if (fixup_exception(regs))
342 return 1;
343 }
344 return 0;
345}
346
347int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
348 unsigned long val, void *data)
349{
350 return NOTIFY_DONE;
351}
352
353static void __kprobes kprobe_handler(struct pt_regs *regs)
354{
355 struct kprobe *p, *cur_kprobe;
356 struct kprobe_ctlblk *kcb;
357 unsigned long addr = instruction_pointer(regs);
358
359 kcb = get_kprobe_ctlblk();
360 cur_kprobe = kprobe_running();
361
362 p = get_kprobe((kprobe_opcode_t *) addr);
363
364 if (p) {
365 if (cur_kprobe) {
366 if (reenter_kprobe(p, regs, kcb))
367 return;
368 } else {
369 /* Probe hit */
370 set_current_kprobe(p);
371 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
372
373 /*
374 * If we have no pre-handler or it returned 0, we
375 * continue with normal processing. If we have a
376 * pre-handler and it returned non-zero, it prepped
377 * for calling the break_handler below on re-entry,
378 * so get out doing nothing more here.
379 *
380 * pre_handler can hit a breakpoint and can step thru
381 * before return, keep PSTATE D-flag enabled until
382 * pre_handler return back.
383 */
384 if (!p->pre_handler || !p->pre_handler(p, regs)) {
385 setup_singlestep(p, regs, kcb, 0);
386 return;
387 }
388 }
389 } else if ((le32_to_cpu(*(kprobe_opcode_t *) addr) ==
390 BRK64_OPCODE_KPROBES) && cur_kprobe) {
391 /* We probably hit a jprobe. Call its break handler. */
392 if (cur_kprobe->break_handler &&
393 cur_kprobe->break_handler(cur_kprobe, regs)) {
394 setup_singlestep(cur_kprobe, regs, kcb, 0);
395 return;
396 }
397 }
398 /*
399 * The breakpoint instruction was removed right
400 * after we hit it. Another cpu has removed
401 * either a probepoint or a debugger breakpoint
402 * at this address. In either case, no further
403 * handling of this interrupt is appropriate.
404 * Return back to original instruction, and continue.
405 */
406}
407
408static int __kprobes
409kprobe_ss_hit(struct kprobe_ctlblk *kcb, unsigned long addr)
410{
411 if ((kcb->ss_ctx.ss_pending)
412 && (kcb->ss_ctx.match_addr == addr)) {
413 clear_ss_context(kcb); /* clear pending ss */
414 return DBG_HOOK_HANDLED;
415 }
416 /* not ours, kprobes should ignore it */
417 return DBG_HOOK_ERROR;
418}
419
420int __kprobes
421kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
422{
423 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
424 int retval;
425
426 /* return error if this is not our step */
427 retval = kprobe_ss_hit(kcb, instruction_pointer(regs));
428
429 if (retval == DBG_HOOK_HANDLED) {
430 kprobes_restore_local_irqflag(kcb, regs);
431 kernel_disable_single_step();
432
433 if (kcb->kprobe_status == KPROBE_REENTER)
434 spsr_set_debug_flag(regs, 1);
435
436 post_kprobe_handler(kcb, regs);
437 }
438
439 return retval;
440}
441
442int __kprobes
443kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr)
444{
445 kprobe_handler(regs);
446 return DBG_HOOK_HANDLED;
447}
448
449int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
450{
451 struct jprobe *jp = container_of(p, struct jprobe, kp);
452 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
453 long stack_ptr = kernel_stack_pointer(regs);
454
455 kcb->jprobe_saved_regs = *regs;
456 /*
457 * As Linus pointed out, gcc assumes that the callee
458 * owns the argument space and could overwrite it, e.g.
459 * tailcall optimization. So, to be absolutely safe
460 * we also save and restore enough stack bytes to cover
461 * the argument area.
462 */
463 memcpy(kcb->jprobes_stack, (void *)stack_ptr,
464 MIN_STACK_SIZE(stack_ptr));
465
466 instruction_pointer_set(regs, (unsigned long) jp->entry);
467 preempt_disable();
468 pause_graph_tracing();
469 return 1;
470}
471
472void __kprobes jprobe_return(void)
473{
474 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
475
476 /*
477 * Jprobe handler return by entering break exception,
478 * encoded same as kprobe, but with following conditions
479 * -a magic number in x0 to identify from rest of other kprobes.
480 * -restore stack addr to original saved pt_regs
481 */
482 asm volatile ("ldr x0, [%0]\n\t"
483 "mov sp, x0\n\t"
484 ".globl jprobe_return_break\n\t"
485 "jprobe_return_break:\n\t"
486 "brk %1\n\t"
487 :
488 : "r"(&kcb->jprobe_saved_regs.sp),
489 "I"(BRK64_ESR_KPROBES)
490 : "memory");
491}
492
493int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
494{
495 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
496 long stack_addr = kcb->jprobe_saved_regs.sp;
497 long orig_sp = kernel_stack_pointer(regs);
498 struct jprobe *jp = container_of(p, struct jprobe, kp);
499
500 if (instruction_pointer(regs) != (u64) jprobe_return_break)
501 return 0;
502
503 if (orig_sp != stack_addr) {
504 struct pt_regs *saved_regs =
505 (struct pt_regs *)kcb->jprobe_saved_regs.sp;
506 pr_err("current sp %lx does not match saved sp %lx\n",
507 orig_sp, stack_addr);
508 pr_err("Saved registers for jprobe %p\n", jp);
509 show_regs(saved_regs);
510 pr_err("Current registers\n");
511 show_regs(regs);
512 BUG();
513 }
514 unpause_graph_tracing();
515 *regs = kcb->jprobe_saved_regs;
516 memcpy((void *)stack_addr, kcb->jprobes_stack,
517 MIN_STACK_SIZE(stack_addr));
518 preempt_enable_no_resched();
519 return 1;
520}
521
522int __init arch_init_kprobes(void)
523{
524 return 0;
525}
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 435e820e898d..075ce322e82b 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -121,6 +121,7 @@ SECTIONS
121 TEXT_TEXT 121 TEXT_TEXT
122 SCHED_TEXT 122 SCHED_TEXT
123 LOCK_TEXT 123 LOCK_TEXT
124 KPROBES_TEXT
124 HYPERVISOR_TEXT 125 HYPERVISOR_TEXT
125 IDMAP_TEXT 126 IDMAP_TEXT
126 HIBERNATE_TEXT 127 HIBERNATE_TEXT
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 013e2cbe7924..2408e51d781f 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -41,6 +41,28 @@
41 41
42static const char *fault_name(unsigned int esr); 42static const char *fault_name(unsigned int esr);
43 43
44#ifdef CONFIG_KPROBES
45static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
46{
47 int ret = 0;
48
49 /* kprobe_running() needs smp_processor_id() */
50 if (!user_mode(regs)) {
51 preempt_disable();
52 if (kprobe_running() && kprobe_fault_handler(regs, esr))
53 ret = 1;
54 preempt_enable();
55 }
56
57 return ret;
58}
59#else
60static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
61{
62 return 0;
63}
64#endif
65
44/* 66/*
45 * Dump out the page tables associated with 'addr' in mm 'mm'. 67 * Dump out the page tables associated with 'addr' in mm 'mm'.
46 */ 68 */
@@ -259,6 +281,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
259 unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC; 281 unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
260 unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 282 unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
261 283
284 if (notify_page_fault(regs, esr))
285 return 0;
286
262 tsk = current; 287 tsk = current;
263 mm = tsk->mm; 288 mm = tsk->mm;
264 289
@@ -629,6 +654,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
629 654
630 return rv; 655 return rv;
631} 656}
657NOKPROBE_SYMBOL(do_debug_exception);
632 658
633#ifdef CONFIG_ARM64_PAN 659#ifdef CONFIG_ARM64_PAN
634void cpu_enable_pan(void *__unused) 660void cpu_enable_pan(void *__unused)