diff options
-rw-r--r-- | arch/s390/include/asm/kprobes.h | 4 | ||||
-rw-r--r-- | arch/s390/kernel/kprobes.c | 144 |
2 files changed, 140 insertions, 8 deletions
diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h index dcf6948a875c..4176dfe0fba1 100644 --- a/arch/s390/include/asm/kprobes.h +++ b/arch/s390/include/asm/kprobes.h | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/ptrace.h> | 31 | #include <linux/ptrace.h> |
32 | #include <linux/percpu.h> | 32 | #include <linux/percpu.h> |
33 | 33 | ||
34 | #define __ARCH_WANT_KPROBES_INSN_SLOT | ||
35 | |||
34 | struct pt_regs; | 36 | struct pt_regs; |
35 | struct kprobe; | 37 | struct kprobe; |
36 | 38 | ||
@@ -57,7 +59,7 @@ typedef u16 kprobe_opcode_t; | |||
57 | /* Architecture specific copy of original instruction */ | 59 | /* Architecture specific copy of original instruction */ |
58 | struct arch_specific_insn { | 60 | struct arch_specific_insn { |
59 | /* copy of original instruction */ | 61 | /* copy of original instruction */ |
60 | kprobe_opcode_t insn[MAX_INSN_SIZE]; | 62 | kprobe_opcode_t *insn; |
61 | }; | 63 | }; |
62 | 64 | ||
63 | struct prev_kprobe { | 65 | struct prev_kprobe { |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index adbbe7f1cb0d..0ce9fb245034 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -37,6 +37,26 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | |||
37 | 37 | ||
38 | struct kretprobe_blackpoint kretprobe_blacklist[] = { }; | 38 | struct kretprobe_blackpoint kretprobe_blacklist[] = { }; |
39 | 39 | ||
40 | DEFINE_INSN_CACHE_OPS(dmainsn); | ||
41 | |||
42 | static void *alloc_dmainsn_page(void) | ||
43 | { | ||
44 | return (void *)__get_free_page(GFP_KERNEL | GFP_DMA); | ||
45 | } | ||
46 | |||
47 | static void free_dmainsn_page(void *page) | ||
48 | { | ||
49 | free_page((unsigned long)page); | ||
50 | } | ||
51 | |||
52 | struct kprobe_insn_cache kprobe_dmainsn_slots = { | ||
53 | .mutex = __MUTEX_INITIALIZER(kprobe_dmainsn_slots.mutex), | ||
54 | .alloc = alloc_dmainsn_page, | ||
55 | .free = free_dmainsn_page, | ||
56 | .pages = LIST_HEAD_INIT(kprobe_dmainsn_slots.pages), | ||
57 | .insn_size = MAX_INSN_SIZE, | ||
58 | }; | ||
59 | |||
40 | static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) | 60 | static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) |
41 | { | 61 | { |
42 | switch (insn[0] >> 8) { | 62 | switch (insn[0] >> 8) { |
@@ -100,9 +120,8 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn) | |||
100 | fixup |= FIXUP_RETURN_REGISTER; | 120 | fixup |= FIXUP_RETURN_REGISTER; |
101 | break; | 121 | break; |
102 | case 0xc0: | 122 | case 0xc0: |
103 | if ((insn[0] & 0x0f) == 0x00 || /* larl */ | 123 | if ((insn[0] & 0x0f) == 0x05) /* brasl */ |
104 | (insn[0] & 0x0f) == 0x05) /* brasl */ | 124 | fixup |= FIXUP_RETURN_REGISTER; |
105 | fixup |= FIXUP_RETURN_REGISTER; | ||
106 | break; | 125 | break; |
107 | case 0xeb: | 126 | case 0xeb: |
108 | switch (insn[2] & 0xff) { | 127 | switch (insn[2] & 0xff) { |
@@ -134,18 +153,128 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn) | |||
134 | return fixup; | 153 | return fixup; |
135 | } | 154 | } |
136 | 155 | ||
156 | static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn) | ||
157 | { | ||
158 | /* Check if we have a RIL-b or RIL-c format instruction which | ||
159 | * we need to modify in order to avoid instruction emulation. */ | ||
160 | switch (insn[0] >> 8) { | ||
161 | case 0xc0: | ||
162 | if ((insn[0] & 0x0f) == 0x00) /* larl */ | ||
163 | return true; | ||
164 | break; | ||
165 | case 0xc4: | ||
166 | switch (insn[0] & 0x0f) { | ||
167 | case 0x02: /* llhrl */ | ||
168 | case 0x04: /* lghrl */ | ||
169 | case 0x05: /* lhrl */ | ||
170 | case 0x06: /* llghrl */ | ||
171 | case 0x07: /* sthrl */ | ||
172 | case 0x08: /* lgrl */ | ||
173 | case 0x0b: /* stgrl */ | ||
174 | case 0x0c: /* lgfrl */ | ||
175 | case 0x0d: /* lrl */ | ||
176 | case 0x0e: /* llgfrl */ | ||
177 | case 0x0f: /* strl */ | ||
178 | return true; | ||
179 | } | ||
180 | break; | ||
181 | case 0xc6: | ||
182 | switch (insn[0] & 0x0f) { | ||
183 | case 0x00: /* exrl */ | ||
184 | case 0x02: /* pfdrl */ | ||
185 | case 0x04: /* cghrl */ | ||
186 | case 0x05: /* chrl */ | ||
187 | case 0x06: /* clghrl */ | ||
188 | case 0x07: /* clhrl */ | ||
189 | case 0x08: /* cgrl */ | ||
190 | case 0x0a: /* clgrl */ | ||
191 | case 0x0c: /* cgfrl */ | ||
192 | case 0x0d: /* crl */ | ||
193 | case 0x0e: /* clgfrl */ | ||
194 | case 0x0f: /* clrl */ | ||
195 | return true; | ||
196 | } | ||
197 | break; | ||
198 | } | ||
199 | return false; | ||
200 | } | ||
201 | |||
202 | static void __kprobes copy_instruction(struct kprobe *p) | ||
203 | { | ||
204 | s64 disp, new_disp; | ||
205 | u64 addr, new_addr; | ||
206 | |||
207 | memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2); | ||
208 | if (!is_insn_relative_long(p->ainsn.insn)) | ||
209 | return; | ||
210 | /* | ||
211 | * For pc-relative instructions in RIL-b or RIL-c format patch the | ||
212 | * RI2 displacement field. We have already made sure that the insn | ||
213 | * slot for the patched instruction is within the same 2GB area | ||
214 | * as the original instruction (either kernel image or module area). | ||
215 | * Therefore the new displacement will always fit. | ||
216 | */ | ||
217 | disp = *(s32 *)&p->ainsn.insn[1]; | ||
218 | addr = (u64)(unsigned long)p->addr; | ||
219 | new_addr = (u64)(unsigned long)p->ainsn.insn; | ||
220 | new_disp = ((addr + (disp * 2)) - new_addr) / 2; | ||
221 | *(s32 *)&p->ainsn.insn[1] = new_disp; | ||
222 | } | ||
223 | |||
224 | static inline int is_kernel_addr(void *addr) | ||
225 | { | ||
226 | return addr < (void *)_end; | ||
227 | } | ||
228 | |||
229 | static inline int is_module_addr(void *addr) | ||
230 | { | ||
231 | #ifdef CONFIG_64BIT | ||
232 | BUILD_BUG_ON(MODULES_LEN > (1UL << 31)); | ||
233 | if (addr < (void *)MODULES_VADDR) | ||
234 | return 0; | ||
235 | if (addr > (void *)MODULES_END) | ||
236 | return 0; | ||
237 | #endif | ||
238 | return 1; | ||
239 | } | ||
240 | |||
241 | static int __kprobes s390_get_insn_slot(struct kprobe *p) | ||
242 | { | ||
243 | /* | ||
244 | * Get an insn slot that is within the same 2GB area like the original | ||
245 | * instruction. That way instructions with a 32bit signed displacement | ||
246 | * field can be patched and executed within the insn slot. | ||
247 | */ | ||
248 | p->ainsn.insn = NULL; | ||
249 | if (is_kernel_addr(p->addr)) | ||
250 | p->ainsn.insn = get_dmainsn_slot(); | ||
251 | if (is_module_addr(p->addr)) | ||
252 | p->ainsn.insn = get_insn_slot(); | ||
253 | return p->ainsn.insn ? 0 : -ENOMEM; | ||
254 | } | ||
255 | |||
256 | static void __kprobes s390_free_insn_slot(struct kprobe *p) | ||
257 | { | ||
258 | if (!p->ainsn.insn) | ||
259 | return; | ||
260 | if (is_kernel_addr(p->addr)) | ||
261 | free_dmainsn_slot(p->ainsn.insn, 0); | ||
262 | else | ||
263 | free_insn_slot(p->ainsn.insn, 0); | ||
264 | p->ainsn.insn = NULL; | ||
265 | } | ||
266 | |||
137 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 267 | int __kprobes arch_prepare_kprobe(struct kprobe *p) |
138 | { | 268 | { |
139 | if ((unsigned long) p->addr & 0x01) | 269 | if ((unsigned long) p->addr & 0x01) |
140 | return -EINVAL; | 270 | return -EINVAL; |
141 | |||
142 | /* Make sure the probe isn't going on a difficult instruction */ | 271 | /* Make sure the probe isn't going on a difficult instruction */ |
143 | if (is_prohibited_opcode(p->addr)) | 272 | if (is_prohibited_opcode(p->addr)) |
144 | return -EINVAL; | 273 | return -EINVAL; |
145 | 274 | if (s390_get_insn_slot(p)) | |
275 | return -ENOMEM; | ||
146 | p->opcode = *p->addr; | 276 | p->opcode = *p->addr; |
147 | memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2); | 277 | copy_instruction(p); |
148 | |||
149 | return 0; | 278 | return 0; |
150 | } | 279 | } |
151 | 280 | ||
@@ -186,6 +315,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) | |||
186 | 315 | ||
187 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 316 | void __kprobes arch_remove_kprobe(struct kprobe *p) |
188 | { | 317 | { |
318 | s390_free_insn_slot(p); | ||
189 | } | 319 | } |
190 | 320 | ||
191 | static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb, | 321 | static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb, |