{
}
-void dbi_arch_uprobe_return (void)
-{
-}
-
int longjmp_break_handler (struct kprobe *p, struct pt_regs *regs)
{
-# ifndef REENTER
- //kprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
- kprobe_opcode_t insns[2];
-
- if (p->pid)
- {
- insns[0] = BREAKPOINT_INSTRUCTION;
- insns[1] = p->opcode;
- //p->opcode = *p->addr;
- if (read_proc_vm_atomic (current, (unsigned long) (p->addr), &(p->opcode), sizeof (p->opcode)) < sizeof (p->opcode))
- {
- printk ("ERROR[%lu]: failed to read vm of proc %s/%u addr %p.", nCount, current->comm, current->pid, p->addr);
- return -1;
- }
- //*p->addr = BREAKPOINT_INSTRUCTION;
- //*(p->addr+1) = p->opcode;
- if (write_proc_vm_atomic (current, (unsigned long) (p->addr), insns, sizeof (insns)) < sizeof (insns))
- {
- printk ("ERROR[%lu]: failed to write vm of proc %s/%u addr %p.", nCount, current->comm, current->pid, p->addr);
- return -1;
- }
- }
- else
- {
- DBPRINTF ("p->opcode = 0x%lx *p->addr = 0x%lx p->addr = 0x%p\n", p->opcode, *p->addr, p->addr);
- *(p->addr + 1) = p->opcode;
- p->opcode = *p->addr;
- *p->addr = BREAKPOINT_INSTRUCTION;
-
- flush_icache_range ((unsigned int) p->addr, (unsigned int) (((unsigned int) p->addr) + (sizeof (kprobe_opcode_t) * 2)));
- }
-
- reset_current_kprobe();
-
-#endif //REENTER
-
return 0;
}
+EXPORT_SYMBOL_GPL(longjmp_break_handler);
-void arch_arm_kprobe (struct kprobe *p)
+ #ifdef CONFIG_STRICT_MEMORY_RWX
+ extern void mem_text_write_kernel_word(unsigned long *addr, unsigned long word);
+ #endif
+
+void arch_arm_kprobe(struct kprobe *p)
{
+ #ifdef CONFIG_STRICT_MEMORY_RWX
+ mem_text_write_kernel_word(p->addr, BREAKPOINT_INSTRUCTION);
+ #else
*p->addr = BREAKPOINT_INSTRUCTION;
- flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
+ flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+ #endif
}
-void arch_disarm_kprobe (struct kprobe *p)
+void arch_disarm_kprobe(struct kprobe *p)
{
+ #ifdef CONFIG_STRICT_MEMORY_RWX
+ mem_text_write_kernel_word(p->addr, p->opcode);
+ #else
*p->addr = p->opcode;
- flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
+ flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+ #endif
}
-
-int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs)
-{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
- struct hlist_node *node, *tmp;
- unsigned long flags, orig_ret_address = 0;
- unsigned long trampoline_address = (unsigned long) &kretprobe_trampoline;
- unsigned long ret = 1;
-
- struct kretprobe *crp = NULL;
- struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
-
- DBPRINTF ("start");
-
- if (p && p->tgid){
- // in case of user space retprobe trampoline is at the Nth instruction of US tramp
- if (!thumb_mode( regs ))
- trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
- else
- trampoline_address = (unsigned long)(p->ainsn.insn) + 0x1b;
- }
-
- spin_lock_irqsave (&kretprobe_lock, flags);
-
- /*
- * We are using different hash keys (current and mm) for finding kernel
- * space and user space probes. Kernel space probes can change mm field in
- * task_struct. User space probes can be shared between threads of one
- * process so they have different current but same mm.
- */
- if (p && p->tgid) {
- head = kretprobe_inst_table_head(current->mm);
- } else {
- head = kretprobe_inst_table_head(current);
- }
-
- /*
- * It is possible to have multiple instances associated with a given
- * task either because an multiple functions in the call path
- * have a return probe installed on them, and/or more then one
- * return probe was registered for a target function.
- *
- * We can handle this because:
- * - instances are always inserted at the head of the list
- * - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
- * real return address, and all the rest will point to
- * kretprobe_trampoline
- */
- swap_hlist_for_each_entry_safe (ri, node, tmp, head, hlist)
- {
- if (ri->task != current)
- /* another task is sharing our hash bucket */
- continue;
- if (ri->rp && ri->rp->handler){
- ri->rp->handler (ri, regs, ri->rp->priv_arg);
- }
-
- orig_ret_address = (unsigned long) ri->ret_addr;
- recycle_rp_inst (ri);
- if (orig_ret_address != trampoline_address)
- /*
- * This is the real return address. Any other
- * instances associated with this task are for
- * other calls deeper on the call stack
- */
- break;
- }
- kretprobe_assert (ri, orig_ret_address, trampoline_address);
- //BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
- //E.G. Check this code in case of __switch_to function instrumentation -- currently this code generates dump in this case
- //if (trampoline_address != (unsigned long) &kretprobe_trampoline){
- //if (ri->rp2) BUG_ON (ri->rp2->kp.tgid == 0);
- //if (ri->rp) BUG_ON (ri->rp->kp.tgid == 0);
- //else if (ri->rp2) BUG_ON (ri->rp2->kp.tgid == 0);
- //}
- if ((ri->rp && ri->rp->kp.tgid) || (ri->rp2 && ri->rp2->kp.tgid))
- BUG_ON (trampoline_address == (unsigned long) &kretprobe_trampoline);
-
- if (p && p->tgid)
- regs->uregs[14] = orig_ret_address;
-
- DBPRINTF ("regs->uregs[14] = 0x%lx\n", regs->uregs[14]);
- DBPRINTF ("regs->uregs[15] = 0x%lx\n", regs->uregs[15]);
-
- if (trampoline_address != (unsigned long) &kretprobe_trampoline)
- {
- regs->uregs[15] = orig_ret_address;
- }else{
- ret = (unsigned long)orig_ret_address;
- }
-
- DBPRINTF ("regs->uregs[15] = 0x%lx\n", regs->uregs[15]);
-
- if(p){ // ARM, MIPS, X86 user space
- if (thumb_mode( regs ) && !(regs->uregs[14] & 0x01))
- {
- regs->ARM_cpsr &= 0xFFFFFFDF;
- }else{
- if (user_mode( regs ) && (regs->uregs[14] & 0x01))
- {
- regs->ARM_cpsr |= 0x20;
- }
- }
-
- //TODO: test - enter function, delete us retprobe, exit function
- // for user space retprobes only - deferred deletion
-
- if (trampoline_address != (unsigned long) &kretprobe_trampoline)
- {
- // if we are not at the end of the list and current retprobe should be disarmed
- if (node && ri->rp2)
- {
- struct hlist_node *current_node = node;
- crp = ri->rp2;
- /*sprintf(die_msg, "deferred disarm p->addr = %p [%lx %lx %lx]\n",
- crp->kp.addr, *kaddrs[0], *kaddrs[1], *kaddrs[2]);
- DIE(die_msg, regs); */
- // look for other instances for the same retprobe
- swap_hlist_for_each_entry_safe (ri, node, tmp, head, hlist)
- {
- /*
- * Trying to find another retprobe instance associated with
- * the same retprobe.
- */
- if (ri->rp2 == crp && node != current_node)
- break;
- }
-
- if (!node)
- {
- // if there are no more instances for this retprobe
- // delete retprobe
- struct kprobe *is_p = &crp->kp;
- DBPRINTF ("defered retprobe deletion p->addr = %p", crp->kp.addr);
- /*
- If there is no any retprobe instances of this retprobe
- we can free the resources related to the probe.
- */
- if (!(hlist_unhashed(&is_p->is_hlist_arm))) {
- hlist_del_rcu(&is_p->is_hlist_arm);
- }
- if (!(hlist_unhashed(&is_p->is_hlist_thumb))) {
- hlist_del_rcu(&is_p->is_hlist_thumb);
- }
- unregister_uprobe (&crp->kp, current, 1);
- kfree (crp);
- }
- hlist_del(current_node);
- }
- }
-
- if (kcb->kprobe_status == KPROBE_REENTER) {
- restore_previous_kprobe(kcb);
- } else {
- reset_current_kprobe();
- }
- }
-
- spin_unlock_irqrestore (&kretprobe_lock, flags);
-
- /*
- * By returning a non-zero value, we are telling
- * kprobe_handler() that we don't want the post_handler
- * to run (and have re-enabled preemption)
- */
-
- return ret;
-}
-
void __naked kretprobe_trampoline(void)
{
__asm__ __volatile__ (
static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
atomic_t kprobe_count;
-static void *(*module_alloc)(unsigned long size);
+EXPORT_SYMBOL_GPL(kprobe_count);
+
+
-void *__wrapper_module_alloc(unsigned long size)
++static void *(*module_alloc)(unsigned long size) = NULL;
++static void *(*module_free)(struct module *mod, void *module_region) = NULL;
+
-static void *(*module_free)(struct module *mod, void *module_region);
-
-void *__wrapper_module_free(void *module_region)
++static void *__wrapper_module_alloc(unsigned long size)
+ {
+ return module_alloc(size);
+ }
+
- return kmalloc(PAGE_SIZE, GFP_ATOMIC);
++static void *__wrapper_module_free(void *module_region)
+ {
+ return module_free(NULL, module_region);
+ }
+
+static void *sm_alloc(struct slot_manager *sm)
+{
- kfree(ptr);
++ return __wrapper_module_alloc(PAGE_SIZE);
+}
+
+static void sm_free(struct slot_manager *sm, void *ptr)
+{
++ __wrapper_module_free(ptr);
+}
+
+static void init_sm()
+{
+ sm.slot_size = KPROBES_TRAMP_LEN;
+ sm.alloc = sm_alloc;
+ sm.free = sm_free;
+ INIT_HLIST_NODE(&sm.page_list);
+}
+
+static void exit_sm()
+{
+ /* FIXME: free */
+}
-void kretprobe_assert (struct kretprobe_instance *ri, unsigned long orig_ret_address, unsigned long trampoline_address)
+void kretprobe_assert(struct kretprobe_instance *ri, unsigned long orig_ret_address, unsigned long trampoline_address)
{
if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
struct task_struct *task;
{
unsigned long flags;
struct kretprobe_instance *ri;
- struct hlist_node *node;
spin_lock_irqsave(&kretprobe_lock, flags);
- while ((ri = get_used_rp_inst (rp)) != NULL) {
+ while ((ri = get_used_rp_inst(rp)) != NULL) {
recycle_rp_inst(ri);
}
- spin_unlock_irqrestore (&kretprobe_lock, flags);
- free_rp_inst (rp);
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ free_rp_inst(rp);
+}
+
+void dbi_unregister_kretprobe(struct kretprobe *rp)
+{
+ dbi_unregister_kretprobe_top(rp);
+ dbi_unregister_kretprobe_bottom(rp);
}
-struct kretprobe * clone_kretprobe (struct kretprobe *rp)
+struct kretprobe *clone_kretprobe(struct kretprobe *rp)
{
struct kprobe *old_p;
struct kretprobe *clone = NULL;
{
int i, err = 0;
+ module_alloc = (void *)swap_ksyms("module_alloc");
+ if (!module_alloc) {
+ printk("module_alloc is not found! Oops.\n");
+ return -1;
+ }
+ module_free = (void *)swap_ksyms("module_free");
+ if (!module_alloc) {
+ printk("module_free is not found! Oops.\n");
+ return -1;
+ }
+
+ init_sm();
+
/* FIXME allocate the probe table, currently defined statically */
/* initialize all list heads */
- for (i = 0; i < KPROBE_TABLE_SIZE; i++)
- {
- INIT_HLIST_HEAD (&kprobe_table[i]);
- INIT_HLIST_HEAD (&kretprobe_inst_table[i]);
+ for (i = 0; i < KPROBE_TABLE_SIZE; ++i) {
+ INIT_HLIST_HEAD(&kprobe_table[i]);
+ INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
+ }
+ atomic_set(&kprobe_count, 0);
- init_uprobes_insn_slots(i);
+ err = init_module_deps();
+ if (err) {
+ return err;
}
- atomic_set (&kprobe_count, 0);
- err = arch_init_kprobes ();
+ err = arch_init_kprobes();
DBPRINTF ("init_kprobes: arch_init_kprobes - %d", err);