Merge commit 'd307e458a' into kernel
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 20 Aug 2013 10:39:29 +0000 (14:39 +0400)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 20 Aug 2013 10:39:29 +0000 (14:39 +0400)
Conflicts:
src/modules/kprobe/arch/asm-arm/dbi_kprobes.c
src/modules/kprobe/dbi_insn_slots.c
src/modules/kprobe/dbi_kprobes.c
src/modules/kprobe/dbi_kprobes.h

1  2 
kprobe/arch/asm-arm/dbi_kprobes.c
kprobe/dbi_kprobes.c

@@@ -372,24 -1399,246 +372,36 @@@ void dbi_jprobe_return (void
  {
  }
  
 -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__ (
@@@ -83,32 -80,23 +83,46 @@@ struct hlist_head kprobe_table[KPROBE_T
  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;
@@@ -842,23 -801,16 +856,22 @@@ static void dbi_unregister_kretprobe_bo
  {
        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;
@@@ -977,22 -946,29 +990,33 @@@ static int __init init_kprobes(void
  {
        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);