}
}
+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);
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);
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)
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));
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)
}
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);
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)
{
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);
}
}
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);