]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
1c2e80c5445aa11eee1849e062ece2584bd36127
[thirdparty/kernel/stable-queue.git] /
1 From 7ee31a3aa8f490c6507bc4294df6b70bed1c593e Mon Sep 17 00:00:00 2001
2 From: Jean-Philippe Brucker <jean-philippe@linaro.org>
3 Date: Tue, 3 Nov 2020 14:49:01 +0100
4 Subject: arm64: kprobes: Use BRK instead of single-step when executing instructions out-of-line
5
6 From: Jean-Philippe Brucker <jean-philippe@linaro.org>
7
8 commit 7ee31a3aa8f490c6507bc4294df6b70bed1c593e upstream.
9
10 Commit 36dadef23fcc ("kprobes: Init kprobes in early_initcall") enabled
11 using kprobes from early_initcall. Unfortunately at this point the
12 hardware debug infrastructure is not operational. The OS lock may still
13 be locked, and the hardware watchpoints may have unknown values when
14 kprobe enables debug monitors to single-step instructions.
15
16 Rather than using hardware single-step, append a BRK instruction after
17 the instruction to be executed out-of-line.
18
19 Fixes: 36dadef23fcc ("kprobes: Init kprobes in early_initcall")
20 Suggested-by: Will Deacon <will@kernel.org>
21 Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
22 Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
23 Link: https://lore.kernel.org/r/20201103134900.337243-1-jean-philippe@linaro.org
24 Signed-off-by: Will Deacon <will@kernel.org>
25 Signed-off-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
26 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
27 ---
28 arch/arm64/include/asm/brk-imm.h | 2
29 arch/arm64/include/asm/debug-monitors.h | 1
30 arch/arm64/include/asm/kprobes.h | 2
31 arch/arm64/kernel/probes/kprobes.c | 69 ++++++++++----------------------
32 4 files changed, 27 insertions(+), 47 deletions(-)
33
34 --- a/arch/arm64/include/asm/brk-imm.h
35 +++ b/arch/arm64/include/asm/brk-imm.h
36 @@ -10,6 +10,7 @@
37 * #imm16 values used for BRK instruction generation
38 * 0x004: for installing kprobes
39 * 0x005: for installing uprobes
40 + * 0x006: for kprobe software single-step
41 * Allowed values for kgdb are 0x400 - 0x7ff
42 * 0x100: for triggering a fault on purpose (reserved)
43 * 0x400: for dynamic BRK instruction
44 @@ -19,6 +20,7 @@
45 */
46 #define KPROBES_BRK_IMM 0x004
47 #define UPROBES_BRK_IMM 0x005
48 +#define KPROBES_BRK_SS_IMM 0x006
49 #define FAULT_BRK_IMM 0x100
50 #define KGDB_DYN_DBG_BRK_IMM 0x400
51 #define KGDB_COMPILED_DBG_BRK_IMM 0x401
52 --- a/arch/arm64/include/asm/debug-monitors.h
53 +++ b/arch/arm64/include/asm/debug-monitors.h
54 @@ -53,6 +53,7 @@
55
56 /* kprobes BRK opcodes with ESR encoding */
57 #define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (KPROBES_BRK_IMM << 5))
58 +#define BRK64_OPCODE_KPROBES_SS (AARCH64_BREAK_MON | (KPROBES_BRK_SS_IMM << 5))
59 /* uprobes BRK opcodes with ESR encoding */
60 #define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (UPROBES_BRK_IMM << 5))
61
62 --- a/arch/arm64/include/asm/kprobes.h
63 +++ b/arch/arm64/include/asm/kprobes.h
64 @@ -16,7 +16,7 @@
65 #include <linux/percpu.h>
66
67 #define __ARCH_WANT_KPROBES_INSN_SLOT
68 -#define MAX_INSN_SIZE 1
69 +#define MAX_INSN_SIZE 2
70
71 #define flush_insn_slot(p) do { } while (0)
72 #define kretprobe_blacklist_size 0
73 --- a/arch/arm64/kernel/probes/kprobes.c
74 +++ b/arch/arm64/kernel/probes/kprobes.c
75 @@ -36,25 +36,16 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kpr
76 static void __kprobes
77 post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
78
79 -static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
80 -{
81 - void *addrs[1];
82 - u32 insns[1];
83 -
84 - addrs[0] = addr;
85 - insns[0] = opcode;
86 -
87 - return aarch64_insn_patch_text(addrs, insns, 1);
88 -}
89 -
90 static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
91 {
92 + kprobe_opcode_t *addr = p->ainsn.api.insn;
93 + void *addrs[] = {addr, addr + 1};
94 + u32 insns[] = {p->opcode, BRK64_OPCODE_KPROBES_SS};
95 +
96 /* prepare insn slot */
97 - patch_text(p->ainsn.api.insn, p->opcode);
98 + aarch64_insn_patch_text(addrs, insns, 2);
99
100 - flush_icache_range((uintptr_t) (p->ainsn.api.insn),
101 - (uintptr_t) (p->ainsn.api.insn) +
102 - MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
103 + flush_icache_range((uintptr_t)addr, (uintptr_t)(addr + MAX_INSN_SIZE));
104
105 /*
106 * Needs restoring of return address after stepping xol.
107 @@ -134,13 +125,18 @@ void *alloc_insn_page(void)
108 /* arm kprobe: install breakpoint in text */
109 void __kprobes arch_arm_kprobe(struct kprobe *p)
110 {
111 - patch_text(p->addr, BRK64_OPCODE_KPROBES);
112 + void *addr = p->addr;
113 + u32 insn = BRK64_OPCODE_KPROBES;
114 +
115 + aarch64_insn_patch_text(&addr, &insn, 1);
116 }
117
118 /* disarm kprobe: remove breakpoint from text */
119 void __kprobes arch_disarm_kprobe(struct kprobe *p)
120 {
121 - patch_text(p->addr, p->opcode);
122 + void *addr = p->addr;
123 +
124 + aarch64_insn_patch_text(&addr, &p->opcode, 1);
125 }
126
127 void __kprobes arch_remove_kprobe(struct kprobe *p)
128 @@ -169,20 +165,15 @@ static void __kprobes set_current_kprobe
129 }
130
131 /*
132 - * Interrupts need to be disabled before single-step mode is set, and not
133 - * reenabled until after single-step mode ends.
134 - * Without disabling interrupt on local CPU, there is a chance of
135 - * interrupt occurrence in the period of exception return and start of
136 - * out-of-line single-step, that result in wrongly single stepping
137 - * into the interrupt handler.
138 + * Mask all of DAIF while executing the instruction out-of-line, to keep things
139 + * simple and avoid nesting exceptions. Interrupts do have to be disabled since
140 + * the kprobe state is per-CPU and doesn't get migrated.
141 */
142 static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
143 struct pt_regs *regs)
144 {
145 kcb->saved_irqflag = regs->pstate & DAIF_MASK;
146 - regs->pstate |= PSR_I_BIT;
147 - /* Unmask PSTATE.D for enabling software step exceptions. */
148 - regs->pstate &= ~PSR_D_BIT;
149 + regs->pstate |= DAIF_MASK;
150 }
151
152 static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
153 @@ -225,10 +216,7 @@ static void __kprobes setup_singlestep(s
154 slot = (unsigned long)p->ainsn.api.insn;
155
156 set_ss_context(kcb, slot); /* mark pending ss */
157 -
158 - /* IRQs and single stepping do not mix well. */
159 kprobes_save_local_irqflag(kcb, regs);
160 - kernel_enable_single_step(regs);
161 instruction_pointer_set(regs, slot);
162 } else {
163 /* insn simulation */
164 @@ -279,12 +267,8 @@ post_kprobe_handler(struct kprobe_ctlblk
165 }
166 /* call post handler */
167 kcb->kprobe_status = KPROBE_HIT_SSDONE;
168 - if (cur->post_handler) {
169 - /* post_handler can hit breakpoint and single step
170 - * again, so we enable D-flag for recursive exception.
171 - */
172 + if (cur->post_handler)
173 cur->post_handler(cur, regs, 0);
174 - }
175
176 reset_current_kprobe();
177 }
178 @@ -308,8 +292,6 @@ int __kprobes kprobe_fault_handler(struc
179 if (!instruction_pointer(regs))
180 BUG();
181
182 - kernel_disable_single_step();
183 -
184 if (kcb->kprobe_status == KPROBE_REENTER)
185 restore_previous_kprobe(kcb);
186 else
187 @@ -371,10 +353,6 @@ static void __kprobes kprobe_handler(str
188 * pre-handler and it returned non-zero, it will
189 * modify the execution path and no need to single
190 * stepping. Let's just reset current kprobe and exit.
191 - *
192 - * pre_handler can hit a breakpoint and can step thru
193 - * before return, keep PSTATE D-flag enabled until
194 - * pre_handler return back.
195 */
196 if (!p->pre_handler || !p->pre_handler(p, regs)) {
197 setup_singlestep(p, regs, kcb, 0);
198 @@ -405,7 +383,7 @@ kprobe_ss_hit(struct kprobe_ctlblk *kcb,
199 }
200
201 static int __kprobes
202 -kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
203 +kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned int esr)
204 {
205 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
206 int retval;
207 @@ -415,16 +393,15 @@ kprobe_single_step_handler(struct pt_reg
208
209 if (retval == DBG_HOOK_HANDLED) {
210 kprobes_restore_local_irqflag(kcb, regs);
211 - kernel_disable_single_step();
212 -
213 post_kprobe_handler(kcb, regs);
214 }
215
216 return retval;
217 }
218
219 -static struct step_hook kprobes_step_hook = {
220 - .fn = kprobe_single_step_handler,
221 +static struct break_hook kprobes_break_ss_hook = {
222 + .imm = KPROBES_BRK_SS_IMM,
223 + .fn = kprobe_breakpoint_ss_handler,
224 };
225
226 static int __kprobes
227 @@ -568,7 +545,7 @@ int __kprobes arch_trampoline_kprobe(str
228 int __init arch_init_kprobes(void)
229 {
230 register_kernel_break_hook(&kprobes_break_hook);
231 - register_kernel_step_hook(&kprobes_step_hook);
232 + register_kernel_break_hook(&kprobes_break_ss_hook);
233
234 return 0;
235 }