[FIX] unregister_uretprobe() for x86
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 2 Dec 2013 12:28:17 +0000 (16:28 +0400)
committerGerrit Code Review <gerrit@gerrit.vlan144.tizendev.org>
Mon, 2 Dec 2013 13:46:47 +0000 (13:46 +0000)
Change-Id: Ib4cfaee5d742e8d5d0c65da320e0d0707493ac69
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
uprobe/arch/asm-arm/swap_uprobes.c
uprobe/arch/asm-arm/swap_uprobes.h
uprobe/arch/asm-x86/swap_uprobes.c
uprobe/arch/asm-x86/swap_uprobes.h
uprobe/swap_uprobes.c

index 0fd22e6..526b6a7 100644 (file)
@@ -712,6 +712,83 @@ void arch_prepare_uretprobe(struct uretprobe_instance *ri,
        }
 }
 
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task)
+{
+       unsigned long *tramp;
+       unsigned long *sp = (unsigned long *)((long)ri->sp & ~1);
+       unsigned long *stack = sp - RETPROBE_STACK_DEPTH + 1;
+       unsigned long *found = NULL;
+       unsigned long *buf[RETPROBE_STACK_DEPTH];
+       int i, retval;
+
+       /* Understand function mode */
+       if ((long)ri->sp & 1) {
+               tramp = (unsigned long *)
+                       ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b);
+       } else {
+               tramp = (unsigned long *)(ri->rp->up.kp.ainsn.insn +
+                                         UPROBES_TRAMP_RET_BREAK_IDX);
+       }
+
+       retval = read_proc_vm_atomic(task, (unsigned long)stack,
+                                    buf, sizeof(buf));
+       if (retval != sizeof(buf)) {
+               printk("---> %s (%d/%d): failed to read stack from %08lx\n",
+                      task->comm, task->tgid, task->pid,
+                      (unsigned long)stack);
+               retval = -EFAULT;
+               goto out;
+       }
+
+       /* search the stack from the bottom */
+       for (i = RETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
+               if (buf[i] == tramp) {
+                       found = stack + i;
+                       break;
+               }
+       }
+
+       if (found) {
+               printk("---> %s (%d/%d): trampoline found at "
+                      "%08lx (%08lx /%+d) - %p\n",
+                      task->comm, task->tgid, task->pid,
+                      (unsigned long)found, (unsigned long)sp,
+                      found - sp, ri->rp->up.kp.addr);
+               retval = write_proc_vm_atomic(task, (unsigned long)found,
+                                             &ri->ret_addr,
+                                             sizeof(ri->ret_addr));
+               if (retval != sizeof(ri->ret_addr)) {
+                       printk("---> %s (%d/%d): failed to write value "
+                              "to %08lx",
+                              task->comm, task->tgid, task->pid, (unsigned long)found);
+                       retval = -EFAULT;
+               } else {
+                       retval = 0;
+               }
+       } else {
+               struct pt_regs *uregs = task_pt_regs(ri->task);
+               unsigned long ra = dbi_get_ret_addr(uregs);
+               if (ra == (unsigned long)tramp) {
+                       printk("---> %s (%d/%d): trampoline found at "
+                              "lr = %08lx - %p\n",
+                              task->comm, task->tgid, task->pid,
+                              ra, ri->rp->up.kp.addr);
+                       dbi_set_ret_addr(uregs, (unsigned long)ri->ret_addr);
+                       retval = 0;
+               } else {
+                       printk("---> %s (%d/%d): trampoline NOT found at "
+                              "sp = %08lx, lr = %08lx - %p\n",
+                              task->comm, task->tgid, task->pid,
+                              (unsigned long)sp, ra, ri->rp->up.kp.addr);
+                       retval = -ENOENT;
+               }
+       }
+
+out:
+       return retval;
+}
+
 int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct uprobe *up = container_of(p, struct uprobe, kp);
index 8dce806..74f4cb3 100644 (file)
@@ -70,6 +70,8 @@ static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
 
 void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
 void arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task);
 
 unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
 void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
index 7a5015d..2b9635b 100644 (file)
@@ -35,6 +35,12 @@ struct uprobe_ctlblk {
         struct kprobe *p;
 };
 
+static unsigned long trampoline_addr(struct uprobe *up)
+{
+       return (unsigned long)(up->kp.ainsn.insn +
+                              UPROBES_TRAMP_RET_BREAK_IDX);
+}
+
 static DEFINE_PER_CPU(struct uprobe_ctlblk, ucb) = { 0, NULL };
 
 static struct kprobe *get_current_probe(void)
