Merge branch 'dev' into kernel
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 4 Jun 2013 14:16:40 +0000 (18:16 +0400)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 4 Jun 2013 14:16:40 +0000 (18:16 +0400)
Conflicts:
src/modules/driver/us_proc_inst.c

1  2 
us_manager/helper.c
us_manager/helper.h
us_manager/us_manager.c

index 9b6bfa9,0000000..5073b01
mode 100644,000000..100644
--- /dev/null
@@@ -1,362 -1,0 +1,369 @@@
-       if (task->flags & PF_KTHREAD)
 +#include <dbi_kprobes.h>
 +#include <dbi_kprobes_deps.h>
 +#include <ksyms.h>
 +#include "us_proc_inst.h"
 +#include "us_slot_manager.h"
 +#include "storage.h"
 +#include "sspt/sspt.h"
 +#include "filters/filters_core.h"
++#include "helper.h"
 +
 +/*
 + ******************************************************************************
 + *                               do_page_fault()                              *
 + ******************************************************************************
 + */
 +
 +struct pf_data {
 +      unsigned long addr;
 +};
 +
 +static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
 +{
 +      struct pf_data *data = (struct pf_data *)ri->data;
 +
 +#if defined(CONFIG_X86)
 +      data->addr = read_cr2();
 +#elif defined(CONFIG_ARM)
 +      data->addr = regs->ARM_r0;
 +#else
 +#error this architecture is not supported
 +#endif
 +
 +      return 0;
 +}
 +
 +/* Detects when IPs are really loaded into phy mem and installs probes. */
 +static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
 +{
 +      struct task_struct *task;
 +      struct sspt_proc *proc;
 +
 +      /*
 +       * Because process threads have same address space
 +       * we instrument only group_leader of all this threads
 +       */
 +      task = current->group_leader;
++      if (is_kthread(task))
 +              return 0;
 +
 +      proc = sspt_proc_get_by_task(task);
 +      if (proc)
 +              goto install_proc;
 +
 +      task = check_task(task);
 +      if (task) {
 +              proc = sspt_proc_get_new(task);
 +              goto install_proc;
 +      }
 +
 +      return 0;
 +
 +install_proc:
 +      if (proc->first_install) {
 +              unsigned long page;
 +              page = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
 +              sspt_proc_install_page(proc, page);
 +      } else {
 +              sspt_proc_install(proc);
 +      }
 +
 +      return 0;
 +}
 +
 +static struct kretprobe pf_kretprobe = {
 +      .entry_handler = entry_handler_pf,
 +      .handler = ret_handler_pf,
 +      .data_size = sizeof(struct pf_data)
 +};
 +
 +
 +
 +/*
 + ******************************************************************************
 + *                              copy_process()                                *
 + ******************************************************************************
 + */
 +
 +static void recover_child(struct task_struct *child_task, struct sspt_proc *proc)
 +{
 +      sspt_proc_uninstall(proc, child_task, US_DISARM);
 +      dbi_disarm_urp_inst_for_task(current, child_task);
 +}
 +
 +static void rm_uprobes_child(struct task_struct *task)
 +{
 +      struct sspt_proc *proc = sspt_proc_get_by_task(current);
 +      if(proc) {
 +              recover_child(task, proc);
 +      }
 +}
 +
 +/* Delete uprobs in children at fork */
 +static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
 +{
 +      struct task_struct *task = (struct task_struct *)regs_return_value(regs);
 +
 +      if(!task || IS_ERR(task))
 +              goto out;
 +
 +      if(task->mm != current->mm) {   /* check flags CLONE_VM */
 +              rm_uprobes_child(task);
 +
 +              if (check_task(current)) {
 +                      struct sspt_proc *proc;
 +
 +                      proc = sspt_proc_get_new(task);
 +                      sspt_proc_install(proc);
 +              }
 +      }
 +out:
 +      return 0;
 +}
 +
 +static struct kretprobe cp_kretprobe = {
 +      .handler = ret_handler_cp,
 +};
 +
 +
 +
 +/*
 + ******************************************************************************
 + *                                mm_release()                                *
 + ******************************************************************************
 + */
 +
 +/* Detects when target process removes IPs. */
 +static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
 +{
 +      struct sspt_proc *proc = NULL;
 +      struct task_struct *task;
 +
 +#if defined(CONFIG_X86)
 +      task = (struct task_struct *)regs->EREG(ax);
 +#elif defined(CONFIG_ARM)
 +      task = (struct task_struct *)regs->ARM_r0;
 +#else
 +#error this architecture is not supported
 +#endif
 +
++      if (is_kthread(task))
++              goto out;
++
 +      if (task->tgid != task->pid) {
 +              goto out;
 +      }
 +
 +      proc = sspt_proc_get_by_task(task);
 +      if (proc) {
 +              int ret = sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
 +              if (ret != 0) {
 +                      printk("failed to uninstall IPs (%d)!\n", ret);
 +              }
 +
 +              dbi_unregister_all_uprobes(task);
 +      }
 +
 +out:
 +      return 0;
 +}
 +
 +static struct kprobe mr_kprobe = {
 +      .pre_handler = mr_pre_handler
 +};
 +
 +
 +
 +/*
 + ******************************************************************************
 + *                                 do_munmap()                                *
 + ******************************************************************************
 + */
 +
 +static int remove_unmap_probes(struct task_struct *task, struct sspt_proc *proc, unsigned long start, size_t len)
 +{
 +      struct mm_struct *mm = task->mm;
 +      struct vm_area_struct *vma;
 +
 +      if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE - start) {
 +              return -EINVAL;
 +      }
 +
 +      if ((len = PAGE_ALIGN(len)) == 0) {
 +              return -EINVAL;
 +      }
 +
 +      vma = find_vma(mm, start);
 +      if (vma && check_vma(vma)) {
 +              struct sspt_file *file;
 +              unsigned long end = start + len;
 +              struct dentry *dentry = vma->vm_file->f_dentry;
 +
 +              file = sspt_proc_find_file(proc, dentry);
 +              if (file) {
 +                      if (vma->vm_start == start || vma->vm_end == end) {
 +                              sspt_file_uninstall(file, task, US_UNREGS_PROBE);
 +                              file->loaded = 0;
 +                      } else {
 +                              unsigned long page_addr;
 +                              struct sspt_page *page;
 +
 +                              for (page_addr = vma->vm_start; page_addr < vma->vm_end; page_addr += PAGE_SIZE) {
 +                                      page = sspt_find_page_mapped(file, page_addr);
 +                                      if (page) {
 +                                              sspt_unregister_page(page, US_UNREGS_PROBE, task);
 +                                      }
 +                              }
 +
 +                              if (sspt_file_check_install_pages(file)) {
 +                                      file->loaded = 0;
 +                              }
 +                      }
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +/* Detects when target removes IPs. */
 +static int unmap_pre_handler(struct kprobe *p, struct pt_regs *regs)
 +{
 +      /* for ARM */
 +      struct mm_struct *mm;
 +      unsigned long start;
 +      size_t len;
 +
 +#if defined(CONFIG_X86)
 +      mm = (struct mm_struct *)regs->EREG(ax);
 +      start = regs->EREG(dx);
 +      len = (size_t)regs->EREG(cx);
 +#elif defined(CONFIG_ARM)
 +      mm = (struct mm_struct *)regs->ARM_r0;
 +      start = regs->ARM_r1;
 +      len = (size_t)regs->ARM_r2;
 +#else
 +#error this architecture is not supported
 +#endif
 +
 +      struct sspt_proc *proc = NULL;
 +      struct task_struct *task = current;
 +
++      if (is_kthread(task))
++              goto out;
++
 +      proc = sspt_proc_get_by_task(task);
 +      if (proc) {
 +              if (remove_unmap_probes(task, proc, start, len)) {
 +                      printk("ERROR do_munmap: start=%lx, len=%x\n", start, len);
 +              }
 +      }
 +
 +out:
 +      return 0;
 +}
 +
 +static struct kprobe unmap_kprobe = {
 +      .pre_handler = unmap_pre_handler
 +};
 +
 +
 +
 +int register_helper(void)
 +{
 +      int ret = 0;
 +
 +      /* install kprobe on 'do_munmap' to detect when for remove user space probes */
 +      ret = dbi_register_kprobe(&unmap_kprobe);
 +      if (ret) {
 +              printk("dbi_register_kprobe(do_munmap) result=%d!\n", ret);
 +              return ret;
 +      }
 +
 +      /* install kprobe on 'mm_release' to detect when for remove user space probes */
 +      ret = dbi_register_kprobe(&mr_kprobe);
 +      if (ret != 0) {
 +              printk("dbi_register_kprobe(mm_release) result=%d!\n", ret);
 +              goto unregister_unmap;
 +      }
 +
 +
 +      /* install kretprobe on 'copy_process' */
 +      ret = dbi_register_kretprobe(&cp_kretprobe);
 +      if (ret) {
 +              printk("dbi_register_kretprobe(copy_process) result=%d!\n", ret);
 +              goto unregister_mr;
 +      }
 +
 +      /* install kretprobe on 'do_page_fault' to detect when they will be loaded */
 +      ret = dbi_register_kretprobe(&pf_kretprobe);
 +      if (ret) {
 +              printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
 +              goto unregister_cp;
 +      }
 +
 +      return ret;
 +
 +unregister_cp:
 +      dbi_unregister_kretprobe(&cp_kretprobe);
 +
 +unregister_mr:
 +      dbi_unregister_kprobe(&mr_kprobe, NULL);
 +
 +unregister_unmap:
 +      dbi_unregister_kprobe(&unmap_kprobe, NULL);
 +
 +      return ret;
 +}
 +
 +void unregister_helper(void)
 +{
 +      /* uninstall kretprobe with 'do_page_fault' */
 +      dbi_unregister_kretprobe(&pf_kretprobe);
 +
 +      /* uninstall kretprobe with 'copy_process' */
 +      dbi_unregister_kretprobe(&cp_kretprobe);
 +
 +      /* uninstall kprobe with 'mm_release' */
 +      dbi_unregister_kprobe(&mr_kprobe, NULL);
 +
 +      /* uninstall kprobe with 'do_munmap' */
 +      dbi_unregister_kprobe(&unmap_kprobe, NULL);
 +}
 +
 +int init_helper(void)
 +{
 +      unsigned long addr;
 +      addr = swap_ksyms("do_page_fault");
 +      if (addr == 0) {
 +              printk("Cannot find address for page fault function!\n");
 +              return -EINVAL;
 +      }
 +      pf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
 +
 +      addr = swap_ksyms("copy_process");
 +      if (addr == 0) {
 +              printk("Cannot find address for copy_process function!\n");
 +              return -EINVAL;
 +      }
 +      cp_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
 +
 +      addr = swap_ksyms("mm_release");
 +      if (addr == 0) {
 +              printk("Cannot find address for mm_release function!\n");
 +              return -EINVAL;
 +      }
 +      mr_kprobe.addr = (kprobe_opcode_t *)addr;
 +
 +      addr = swap_ksyms("do_munmap");
 +      if (addr == 0) {
 +              printk("Cannot find address for do_munmap function!\n");
 +              return -EINVAL;
 +      }
 +      unmap_kprobe.addr = (kprobe_opcode_t *)addr;
 +
 +      return 0;
 +}
 +
 +void uninit_helper(void)
 +{
 +}
index b88a0d8,0000000..4c57794
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,17 @@@
 +#ifndef _HELPER_H
 +#define _HELPER_H
 +
++#include <linux/sched.h>
++
++static inline int is_kthread(struct task_struct *task)
++{
++      return !task->mm;
++}
++
 +int init_helper(void);
 +void uninit_helper(void);
 +
 +int register_helper(void);
 +void unregister_helper(void);
 +
 +#endif /* _HELPER_H */
index 8fcb5cb,0000000..0c8f41d
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,190 @@@
 +#include <linux/module.h>
 +#include <sspt/sspt.h>
 +#include <sspt/sspt_proc.h>
 +#include <sspt/sspt_page.h>
 +#include <filters/filters_core.h>
 +#include <filters/filter_by_path.h>
 +#include <helper.h>
 +
 +static const char *app_filter = "app";
 +
 +struct sspt_proc *proc_base;
 +void (*ptr_pack_task_event_info)(struct task_struct *task,
 +                               int probe_id,
 +                               int record_type,
 +                               const char *fmt, ...) = NULL;
 +
 +EXPORT_SYMBOL_GPL(ptr_pack_task_event_info);
 +
 +int usm_register_probe(struct dentry *dentry, unsigned long offset,
 +                     void *pre_handler, void *jp_handler, void *rp_handler)
 +{
 +      char *file_name;
 +      struct sspt_file *file;
 +      struct ip_data ip_d;
 +
 +      file_name = dentry->d_iname;
 +      file = sspt_proc_find_file_or_new(proc_base, dentry, file_name);
 +
 +      ip_d.flag_retprobe = 1;
 +      ip_d.got_addr = 0;
 +      ip_d.jp_handler = jp_handler;
 +      ip_d.offset = offset;
 +      ip_d.pre_handler = pre_handler;
 +      ip_d.rp_handler = rp_handler;
 +
 +      sspt_file_add_ip(file, &ip_d);
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(usm_register_probe);
 +
 +int usm_unregister_probe(struct dentry *dentry, unsigned long offset)
 +{
 +      struct sspt_file *file;
 +      struct sspt_page *page;
 +      struct us_ip *ip;
 +
 +      file = sspt_proc_find_file(proc_base, dentry);
 +      if (file == NULL)
 +              return -EINVAL;
 +
 +      page = sspt_get_page(file, offset);
 +      if (page == NULL)
 +              return -EINVAL;
 +
 +      ip = sspt_find_ip(page, offset & ~PAGE_MASK);
 +      if (ip == NULL) {
 +              sspt_put_page(page);
 +              return -EINVAL;
 +      }
 +
 +      sspt_del_ip(ip);
 +      sspt_put_page(page);
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(usm_unregister_probe);
 +
 +int usm_set_dentry(struct dentry *dentry)
 +{
 +      proc_base->dentry = dentry;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(usm_set_dentry);
 +
 +int usm_stop(void)
 +{
 +      int iRet = 0, found = 0;
 +      struct task_struct *task = NULL;
 +      struct sspt_proc *proc;
 +      int tmp_oops_in_progress;
 +
 +      unregister_helper();
 +
 +      if (iRet)
 +              printk("uninstall_kernel_probe(do_munmap) result=%d!\n", iRet);
 +
 +
 +      tmp_oops_in_progress = oops_in_progress;
 +      oops_in_progress = 1;
 +      rcu_read_lock();
 +      for_each_process(task) {
++              if (is_kthread(task))
++                      continue;
++
 +              proc = sspt_proc_get_by_task(task);
 +              if (proc) {
 +                      int ret = sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
 +                      if (ret)
 +                              printk("failed to uninstall IPs (%d)!\n", ret);
 +
 +                      dbi_unregister_all_uprobes(task);
 +              }
 +      }
 +      rcu_read_unlock();
 +      oops_in_progress = tmp_oops_in_progress;
 +
 +      uninit_filter();
 +      unregister_filter(app_filter);
 +
 +      sspt_proc_free_all();
 +
 +      return iRet;
 +}
 +EXPORT_SYMBOL_GPL(usm_stop);
 +
 +int usm_start(void)
 +{
 +      int ret, i;
 +      struct task_struct *task = NULL, *ts;
 +      struct sspt_proc *proc;
 +      int tmp_oops_in_progress;
 +
 +      ret = register_filter(app_filter, get_filter_by_path());
 +      if (ret)
 +              return ret;
 +
 +      if (proc_base->dentry) {
 +              ret = set_filter(app_filter);
 +              if (ret)
 +                      return ret;
 +
 +              ret = init_filter(proc_base->dentry, 0);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      ret = register_helper();
 +      if (ret) {
 +              return ret;
 +      }
 +
 +      tmp_oops_in_progress = oops_in_progress;
 +      oops_in_progress = 1;
 +      rcu_read_lock();
 +      for_each_process(task) {
++              if (is_kthread(task))
++                      continue;
++
 +              ts = check_task(task);
 +
 +              if (ts) {
 +                      proc = sspt_proc_get_by_task_or_new(ts);
 +                      sspt_proc_install(proc);
 +              }
 +      }
 +      rcu_read_unlock();
 +      oops_in_progress = tmp_oops_in_progress;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(usm_start);
 +
 +static int __init init_us_manager(void)
 +{
 +      int ret;
 +
 +      ret = init_helper();
 +      if (ret)
 +              return ret;
 +
 +      proc_base = sspt_proc_create(NULL, NULL);
 +      if (proc_base == NULL)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +
 +static void __exit exit_us_manager(void)
 +{
 +      sspt_proc_free(proc_base);
 +      uninit_helper();
 +}
 +
 +module_init(init_us_manager);
 +module_exit(exit_us_manager);
 +
 +MODULE_LICENSE ("GPL");
 +