ri->rp2 = NULL;
ri->task = current;
ri->ret_addr = (kprobe_opcode_t *) regs->uregs[14];
+ ri->sp = (kprobe_opcode_t *)regs->ARM_sp; //uregs[13];
if (rp->kp.tgid)
if (!thumb_mode( regs ))
ri->rp = rp;
ri->rp2 = NULL;
ri->task = current;
+ ri->sp = (kprobe_opcode_t *)regs->EREG(sp);
/* Replace the return addr with trampoline addr */
if (rp->kp.tgid){
extern unsigned long sched_addr;
extern unsigned long fork_addr;
+extern unsigned long exit_addr;
extern struct hlist_head kprobe_insn_pages;
extern struct hlist_head uprobe_insn_pages;
{
sched_addr = swap_ksyms("__switch_to");
fork_addr = swap_ksyms("do_fork");
+ exit_addr = swap_ksyms("do_exit");
init_module_dependencies();
extern unsigned long sched_addr;
extern unsigned long fork_addr;
+extern unsigned long exit_addr;
extern struct hlist_head kprobe_insn_pages;
DEFINE_PER_CPU (struct kprobe *, current_kprobe) = NULL;
/* Pre-allocate memory for max kretprobe instances */
if ((unsigned long)rp->kp.addr == sched_addr) {
rp->maxactive = SCHED_RP_NR;//max (100, 2 * NR_CPUS);
+ rp->kp.pre_handler = NULL; //not needed for __switch_to
+ } else if ((unsigned long)rp->kp.addr == exit_addr) {
+ rp->kp.pre_handler = NULL; //not needed for do_exit
+ rp->maxactive = 0;
} else if (rp->maxactive <= 0) {
#if 1//def CONFIG_PREEMPT
rp->maxactive = max (COMMON_RP_NR, 2 * NR_CPUS);
}
static void unpatch_suspended_all_task_ret_addr(struct kretprobe *rp);
+static int dbi_disarm_krp_inst(struct kretprobe_instance *ri);
void dbi_unregister_kretprobe (struct kretprobe *rp)
{
/* No race here */
spin_lock_irqsave (&kretprobe_lock, flags);
- while ((ri = get_used_rp_inst (rp)) != NULL)
- {
- ri->rp = NULL;
- hlist_del (&ri->uflist);
+ while ((ri = get_used_rp_inst (rp)) != NULL) {
+ if (dbi_disarm_krp_inst(ri) == 0)
+ recycle_rp_inst(ri);
+ else
+ panic("%s (%d/%d): cannot disarm krp instance (%08lx)",
+ ri->task->comm, ri->task->tgid, ri->task->pid, rp->kp.addr);
}
spin_unlock_irqrestore (&kretprobe_lock, flags);
free_rp_inst (rp);
return clone;
}
+static int dbi_disarm_krp_inst(struct kretprobe_instance *ri)
+{
+ kprobe_opcode_t *tramp = (kprobe_opcode_t *)&kretprobe_trampoline;
+ kprobe_opcode_t *sp = ri->sp;
+ kprobe_opcode_t *found = NULL;
+ int retval = -ENOENT;
+
+ if (!sp) {
+ printk("---> %s (%d/%d) sp == NULL (%08lx)!!!!\n",
+ ri->task->comm, ri->task->tgid, ri->task->pid,
+ ri->rp ? ri->rp->kp.addr: NULL);
+ return -EINVAL;
+ }
+
+ while (sp > ri->sp - RETPROBE_STACK_DEPTH) {
+ if (*sp == tramp) {
+ found = sp;
+ break;
+ }
+ sp--;
+ }
+
+ if (found) {
+ printk("---> %s (%d/%d): trampoline found at %08lx (%08lx /%+d) - %p\n",
+ ri->task->comm, ri->task->tgid, ri->task->pid,
+ found, ri->sp, found - ri->sp, ri->rp ? ri->rp->kp.addr: NULL);
+ *found = ri->ret_addr;
+ retval = 0;
+ } else {
+ printk("---> %s (%d/%d): trampoline NOT found at sp = %08lx - %p\n",
+ ri->task->comm, ri->task->tgid, ri->task->pid,
+ ri->sp, ri->rp ? ri->rp->kp.addr: NULL);
+ }
+
+ return retval;
+}
static void inline set_task_trampoline(struct task_struct *p, struct kretprobe_instance *ri, unsigned long tramp_addr)
{
ri->rp = rp;
ri->rp2 = NULL;
ri->task = p;
+ ri->sp = NULL;
// set PC
set_task_trampoline(p, ri, tramp_addr);
add_rp_inst(ri);
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
+#define RETPROBE_STACK_DEPTH 64
+
struct kprobe;
struct pt_regs;
struct kretprobe;
struct hlist_node hlist;
struct kretprobe *rp;
kprobe_opcode_t *ret_addr;
+ kprobe_opcode_t *sp;
struct kretprobe *rp2;
struct task_struct *task;
};
unsigned long sched_addr;
unsigned long fork_addr;
+unsigned long exit_addr;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
struct mm_struct* init_mm_ptr;
return ret;
}
+static int dbi_disarm_urp_inst(struct kretprobe_instance *ri)
+{
+ struct task_struct *task = ri->task;
+ kprobe_opcode_t *tramp = (kprobe_opcode_t *)(ri->rp->kp.ainsn.insn +
+ UPROBES_TRAMP_RET_BREAK_IDX);
+ kprobe_opcode_t *stack = ri->sp - RETPROBE_STACK_DEPTH;
+ kprobe_opcode_t *found = NULL;
+ kprobe_opcode_t *buf[RETPROBE_STACK_DEPTH];
+ int i, retval;
+
+ retval = read_proc_vm_atomic(task, stack, buf, sizeof(buf));
+ if (retval != sizeof(buf)) {
+ printk("---> %s (%d/%d): failed to read stack from %08lx",
+ task->comm, task->tgid, task->pid, 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,
+ found, ri->sp, found - ri->sp, ri->rp->kp.addr);
+ retval = write_proc_vm_atomic(task, 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, found);
+ retval = -EFAULT;
+ } else {
+ retval = 0;
+ }
+ } else {
+ printk("---> %s (%d/%d): trampoline NOT found at sp = %08lx - %p\n",
+ task->comm, task->tgid, task->pid, ri->sp, ri->rp->kp.addr);
+ retval = -ENOENT;
+ }
+
+out:
+ return retval;
+}
void dbi_unregister_uretprobe(struct task_struct *task, struct kretprobe *rp, int atomic, int not_rp2)
{
spin_lock_irqsave (&kretprobe_lock, flags);
+ while ((ri = get_used_rp_inst(rp)) != NULL) {
+ if (dbi_disarm_urp_inst(ri) == 0)
+ recycle_rp_inst(ri);
+ else
+ panic("%s (%d/%d): cannot disarm urp instance (%08lx)",
+ ri->task->comm, ri->task->tgid, ri->task->pid, rp->kp.addr);
+ }
+
if (hlist_empty(&rp->used_instances) || not_rp2) {
struct kprobe *p = &rp->kp;
// if there are no used retprobe instances (i.e. function is not entered) - disarm retprobe