diff options
author | Masami Hiramatsu <mhiramat@kernel.org> | 2017-03-29 01:00:25 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-04-12 03:23:45 -0400 |
commit | 804dec5bda9b4fcdab5f67fe61db4a0498af5221 (patch) | |
tree | 21c03ef2a8d261208348be56333abfb9b9d036ab | |
parent | 17880e4d5777df4770081ecf0750471cda57f86b (diff) |
kprobes/x86: Do not modify singlestep buffer while resuming
Do not modify singlestep execution buffer (kprobe.ainsn.insn)
while resuming from single-stepping, instead, modifies
the buffer to add a jump back instruction at preparing
buffer.
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: David S . Miller <davem@davemloft.net>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ye Xiaolong <xiaolong.ye@intel.com>
Link: http://lkml.kernel.org/r/149076361560.22469.1610155860343077495.stgit@devbox
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/kprobes/core.c | 42 |
1 files changed, 20 insertions, 22 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 6327f95832a0..a654054eae7e 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -399,23 +399,36 @@ int __copy_instruction(u8 *dest, u8 *src) | |||
399 | return length; | 399 | return length; |
400 | } | 400 | } |
401 | 401 | ||
402 | /* Prepare reljump right after instruction to boost */ | ||
403 | static void prepare_boost(struct kprobe *p, int length) | ||
404 | { | ||
405 | if (can_boost(p->ainsn.insn, p->addr) && | ||
406 | MAX_INSN_SIZE - length >= RELATIVEJUMP_SIZE) { | ||
407 | /* | ||
408 | * These instructions can be executed directly if it | ||
409 | * jumps back to correct address. | ||
410 | */ | ||
411 | synthesize_reljump(p->ainsn.insn + length, p->addr + length); | ||
412 | p->ainsn.boostable = 1; | ||
413 | } else { | ||
414 | p->ainsn.boostable = -1; | ||
415 | } | ||
416 | } | ||
417 | |||
402 | static int arch_copy_kprobe(struct kprobe *p) | 418 | static int arch_copy_kprobe(struct kprobe *p) |
403 | { | 419 | { |
404 | int ret; | 420 | int len; |
405 | 421 | ||
406 | /* Copy an instruction with recovering if other optprobe modifies it.*/ | 422 | /* Copy an instruction with recovering if other optprobe modifies it.*/ |
407 | ret = __copy_instruction(p->ainsn.insn, p->addr); | 423 | len = __copy_instruction(p->ainsn.insn, p->addr); |
408 | if (!ret) | 424 | if (!len) |
409 | return -EINVAL; | 425 | return -EINVAL; |
410 | 426 | ||
411 | /* | 427 | /* |
412 | * __copy_instruction can modify the displacement of the instruction, | 428 | * __copy_instruction can modify the displacement of the instruction, |
413 | * but it doesn't affect boostable check. | 429 | * but it doesn't affect boostable check. |
414 | */ | 430 | */ |
415 | if (can_boost(p->ainsn.insn, p->addr)) | 431 | prepare_boost(p, len); |
416 | p->ainsn.boostable = 0; | ||
417 | else | ||
418 | p->ainsn.boostable = -1; | ||
419 | 432 | ||
420 | /* Check whether the instruction modifies Interrupt Flag or not */ | 433 | /* Check whether the instruction modifies Interrupt Flag or not */ |
421 | p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn); | 434 | p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn); |
@@ -878,21 +891,6 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs, | |||
878 | break; | 891 | break; |
879 | } | 892 | } |
880 | 893 | ||
881 | if (p->ainsn.boostable == 0) { | ||
882 | if ((regs->ip > copy_ip) && | ||
883 | (regs->ip - copy_ip) + 5 < MAX_INSN_SIZE) { | ||
884 | /* | ||
885 | * These instructions can be executed directly if it | ||
886 | * jumps back to correct address. | ||
887 | */ | ||
888 | synthesize_reljump((void *)regs->ip, | ||
889 | (void *)orig_ip + (regs->ip - copy_ip)); | ||
890 | p->ainsn.boostable = 1; | ||
891 | } else { | ||
892 | p->ainsn.boostable = -1; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | regs->ip += orig_ip - copy_ip; | 894 | regs->ip += orig_ip - copy_ip; |
897 | 895 | ||
898 | no_change: | 896 | no_change: |