]>
Commit | Line | Data |
---|---|---|
819edbe1 GKH |
1 | From 804dec5bda9b4fcdab5f67fe61db4a0498af5221 Mon Sep 17 00:00:00 2001 |
2 | From: Masami Hiramatsu <mhiramat@kernel.org> | |
3 | Date: Wed, 29 Mar 2017 14:00:25 +0900 | |
4 | Subject: kprobes/x86: Do not modify singlestep buffer while resuming | |
5 | ||
6 | From: Masami Hiramatsu <mhiramat@kernel.org> | |
7 | ||
8 | commit 804dec5bda9b4fcdab5f67fe61db4a0498af5221 upstream. | |
9 | ||
10 | Do not modify singlestep execution buffer (kprobe.ainsn.insn) | |
11 | while resuming from single-stepping, instead, modifies | |
12 | the buffer to add a jump back instruction at preparing | |
13 | buffer. | |
14 | ||
15 | Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> | |
16 | Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com> | |
17 | Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> | |
18 | Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> | |
19 | Cc: Borislav Petkov <bp@alien8.de> | |
20 | Cc: Brian Gerst <brgerst@gmail.com> | |
21 | Cc: David S . Miller <davem@davemloft.net> | |
22 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
23 | Cc: H. Peter Anvin <hpa@zytor.com> | |
24 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
25 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
26 | Cc: Peter Zijlstra <peterz@infradead.org> | |
27 | Cc: Thomas Gleixner <tglx@linutronix.de> | |
28 | Cc: Ye Xiaolong <xiaolong.ye@intel.com> | |
29 | Link: http://lkml.kernel.org/r/149076361560.22469.1610155860343077495.stgit@devbox | |
30 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
31 | Reviewed-by: "Steven Rostedt (VMware)" <rostedt@goodmis.org> | |
32 | Signed-off-by: Alexey Makhalov <amakhalov@vmware.com> | |
33 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
34 | --- | |
35 | arch/x86/kernel/kprobes/core.c | 42 +++++++++++++++++++---------------------- | |
36 | 1 file changed, 20 insertions(+), 22 deletions(-) | |
37 | ||
38 | --- a/arch/x86/kernel/kprobes/core.c | |
39 | +++ b/arch/x86/kernel/kprobes/core.c | |
40 | @@ -411,25 +411,38 @@ void free_insn_page(void *page) | |
41 | module_memfree(page); | |
42 | } | |
43 | ||
44 | +/* Prepare reljump right after instruction to boost */ | |
45 | +static void prepare_boost(struct kprobe *p, int length) | |
46 | +{ | |
47 | + if (can_boost(p->ainsn.insn, p->addr) && | |
48 | + MAX_INSN_SIZE - length >= RELATIVEJUMP_SIZE) { | |
49 | + /* | |
50 | + * These instructions can be executed directly if it | |
51 | + * jumps back to correct address. | |
52 | + */ | |
53 | + synthesize_reljump(p->ainsn.insn + length, p->addr + length); | |
54 | + p->ainsn.boostable = 1; | |
55 | + } else { | |
56 | + p->ainsn.boostable = -1; | |
57 | + } | |
58 | +} | |
59 | + | |
60 | static int arch_copy_kprobe(struct kprobe *p) | |
61 | { | |
62 | - int ret; | |
63 | + int len; | |
64 | ||
65 | set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1); | |
66 | ||
67 | /* Copy an instruction with recovering if other optprobe modifies it.*/ | |
68 | - ret = __copy_instruction(p->ainsn.insn, p->addr); | |
69 | - if (!ret) | |
70 | + len = __copy_instruction(p->ainsn.insn, p->addr); | |
71 | + if (!len) | |
72 | return -EINVAL; | |
73 | ||
74 | /* | |
75 | * __copy_instruction can modify the displacement of the instruction, | |
76 | * but it doesn't affect boostable check. | |
77 | */ | |
78 | - if (can_boost(p->ainsn.insn, p->addr)) | |
79 | - p->ainsn.boostable = 0; | |
80 | - else | |
81 | - p->ainsn.boostable = -1; | |
82 | + prepare_boost(p, len); | |
83 | ||
84 | set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1); | |
85 | ||
86 | @@ -894,21 +907,6 @@ static void resume_execution(struct kpro | |
87 | break; | |
88 | } | |
89 | ||
90 | - if (p->ainsn.boostable == 0) { | |
91 | - if ((regs->ip > copy_ip) && | |
92 | - (regs->ip - copy_ip) + 5 < MAX_INSN_SIZE) { | |
93 | - /* | |
94 | - * These instructions can be executed directly if it | |
95 | - * jumps back to correct address. | |
96 | - */ | |
97 | - synthesize_reljump((void *)regs->ip, | |
98 | - (void *)orig_ip + (regs->ip - copy_ip)); | |
99 | - p->ainsn.boostable = 1; | |
100 | - } else { | |
101 | - p->ainsn.boostable = -1; | |
102 | - } | |
103 | - } | |
104 | - | |
105 | regs->ip += orig_ip - copy_ip; | |
106 | ||
107 | no_change: |