aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/kprobes.c')
-rw-r--r--arch/s390/kernel/kprobes.c19
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
35DEFINE_PER_CPU(struct kprobe *, current_kprobe); 36DEFINE_PER_CPU(struct kprobe *, current_kprobe);
36DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); 37DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -59,6 +60,8 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = {
59 60
60static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) 61static 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 }