[FIX] US instrumentation running process
[kernel/swap-modules.git] / uprobe / arch / asm-x86 / swap_uprobes.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/uprobe/arch/asm-x86/swap_uprobes.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2006-2010
20  *
21  * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
22  *              Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces.
23  * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
24  *
25  */
26
27 #include <linux/kdebug.h>
28 #include <kprobe/arch/asm/dbi_kprobes.h>
29 #include <uprobe/swap_uprobes.h>
30 #include <uprobe/arch/asm/swap_uprobes.h>
31 #include <kprobe/dbi_insn_slots.h>
32
33 struct uprobe_ctlblk {
34         unsigned long flags;
35         struct kprobe *p;
36 };
37
38 static DEFINE_PER_CPU(struct uprobe_ctlblk, ucb) = { 0, NULL };
39
40 static struct kprobe *get_current_probe(void)
41 {
42         return __get_cpu_var(ucb).p;
43 }
44
45 static void set_current_probe(struct kprobe *p)
46 {
47         __get_cpu_var(ucb).p = p;
48 }
49
50 static void reset_current_probe(void)
51 {
52         set_current_probe(NULL);
53 }
54
55 static void save_current_flags(struct pt_regs *regs)
56 {
57         __get_cpu_var(ucb).flags = regs->EREG(flags);
58 }
59
60 static void restore_current_flags(struct pt_regs *regs)
61 {
62         regs->EREG(flags) &= ~IF_MASK;
63         regs->EREG(flags) |= __get_cpu_var(ucb).flags & IF_MASK;
64 }
65
66 int arch_prepare_uprobe(struct uprobe *up)
67 {
68         int ret = 0;
69         struct kprobe *p = up2kp(up);
70         struct task_struct *task = up->task;
71         u8 *tramp = up->atramp.tramp;
72
73         if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
74                                  tramp, MAX_INSN_SIZE))
75                 panic("failed to read memory %p!\n", p->addr);
76
77         tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
78
79         /* TODO: remove dual info */
80         p->opcode = tramp[0];
81
82         p->ainsn.boostable = can_boost(tramp) ? 0 : -1;
83
84         return ret;
85 }
86
87 int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
88 {
89         struct uprobe *up = container_of(p, struct uprobe, kp);
90         struct ujprobe *jp = container_of(up, struct ujprobe, up);
91         kprobe_pre_entry_handler_t pre_entry = (kprobe_pre_entry_handler_t)jp->pre_entry;
92         entry_point_t entry = (entry_point_t)jp->entry;
93         unsigned long args[6];
94
95         /* FIXME some user space apps crash if we clean interrupt bit */
96         //regs->EREG(flags) &= ~IF_MASK;
97 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
98         trace_hardirqs_off();
99 #endif
100
101         /* read first 6 args from stack */
102         if (!read_proc_vm_atomic(current, regs->EREG(sp) + 4, args, sizeof(args)))
103                 panic("failed to read user space func arguments %lx!\n", regs->EREG(sp) + 4);
104
105         if (pre_entry)
106                 p->ss_addr = (kprobe_opcode_t *)pre_entry(jp->priv_arg, regs);
107
108         if (entry)
109                 entry(args[0], args[1], args[2], args[3], args[4], args[5]);
110         else
111                 arch_ujprobe_return();
112
113         return 0;
114 }
115
116 void arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
117 {
118         /* Replace the return addr with trampoline addr */
119         unsigned long ra = (unsigned long)(ri->rp->up.kp.ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
120
121         if (!read_proc_vm_atomic(current, regs->EREG(sp), &(ri->ret_addr), sizeof(ri->ret_addr)))
122                 panic("failed to read user space func ra %lx!\n", regs->EREG(sp));
123
124         if (!write_proc_vm_atomic(current, regs->EREG(sp), &ra, sizeof(ra)))
125                 panic("failed to write user space func ra %lx!\n", regs->EREG(sp));
126 }
127
128 unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
129 {
130         return (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
131 }
132
133 void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
134 {
135         regs->EREG(ip) = orig_ret_addr;
136 }
137
138 static void set_user_jmp_op(void *from, void *to)
139 {
140         struct __arch_jmp_op
141         {
142                 char op;
143                 long raddr;
144         } __attribute__ ((packed)) jop;
145
146         jop.raddr = (long)(to) - ((long)(from) + 5);
147         jop.op = RELATIVEJUMP_INSTRUCTION;
148
149         if (!write_proc_vm_atomic(current, (unsigned long)from, &jop, sizeof(jop)))
150                 panic("failed to write jump opcode to user space %p!\n", from);
151 }
152
153 static void resume_execution(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
154 {
155         unsigned long *tos, tos_dword = 0;
156         unsigned long copy_eip = (unsigned long)p->ainsn.insn;
157         unsigned long orig_eip = (unsigned long)p->addr;
158         kprobe_opcode_t insns[2];
159
160         regs->EREG(flags) &= ~TF_MASK;
161
162         tos = (unsigned long *)&tos_dword;
163         if (!read_proc_vm_atomic(current, regs->EREG(sp), &tos_dword, sizeof(tos_dword)))
164                 panic("failed to read dword from top of the user space stack %lx!\n", regs->EREG(sp));
165
166         if (!read_proc_vm_atomic(current, (unsigned long)p->ainsn.insn, insns, 2 * sizeof(kprobe_opcode_t)))
167                 panic("failed to read first 2 opcodes of instruction copy from user space %p!\n", p->ainsn.insn);
168
169         switch (insns[0]) {
170                 case 0x9c:              /* pushfl */
171                         *tos &= ~(TF_MASK | IF_MASK);
172                         *tos |= flags & (TF_MASK | IF_MASK);
173                         break;
174                 case 0xc2:              /* iret/ret/lret */
175                 case 0xc3:
176                 case 0xca:
177                 case 0xcb:
178                 case 0xcf:
179                 case 0xea:              /* jmp absolute -- eip is correct */
180                         /* eip is already adjusted, no more changes required */
181                         p->ainsn.boostable = 1;
182                         goto no_change;
183                 case 0xe8:              /* call relative - Fix return addr */
184                         *tos = orig_eip + (*tos - copy_eip);
185                         break;
186                 case 0x9a:              /* call absolute -- same as call absolute, indirect */
187                         *tos = orig_eip + (*tos - copy_eip);
188
189                         if (!write_proc_vm_atomic(current, regs->EREG (sp), &tos_dword, sizeof(tos_dword)))
190                                 panic("failed to write dword to top of the user space stack %lx!\n", regs->EREG (sp));
191
192                         goto no_change;
193                 case 0xff:
194                         if ((insns[1] & 0x30) == 0x10) {
195                                 /*
196                                  * call absolute, indirect
197                                  * Fix return addr; eip is correct.
198                                  * But this is not boostable
199                                  */
200                                 *tos = orig_eip + (*tos - copy_eip);
201
202                                 if (!write_proc_vm_atomic(current, regs->EREG(sp), &tos_dword, sizeof(tos_dword)))
203                                         panic("failed to write dword to top of the user space stack %lx!\n", regs->EREG(sp));
204
205                                 goto no_change;
206                         } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */
207                                    ((insns[1] & 0x31) == 0x21)) {
208                                 /* jmp far, absolute indirect */
209                                 /* eip is correct. And this is boostable */
210                                 p->ainsn.boostable = 1;
211                                 goto no_change;
212                         }
213                 default:
214                         break;
215         }
216
217         if (!write_proc_vm_atomic(current, regs->EREG(sp), &tos_dword, sizeof(tos_dword)))
218                 panic("failed to write dword to top of the user space stack %lx!\n", regs->EREG(sp));
219
220         if (p->ainsn.boostable == 0) {
221                 if ((regs->EREG(ip) > copy_eip) && (regs->EREG(ip) - copy_eip) + 5 < MAX_INSN_SIZE) {
222                         /*
223                          * These instructions can be executed directly if it
224                          * jumps back to correct address.
225                          */
226                         set_user_jmp_op((void *) regs->EREG(ip), (void *)orig_eip + (regs->EREG(ip) - copy_eip));
227                         p->ainsn.boostable = 1;
228                 } else {
229                         p->ainsn.boostable = -1;
230                 }
231         }
232
233         regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
234
235 no_change:
236         return;
237 }
238
239 static int make_trampoline(struct uprobe *up)
240 {
241         struct kprobe *p = up2kp(up);
242         struct task_struct *task = up->task;
243         void *tramp;
244
245         tramp = alloc_insn_slot(up->sm);
246         if (tramp == 0) {
247                 printk("trampoline out of memory\n");
248                 return -ENOMEM;
249         }
250
251         if (!write_proc_vm_atomic(task, (unsigned long)tramp,
252                                   up->atramp.tramp,
253                                   sizeof(up->atramp.tramp))) {
254                 free_insn_slot(up->sm, tramp);
255                 panic("failed to write memory %p!\n", tramp);
256                 return -EINVAL;
257         }
258
259         p->ainsn.insn = tramp;
260
261         return 0;
262 }
263
264 static int uprobe_handler(struct pt_regs *regs)
265 {
266         struct kprobe *p;
267         kprobe_opcode_t *addr;
268         struct task_struct *task = current;
269         pid_t tgid = task->tgid;
270
271         save_current_flags(regs);
272
273         addr = (kprobe_opcode_t *)(regs->EREG(ip) - sizeof(kprobe_opcode_t));
274         p = get_ukprobe(addr, tgid);
275
276         if (p == NULL) {
277                 void *tramp_addr = (void *)addr - UPROBES_TRAMP_RET_BREAK_IDX;
278
279                 p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
280                 if (p == NULL) {
281                         printk("no_uprobe\n");
282                         return 0;
283                 }
284
285                 trampoline_uprobe_handler(p, regs);
286                 return 1;
287         } else {
288                 if (p->ainsn.insn == NULL) {
289                         struct uprobe *up = kp2up(p);
290
291                         make_trampoline(up);
292
293                         /* for uretprobe */
294                         add_uprobe_table(p);
295                 }
296
297                 if (!p->pre_handler || !p->pre_handler(p, regs)) {
298                         if (p->ainsn.boostable == 1 && !p->post_handler) {
299                                 regs->EREG(ip) = (unsigned long)p->ainsn.insn;
300                                 return 1;
301                         }
302
303                         prepare_singlestep(p, regs);
304                 }
305         }
306
307         set_current_probe(p);
308
309         return 1;
310 }
311
312 static int post_uprobe_handler(struct pt_regs *regs)
313 {
314         struct kprobe *p = get_current_probe();
315         unsigned long flags = __get_cpu_var(ucb).flags;
316
317         if (p == NULL)
318                 return 0;
319
320         resume_execution(p, regs, flags);
321         restore_current_flags(regs);
322
323         reset_current_probe();
324
325         return 1;
326 }
327
328 static int uprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data)
329 {
330         struct die_args *args = (struct die_args *)data;
331         int ret = NOTIFY_DONE;
332
333         if (args->regs && !user_mode_vm(args->regs))
334                 return ret;
335
336         switch (val) {
337 #ifdef CONFIG_KPROBES
338                 case DIE_INT3:
339 #else
340                 case DIE_TRAP:
341 #endif
342                         if (uprobe_handler(args->regs))
343                                 ret = NOTIFY_STOP;
344                         break;
345                 case DIE_DEBUG:
346                         if (post_uprobe_handler(args->regs))
347                                 ret = NOTIFY_STOP;
348                         break;
349                 default:
350                         break;
351         }
352
353         return ret;
354 }
355
356 static struct notifier_block uprobe_exceptions_nb = {
357         .notifier_call = uprobe_exceptions_notify,
358         .priority = INT_MAX
359 };
360
361 int swap_arch_init_uprobes(void)
362 {
363         return register_die_notifier(&uprobe_exceptions_nb);
364 }
365
366 void swap_arch_exit_uprobes(void)
367 {
368         unregister_die_notifier(&uprobe_exceptions_nb);
369 }
370