diff options
Diffstat (limited to 'arch/s390/kernel/kprobes.c')
-rw-r--r-- | arch/s390/kernel/kprobes.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 0ce9fb245034..59a9c35c4598 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -26,11 +26,12 @@ | |||
26 | #include <linux/stop_machine.h> | 26 | #include <linux/stop_machine.h> |
27 | #include <linux/kdebug.h> | 27 | #include <linux/kdebug.h> |
28 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
29 | #include <asm/cacheflush.h> | ||
30 | #include <asm/sections.h> | ||
31 | #include <linux/module.h> | 29 | #include <linux/module.h> |
32 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
33 | #include <linux/hardirq.h> | 31 | #include <linux/hardirq.h> |
32 | #include <asm/cacheflush.h> | ||
33 | #include <asm/sections.h> | ||
34 | #include <asm/dis.h> | ||
34 | 35 | ||
35 | DEFINE_PER_CPU(struct kprobe *, current_kprobe); | 36 | DEFINE_PER_CPU(struct kprobe *, current_kprobe); |
36 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 37 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
@@ -59,6 +60,8 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = { | |||
59 | 60 | ||
60 | static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) | 61 | static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) |
61 | { | 62 | { |
63 | if (!is_known_insn((unsigned char *)insn)) | ||
64 | return -EINVAL; | ||
62 | switch (insn[0] >> 8) { | 65 | switch (insn[0] >> 8) { |
63 | case 0x0c: /* bassm */ | 66 | case 0x0c: /* bassm */ |
64 | case 0x0b: /* bsm */ | 67 | case 0x0b: /* bsm */ |
@@ -67,6 +70,11 @@ static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) | |||
67 | case 0xac: /* stnsm */ | 70 | case 0xac: /* stnsm */ |
68 | case 0xad: /* stosm */ | 71 | case 0xad: /* stosm */ |
69 | return -EINVAL; | 72 | return -EINVAL; |
73 | case 0xc6: | ||
74 | switch (insn[0] & 0x0f) { | ||
75 | case 0x00: /* exrl */ | ||
76 | return -EINVAL; | ||
77 | } | ||
70 | } | 78 | } |
71 | switch (insn[0]) { | 79 | switch (insn[0]) { |
72 | case 0x0101: /* pr */ | 80 | case 0x0101: /* pr */ |
@@ -180,7 +188,6 @@ static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn) | |||
180 | break; | 188 | break; |
181 | case 0xc6: | 189 | case 0xc6: |
182 | switch (insn[0] & 0x0f) { | 190 | switch (insn[0] & 0x0f) { |
183 | case 0x00: /* exrl */ | ||
184 | case 0x02: /* pfdrl */ | 191 | case 0x02: /* pfdrl */ |
185 | case 0x04: /* cghrl */ | 192 | case 0x04: /* cghrl */ |
186 | case 0x05: /* chrl */ | 193 | case 0x05: /* chrl */ |
@@ -204,7 +211,7 @@ static void __kprobes copy_instruction(struct kprobe *p) | |||
204 | s64 disp, new_disp; | 211 | s64 disp, new_disp; |
205 | u64 addr, new_addr; | 212 | u64 addr, new_addr; |
206 | 213 | ||
207 | memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2); | 214 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); |
208 | if (!is_insn_relative_long(p->ainsn.insn)) | 215 | if (!is_insn_relative_long(p->ainsn.insn)) |
209 | return; | 216 | return; |
210 | /* | 217 | /* |
@@ -248,7 +255,7 @@ static int __kprobes s390_get_insn_slot(struct kprobe *p) | |||
248 | p->ainsn.insn = NULL; | 255 | p->ainsn.insn = NULL; |
249 | if (is_kernel_addr(p->addr)) | 256 | if (is_kernel_addr(p->addr)) |
250 | p->ainsn.insn = get_dmainsn_slot(); | 257 | p->ainsn.insn = get_dmainsn_slot(); |
251 | if (is_module_addr(p->addr)) | 258 | else if (is_module_addr(p->addr)) |
252 | p->ainsn.insn = get_insn_slot(); | 259 | p->ainsn.insn = get_insn_slot(); |
253 | return p->ainsn.insn ? 0 : -ENOMEM; | 260 | return p->ainsn.insn ? 0 : -ENOMEM; |
254 | } | 261 | } |
@@ -604,7 +611,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
604 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; | 611 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; |
605 | 612 | ||
606 | if (fixup & FIXUP_BRANCH_NOT_TAKEN) { | 613 | if (fixup & FIXUP_BRANCH_NOT_TAKEN) { |
607 | int ilen = ((p->ainsn.insn[0] >> 14) + 3) & -2; | 614 | int ilen = insn_length(p->ainsn.insn[0] >> 8); |
608 | if (ip - (unsigned long) p->ainsn.insn == ilen) | 615 | if (ip - (unsigned long) p->ainsn.insn == ilen) |
609 | ip = (unsigned long) p->addr + ilen; | 616 | ip = (unsigned long) p->addr + ilen; |
610 | } | 617 | } |