[FIX] remove panic() from uprobe (x86)
[kernel/swap-modules.git] / uprobe / arch / x86 / swap-asm / swap_uprobes.c
1 /**
2  * uprobe/arch/asm-x86/swap_uprobes.c
3  * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
4  * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
5  * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
6  * separating core and arch parts
7  *
8  * @section LICENSE
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  *
24  * @section COPYRIGHT
25  *
26  * Copyright (C) Samsung Electronics, 2006-2010
27  *
28  * @section DESCRIPTION
29  *
30  * Arch-dependent uprobe interface implementation for x86.
31  */
32
33
34 #include <linux/kdebug.h>
35
36 #include <kprobe/swap_slots.h>
37 #include <uprobe/swap_uprobes.h>
38
39 #include "swap_uprobes.h"
40
41
42 /**
43  * @struct uprobe_ctlblk
44  * @brief Uprobe control block
45  */
46 struct uprobe_ctlblk {
47         unsigned long flags;            /**< Flags */
48         struct kprobe *p;               /**< Pointer to the uprobe's kprobe */
49 };
50
51 static unsigned long trampoline_addr(struct uprobe *up)
52 {
53         return (unsigned long)(up->kp.ainsn.insn +
54                                UPROBES_TRAMP_RET_BREAK_IDX);
55 }
56
57 static DEFINE_PER_CPU(struct uprobe_ctlblk, ucb) = { 0, NULL };
58
59 static struct kprobe *get_current_probe(void)
60 {
61         return __get_cpu_var(ucb).p;
62 }
63
64 static void set_current_probe(struct kprobe *p)
65 {
66         __get_cpu_var(ucb).p = p;
67 }
68
69 static void reset_current_probe(void)
70 {
71         set_current_probe(NULL);
72 }
73
74 static void save_current_flags(struct pt_regs *regs)
75 {
76         __get_cpu_var(ucb).flags = regs->EREG(flags);
77 }
78
79 static void restore_current_flags(struct pt_regs *regs)
80 {
81         regs->EREG(flags) &= ~IF_MASK;
82         regs->EREG(flags) |= __get_cpu_var(ucb).flags & IF_MASK;
83 }
84
85 /**
86  * @brief Prepares uprobe for x86.
87  *
88  * @param up Pointer to the uprobe.
89  * @return 0 on success,\n
90  * -1 on error.
91  */
92 int arch_prepare_uprobe(struct uprobe *up)
93 {
94         struct kprobe *p = up2kp(up);
95         struct task_struct *task = up->task;
96         u8 *tramp = up->atramp.tramp;
97         enum { call_relative_opcode = 0xe8 };
98
99         if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
100                                  tramp, MAX_INSN_SIZE)) {
101                 printk("failed to read memory %p!\n", p->addr);
102                 return -EINVAL;
103         }
104         /* TODO: this is a workaround */
105         if (tramp[0] == call_relative_opcode) {
106                 printk(KERN_INFO "cannot install probe: 1st instruction is call\n");
107                 return -1;
108         }
109
110         tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
111
112         /* TODO: remove dual info */
113         p->opcode = tramp[0];
114
115         p->ainsn.boostable = swap_can_boost(tramp) ? 0 : -1;
116
117         p->ainsn.insn = swap_slot_alloc(up->sm);
118         if (p->ainsn.insn == NULL) {
119                 printk(KERN_INFO "trampoline out of memory\n");
120                 return -ENOMEM;
121         }
122
123         if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn,
124                                   tramp, sizeof(up->atramp.tramp))) {
125                 swap_slot_free(up->sm, p->ainsn.insn);
126                 printk("failed to write memory %p!\n", tramp);
127                 return -EINVAL;
128         }
129
130         return 0;
131 }
132
133 /**
134  * @brief Jump pre-handler.
135  *
136  * @param p Pointer to the uprobe's kprobe.
137  * @param regs Pointer to CPU register data.
138  * @return 0.
139  */
140 int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
141 {
142         struct uprobe *up = container_of(p, struct uprobe, kp);
143         struct ujprobe *jp = container_of(up, struct ujprobe, up);
144         kprobe_pre_entry_handler_t pre_entry =
145                 (kprobe_pre_entry_handler_t)jp->pre_entry;
146         entry_point_t entry = (entry_point_t)jp->entry;
147         unsigned long args[6];
148
149         /* FIXME some user space apps crash if we clean interrupt bit */
150         /* regs->EREG(flags) &= ~IF_MASK; */
151 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
152         trace_hardirqs_off();
153 #endif
154
155         /* read first 6 args from stack */
156         if (!read_proc_vm_atomic(current, regs->EREG(sp) + 4,
157                                  args, sizeof(args)))
158                 printk("failed to read user space func arguments %lx!\n",
159                        regs->EREG(sp) + 4);
160
161         if (pre_entry)
162                 p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)
163                                                  pre_entry(jp->priv_arg, regs);
164
165         if (entry)
166                 entry(args[0], args[1], args[2], args[3], args[4], args[5]);
167         else
168                 arch_ujprobe_return();
169
170         return 0;
171 }
172
173 /**
174  * @brief Prepares uretprobe for x86.
175  *
176  * @param ri Pointer to the uretprobe instance.
177  * @param regs Pointer to CPU register data.
178  * @return Void.
179  */
180 int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
181 {
182         /* Replace the return addr with trampoline addr */
183         unsigned long ra = trampoline_addr(&ri->rp->up);
184         ri->sp = (kprobe_opcode_t *)regs->sp;
185
186         if (!read_proc_vm_atomic(current, regs->EREG(sp), &(ri->ret_addr),
187                                  sizeof(ri->ret_addr))) {
188                 printk("failed to read user space func ra %lx addr=%p!\n",
189                                 regs->EREG(sp), ri->rp->up.kp.addr);
190                 return -EINVAL;
191         }
192
193         if (!write_proc_vm_atomic(current, regs->EREG(sp), &ra, sizeof(ra))) {
194                 printk("failed to write user space func ra %lx!\n", regs->EREG(sp));
195                 return -EINVAL;
196         }
197
198         add_uprobe_table(&ri->rp->up.kp);
199
200         return 0;
201 }
202
203 /**
204  * @brief Disarms uretprobe on x86 arch.
205  *
206  * @param ri Pointer to the uretprobe instance.
207  * @param task Pointer to the task for which the probe.
208  * @return 0 on success,\n
209  * negative error code on error.
210  */
211 int arch_disarm_urp_inst(struct uretprobe_instance *ri,
212                          struct task_struct *task)
213 {
214         int len;
215         unsigned long ret_addr;
216         unsigned long sp = (unsigned long)ri->sp;
217         unsigned long tramp_addr = trampoline_addr(&ri->rp->up);
218         len = read_proc_vm_atomic(task, sp, &ret_addr, sizeof(ret_addr));
219         if (len != sizeof(ret_addr)) {
220                 printk(KERN_INFO "---> %s (%d/%d): failed to read stack from %08lx\n",
221                        task->comm, task->tgid, task->pid, sp);
222                 return -EFAULT;
223         }
224
225         if (tramp_addr == ret_addr) {
226                 len = write_proc_vm_atomic(task, sp, &ri->ret_addr,
227                                            sizeof(ri->ret_addr));
228                 if (len != sizeof(ri->ret_addr)) {
229                         printk(KERN_INFO "---> %s (%d/%d): failed to write "
230                                "orig_ret_addr to %08lx",
231                                task->comm, task->tgid, task->pid, sp);
232                         return -EFAULT;
233                 }
234         } else {
235                 printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at sp = %08lx\n",
236                        task->comm, task->tgid, task->pid, sp);
237                 return -ENOENT;
238         }
239
240         return 0;
241 }
242
243 /**
244  * @brief Gets trampoline address.
245  *
246  * @param p Pointer to the uprobe's kprobe.
247  * @param regs Pointer to CPU register data.
248  * @return Trampoline address.
249  */
250 unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
251 {
252         return trampoline_addr(kp2up(p));
253 }
254
255 /**
256  * @brief Restores return address.
257  *
258  * @param orig_ret_addr Original return address.
259  * @param regs Pointer to CPU register data.
260  * @return Void.
261  */
262 void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
263 {
264         regs->EREG(ip) = orig_ret_addr;
265 }
266
267 /**
268  * @brief Removes uprobe.
269  *
270  * @param up Pointer to the target uprobe.
271  * @return Void.
272  */
273 void arch_remove_uprobe(struct uprobe *up)
274 {
275         struct kprobe *p = up2kp(up);
276
277         swap_slot_free(up->sm, p->ainsn.insn);
278 }
279
280 static void set_user_jmp_op(void *from, void *to)
281 {
282         struct __arch_jmp_op {
283                 char op;
284                 long raddr;
285         } __packed jop;
286
287         jop.raddr = (long)(to) - ((long)(from) + 5);
288         jop.op = RELATIVEJUMP_INSTRUCTION;
289
290         if (!write_proc_vm_atomic(current, (unsigned long)from, &jop,
291                                   sizeof(jop)))
292                 printk("failed to write jump opcode to user space %p\n", from);
293 }
294
295 static void resume_execution(struct kprobe *p,
296                              struct pt_regs *regs,
297                              unsigned long flags)
298 {
299         unsigned long *tos, tos_dword = 0;
300         unsigned long copy_eip = (unsigned long)p->ainsn.insn;
301         unsigned long orig_eip = (unsigned long)p->addr;
302         kprobe_opcode_t insns[2];
303
304         regs->EREG(flags) &= ~TF_MASK;
305
306         tos = (unsigned long *)&tos_dword;
307         if (!read_proc_vm_atomic(current, regs->EREG(sp), &tos_dword,
308                                  sizeof(tos_dword))) {
309                 printk("failed to read dword from top of the user space stack "
310                        "%lx!\n", regs->EREG(sp));
311                 return;
312         }
313
314         if (!read_proc_vm_atomic(current, (unsigned long)p->ainsn.insn, insns,
315                                  2 * sizeof(kprobe_opcode_t))) {
316                 printk("failed to read first 2 opcodes of instruction copy "
317                        "from user space %p!\n", p->ainsn.insn);
318                 return;
319         }
320
321         switch (insns[0]) {
322         case 0x9c: /* pushfl */
323                 *tos &= ~(TF_MASK | IF_MASK);
324                 *tos |= flags & (TF_MASK | IF_MASK);
325                 break;
326         case 0xc2: /* iret/ret/lret */
327         case 0xc3:
328         case 0xca:
329         case 0xcb:
330         case 0xcf:
331         case 0xea: /* jmp absolute -- eip is correct */
332                 /* eip is already adjusted, no more changes required */
333                 p->ainsn.boostable = 1;
334                 goto no_change;
335         case 0xe8: /* call relative - Fix return addr */
336                 *tos = orig_eip + (*tos - copy_eip);
337                 break;
338         case 0x9a: /* call absolute -- same as call absolute, indirect */
339                 *tos = orig_eip + (*tos - copy_eip);
340
341                 if (!write_proc_vm_atomic(current,
342                                           regs->EREG(sp),
343                                           &tos_dword,
344                                           sizeof(tos_dword))) {
345                         printk("failed to write dword to top of the"
346                                " user space stack %lx!\n", regs->EREG(sp));
347                         return;
348                 }
349
350                 goto no_change;
351         case 0xff:
352                 if ((insns[1] & 0x30) == 0x10) {
353                         /*
354                          * call absolute, indirect
355                          * Fix return addr; eip is correct.
356                          * But this is not boostable
357                          */
358                         *tos = orig_eip + (*tos - copy_eip);
359
360                         if (!write_proc_vm_atomic(current, regs->EREG(sp),
361                                                   &tos_dword,
362                                                   sizeof(tos_dword))) {
363                                 printk("failed to write dword to top of the "
364                                        "user space stack %lx!\n",
365                                        regs->EREG(sp));
366                                 return;
367                         }
368
369                         goto no_change;
370                 } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
371                                                            * indirect */
372                            ((insns[1] & 0x31) == 0x21)) {
373                         /* jmp far, absolute indirect */
374                         /* eip is correct. And this is boostable */
375                         p->ainsn.boostable = 1;
376                         goto no_change;
377                 }
378         case 0xf3:
379                 if (insns[1] == 0xc3)
380                         /* repz ret special handling: no more changes */
381                         goto no_change;
382                 break;
383         default:
384                 break;
385         }
386
387         if (!write_proc_vm_atomic(current, regs->EREG(sp), &tos_dword,
388                                   sizeof(tos_dword))) {
389                 printk("failed to write dword to top of the user space stack "
390                        "%lx!\n", regs->EREG(sp));
391                 return;
392         }
393
394         if (p->ainsn.boostable == 0) {
395                 if ((regs->EREG(ip) > copy_eip) && (regs->EREG(ip) - copy_eip) +
396                     5 < MAX_INSN_SIZE) {
397                         /*
398                          * These instructions can be executed directly if it
399                          * jumps back to correct address.
400                          */
401                         set_user_jmp_op((void *) regs->EREG(ip),
402                                         (void *)orig_eip +
403                                         (regs->EREG(ip) - copy_eip));
404                         p->ainsn.boostable = 1;
405                 } else {
406                         p->ainsn.boostable = -1;
407                 }
408         }
409
410         regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
411
412 no_change:
413         return;
414 }
415
416 static int uprobe_handler(struct pt_regs *regs)
417 {
418         struct kprobe *p;
419         kprobe_opcode_t *addr;
420         struct task_struct *task = current;
421         pid_t tgid = task->tgid;
422
423         save_current_flags(regs);
424
425         addr = (kprobe_opcode_t *)(regs->EREG(ip) - sizeof(kprobe_opcode_t));
426         p = get_ukprobe(addr, tgid);
427
428         if (p == NULL) {
429                 void *tramp_addr = (void *)addr - UPROBES_TRAMP_RET_BREAK_IDX;
430
431                 p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
432                 if (p == NULL) {
433                         printk(KERN_INFO "no_uprobe\n");
434                         return 0;
435                 }
436
437                 trampoline_uprobe_handler(p, regs);
438                 return 1;
439         } else {
440                 if (!p->pre_handler || !p->pre_handler(p, regs)) {
441
442                         if (p->ainsn.boostable == 1 && !p->post_handler) {
443                                 if (p->ss_addr[smp_processor_id()]) {
444                                         regs->EREG(ip) = (unsigned long)p->ss_addr[smp_processor_id()];
445                                         p->ss_addr[smp_processor_id()] = NULL;
446                                 } else {
447                                         regs->EREG(ip) = (unsigned long)p->ainsn.insn;
448                                 }
449                                 return 1;
450                         }
451
452                         prepare_singlestep(p, regs);
453                 }
454         }
455
456         set_current_probe(p);
457
458         return 1;
459 }
460
461 static int post_uprobe_handler(struct pt_regs *regs)
462 {
463         struct kprobe *p = get_current_probe();
464         unsigned long flags = __get_cpu_var(ucb).flags;
465
466         if (p == NULL)
467                 return 0;
468
469         resume_execution(p, regs, flags);
470         restore_current_flags(regs);
471
472         reset_current_probe();
473
474         return 1;
475 }
476
477 static int uprobe_exceptions_notify(struct notifier_block *self,
478                                     unsigned long val, void *data)
479 {
480         struct die_args *args = (struct die_args *)data;
481         int ret = NOTIFY_DONE;
482
483         if (args->regs == NULL || !user_mode_vm(args->regs))
484                 return ret;
485
486         switch (val) {
487 #ifdef CONFIG_KPROBES
488         case DIE_INT3:
489 #else
490         case DIE_TRAP:
491 #endif
492                 if (uprobe_handler(args->regs))
493                         ret = NOTIFY_STOP;
494                 break;
495         case DIE_DEBUG:
496                 if (post_uprobe_handler(args->regs))
497                         ret = NOTIFY_STOP;
498                 break;
499         default:
500                 break;
501         }
502
503         return ret;
504 }
505
506 static struct notifier_block uprobe_exceptions_nb = {
507         .notifier_call = uprobe_exceptions_notify,
508         .priority = INT_MAX
509 };
510
511 /**
512  * @brief Registers notify.
513  *
514  * @return register_die_notifier result.
515  */
516 int swap_arch_init_uprobes(void)
517 {
518         return register_die_notifier(&uprobe_exceptions_nb);
519 }
520
521 /**
522  * @brief Unregisters notify.
523  *
524  * @return Void.
525  */
526 void swap_arch_exit_uprobes(void)
527 {
528         unregister_die_notifier(&uprobe_exceptions_nb);
529 }
530