@@ -116,7 +122,8 @@ int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
 void arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
 {
        /* Replace the return addr with trampoline addr */
-       unsigned long ra = (unsigned long)(ri->rp->up.kp.ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
+       unsigned long ra = trampoline_addr(&ri->rp->up);
+       ri->sp = (kprobe_opcode_t *)regs->sp;
 
        if (!read_proc_vm_atomic(current, regs->EREG(sp), &(ri->ret_addr), sizeof(ri->ret_addr)))
                panic("failed to read user space func ra %lx!\n", regs->EREG(sp));
@@ -125,9 +132,41 @@ void arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
                panic("failed to write user space func ra %lx!\n", regs->EREG(sp));
 }
 
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task)
+{
+       int len;
+       unsigned long ret_addr;
+       unsigned long sp = (unsigned long)ri->sp;
+       unsigned long tramp_addr = trampoline_addr(&ri->rp->up);
+       len = read_proc_vm_atomic(task, sp, &ret_addr, sizeof(ret_addr));
+       if (len != sizeof(ret_addr)) {
+               printk("---> %s (%d/%d): failed to read stack from %08lx\n",
+                      task->comm, task->tgid, task->pid, sp);
+               return -EFAULT;
+       }
+
+       if (tramp_addr == ret_addr) {
+               len = write_proc_vm_atomic(task, sp, &ri->ret_addr,
+                                          sizeof(ri->ret_addr));
+               if (len != sizeof(ri->ret_addr)) {
+                       printk("---> %s (%d/%d): failed to write "
+                              "orig_ret_addr to %08lx",
+                              task->comm, task->tgid, task->pid, sp);
+                       return -EFAULT;
+               }
+       } else {
+               printk("---> %s (%d/%d): trampoline NOT found at sp = %08lx\n",
+                      task->comm, task->tgid, task->pid, sp);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
 unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
 {
-       return (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
+       return trampoline_addr(kp2up(p));
 }
 
 void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
index 8e34225..f51ab2a 100644 (file)
@@ -76,6 +76,8 @@ static inline int arch_opcode_analysis_uretprobe(struct uretprobe *rp)
 }
 
 void arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
+int arch_disarm_urp_inst(struct uretprobe_instance *ri,
+                        struct task_struct *task);
 unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
 void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
 
index fdb5677..7bd0931 100644 (file)
@@ -756,75 +756,6 @@ int dbi_register_uretprobe(struct uretprobe *rp)
        return 0;
 }
 
-int dbi_disarm_urp_inst(struct uretprobe_instance *ri, struct task_struct *rm_task)
-{
-       struct task_struct *task = rm_task ? rm_task : ri->task;
-       unsigned long *tramp;
-       unsigned long *sp = (unsigned long *)((long)ri->sp & ~1);
-       unsigned long *stack = sp - RETPROBE_STACK_DEPTH + 1;
-       unsigned long *found = NULL;
-       unsigned long *buf[RETPROBE_STACK_DEPTH];
-       int i, retval;
-
-       /* Understand function mode */
-       if ((long)ri->sp & 1) {
-               tramp = (unsigned long *)
-                       ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b);
-       } else {
-               tramp = (unsigned long *)
-                       (ri->rp->up.kp.ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
-       }
-
-       retval = read_proc_vm_atomic(task, (unsigned long)stack, buf, sizeof(buf));
-       if (retval != sizeof(buf)) {
-               printk("---> %s (%d/%d): failed to read stack from %08lx\n",
-                       task->comm, task->tgid, task->pid, (unsigned long)stack);
-               retval = -EFAULT;
-               goto out;
-       }
-
-       /* search the stack from the bottom */
-       for (i = RETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
-               if (buf[i] == tramp) {
-                       found = stack + i;
-                       break;
-               }
-       }
-
-       if (found) {
-               printk("---> %s (%d/%d): trampoline found at %08lx (%08lx /%+d) - %p\n",
-                               task->comm, task->tgid, task->pid,
-                               (unsigned long)found, (unsigned long)sp,
-                               found - sp, ri->rp->up.kp.addr);
-               retval = write_proc_vm_atomic(task, (unsigned long)found, &ri->ret_addr,
-                               sizeof(ri->ret_addr));
-               if (retval != sizeof(ri->ret_addr)) {
-                       printk("---> %s (%d/%d): failed to write value to %08lx",
-                               task->comm, task->tgid, task->pid, (unsigned long)found);
-                       retval = -EFAULT;
-               } else {
-                       retval = 0;
-               }
-       } else {
-               struct pt_regs *uregs = task_pt_regs(ri->task);
-               unsigned long ra = dbi_get_ret_addr(uregs);
-               if (ra == (unsigned long)tramp) {
-                       printk("---> %s (%d/%d): trampoline found at lr = %08lx - %p\n",
-                                       task->comm, task->tgid, task->pid, ra, ri->rp->up.kp.addr);
-                       dbi_set_ret_addr(uregs, (unsigned long)ri->ret_addr);
-                       retval = 0;
-               } else {
-                       printk("---> %s (%d/%d): trampoline NOT found at sp = %08lx, lr = %08lx - %p\n",
-                                       task->comm, task->tgid, task->pid,
-                                       (unsigned long)sp, ra, ri->rp->up.kp.addr);
-                       retval = -ENOENT;
-               }
-       }
-
-out:
-       return retval;
-}
-
 /* Called with uretprobe_lock held */
 int dbi_disarm_urp_inst_for_task(struct task_struct *parent, struct task_struct *task)
 {
@@ -835,7 +766,7 @@ int dbi_disarm_urp_inst_for_task(struct task_struct *parent, struct task_struct
 
        swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
                if (parent == ri->task) {
-                       dbi_disarm_urp_inst(ri, task);
+                       arch_disarm_urp_inst(ri, task);
                }
        }
 
@@ -852,7 +783,7 @@ void __dbi_unregister_uretprobe(struct uretprobe *rp, int disarm)
        spin_lock_irqsave (&uretprobe_lock, flags);
 
        while ((ri = get_used_urp_inst(rp)) != NULL) {
-               if (dbi_disarm_urp_inst(ri, NULL) != 0)
+               if (arch_disarm_urp_inst(ri, ri->task) != 0)
                        printk("%s (%d/%d): cannot disarm urp instance (%08lx)\n",
                                        ri->task->comm, ri->task->tgid, ri->task->pid,
                                        (unsigned long)rp->up.kp.addr);