diff options
Diffstat (limited to 'arch/x86/kernel/kprobes.c')
| -rw-r--r-- | arch/x86/kernel/kprobes.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 675879b65ce6..1bfb6cf4dd55 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
| @@ -126,16 +126,22 @@ static void __kprobes synthesize_reljump(void *from, void *to) | |||
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /* | 128 | /* |
| 129 | * Check for the REX prefix which can only exist on X86_64 | 129 | * Skip the prefixes of the instruction. |
| 130 | * X86_32 always returns 0 | ||
| 131 | */ | 130 | */ |
| 132 | static int __kprobes is_REX_prefix(kprobe_opcode_t *insn) | 131 | static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn) |
| 133 | { | 132 | { |
| 133 | insn_attr_t attr; | ||
| 134 | |||
| 135 | attr = inat_get_opcode_attribute((insn_byte_t)*insn); | ||
| 136 | while (inat_is_legacy_prefix(attr)) { | ||
| 137 | insn++; | ||
| 138 | attr = inat_get_opcode_attribute((insn_byte_t)*insn); | ||
| 139 | } | ||
| 134 | #ifdef CONFIG_X86_64 | 140 | #ifdef CONFIG_X86_64 |
| 135 | if ((*insn & 0xf0) == 0x40) | 141 | if (inat_is_rex_prefix(attr)) |
| 136 | return 1; | 142 | insn++; |
| 137 | #endif | 143 | #endif |
| 138 | return 0; | 144 | return insn; |
| 139 | } | 145 | } |
| 140 | 146 | ||
| 141 | /* | 147 | /* |
| @@ -272,6 +278,9 @@ static int __kprobes can_probe(unsigned long paddr) | |||
| 272 | */ | 278 | */ |
| 273 | static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) | 279 | static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) |
| 274 | { | 280 | { |
| 281 | /* Skip prefixes */ | ||
| 282 | insn = skip_prefixes(insn); | ||
| 283 | |||
| 275 | switch (*insn) { | 284 | switch (*insn) { |
| 276 | case 0xfa: /* cli */ | 285 | case 0xfa: /* cli */ |
| 277 | case 0xfb: /* sti */ | 286 | case 0xfb: /* sti */ |
| @@ -280,13 +289,6 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) | |||
| 280 | return 1; | 289 | return 1; |
| 281 | } | 290 | } |
| 282 | 291 | ||
| 283 | /* | ||
| 284 | * on X86_64, 0x40-0x4f are REX prefixes so we need to look | ||
| 285 | * at the next byte instead.. but of course not recurse infinitely | ||
| 286 | */ | ||
| 287 | if (is_REX_prefix(insn)) | ||
| 288 | return is_IF_modifier(++insn); | ||
| 289 | |||
| 290 | return 0; | 292 | return 0; |
| 291 | } | 293 | } |
| 292 | 294 | ||
| @@ -803,9 +805,8 @@ static void __kprobes resume_execution(struct kprobe *p, | |||
| 803 | unsigned long orig_ip = (unsigned long)p->addr; | 805 | unsigned long orig_ip = (unsigned long)p->addr; |
| 804 | kprobe_opcode_t *insn = p->ainsn.insn; | 806 | kprobe_opcode_t *insn = p->ainsn.insn; |
| 805 | 807 | ||
| 806 | /*skip the REX prefix*/ | 808 | /* Skip prefixes */ |
| 807 | if (is_REX_prefix(insn)) | 809 | insn = skip_prefixes(insn); |
| 808 | insn++; | ||
| 809 | 810 | ||
| 810 | regs->flags &= ~X86_EFLAGS_TF; | 811 | regs->flags &= ~X86_EFLAGS_TF; |
| 811 | switch (*insn) { | 812 | switch (*insn) { |
