added monitoring function 'do_mnumap'
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Wed, 7 Nov 2012 12:31:01 +0000 (16:31 +0400)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Wed, 7 Nov 2012 12:31:01 +0000 (16:31 +0400)
driver/probes_manager.c
driver/probes_manager.h
driver/storage.c
driver/us_proc_inst.c
driver/us_proc_inst.h
kprobe/arch/dbi_kprobes.c

index f4f3b5a..3c748c0 100644 (file)
@@ -39,10 +39,12 @@ unsigned long pf_addr;
 unsigned long cp_addr;
 unsigned long mr_addr;
 unsigned long exit_addr;
+unsigned long unmap_addr;
 kernel_probe_t *pf_probe = NULL;
 kernel_probe_t *cp_probe = NULL;
 kernel_probe_t *mr_probe = NULL;
 kernel_probe_t *exit_probe = NULL;
+kernel_probe_t *unmap_probe = NULL;
 unsigned int probes_flags = 0;
 
 int
@@ -81,6 +83,12 @@ probes_manager_init (void)
                return -EINVAL;
        }
 
+       unmap_addr = lookup_name("do_munmap");
+       if (unmap_addr == 0) {
+               EPRINTF("Cannot find address for do_munmap function!");
+               return -EINVAL;
+       }
+
        return storage_init ();
 }
 
@@ -98,6 +106,7 @@ register_kernel_jprobe (kernel_probe_t * probe)
        if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
            ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
            ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
+           ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
            ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)))
        {
                return 0;       // probe is already registered
@@ -117,6 +126,7 @@ unregister_kernel_jprobe (kernel_probe_t * probe)
        if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
            ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
            ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
+           ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
            ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
                return 0;       // probe is necessary for user space instrumentation
        }
@@ -131,6 +141,7 @@ register_kernel_retprobe (kernel_probe_t * probe)
        if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
            ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
            ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
+           ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
            ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
 
                return 0;       // probe is already registered
@@ -151,6 +162,7 @@ unregister_kernel_retprobe (kernel_probe_t * probe)
        if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
            ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
            ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
+           ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
            ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
                return 0;       // probe is necessary for user space instrumentation
        }
@@ -255,6 +267,14 @@ add_probe (unsigned long addr)
                }
                pprobe = &mr_probe;
        }
+       else if (addr == unmap_addr) {
+               probes_flags |= PROBE_FLAG_UNMAP_INSTLD;
+               if (us_proc_probes & US_PROC_UNMAP_INSTLD)
+               {
+                       return 0;
+               }
+               pprobe = &unmap_probe;
+       }
 
        result = add_probe_to_list (addr, pprobe);
        if (result) {
@@ -266,6 +286,8 @@ add_probe (unsigned long addr)
                        probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
                else if (addr == mr_addr)
                        probes_flags &= ~PROBE_FLAG_MR_INSTLD;
+               else if (addr == unmap_addr)
+                       probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
        }
        return result;
 }
@@ -288,6 +310,9 @@ int reset_probes()
                } else if (p->addr == mr_addr) {
                        probes_flags &= ~PROBE_FLAG_MR_INSTLD;
                        mr_probe = NULL;
+               } else if (p->addr == unmap_addr) {
+                       probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
+                       unmap_probe = NULL;
                }
                hlist_del(node);
                kfree(p);
@@ -306,6 +331,9 @@ int reset_probes()
                } else if (p->addr == mr_addr) {
                        probes_flags &= ~PROBE_FLAG_MR_INSTLD;
                        mr_probe = NULL;
+               } else if (p->addr == unmap_addr) {
+                       probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
+                       unmap_probe = NULL;
                }
                hlist_del(node);
                kfree(p);
@@ -356,6 +384,14 @@ remove_probe (unsigned long addr)
                }
                exit_probe = NULL;
        }
+       else if (addr == unmap_addr) {
+               probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
+               if (us_proc_probes & US_PROC_UNMAP_INSTLD)
+               {
+                       return 0;
+               }
+               unmap_probe = NULL;
+       }
 
        result = remove_probe_from_list (addr);
 
@@ -416,6 +452,13 @@ def_jprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long
                if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
                        skip = 1;
        }
+       else if (unmap_probe == probe)
+       {
+               if (us_proc_probes & US_PROC_UNMAP_INSTLD)
+                       do_munmap_probe_pre_code((struct mm_struct *)arg1, arg2, (size_t)arg3);
+               if (!(probes_flags & PROBE_FLAG_UNMAP_INSTLD))
+                       skip = 1;
+       }
 
        if (!skip)
                pack_event_info (KS_PROBE_ID, RECORD_ENTRY, "pxxxxxx", probe->addr, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -453,6 +496,11 @@ def_retprobe_event_handler (struct kretprobe_instance *pi, struct pt_regs *regs,
                if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
                        skip = 1;
        }
+       else if (unmap_probe == probe)
+       {
+               if (!(probes_flags & PROBE_FLAG_UNMAP_INSTLD))
+                       skip = 1;
+       }
 
        if (!skip) {
                ret_val = regs_return_value(regs);
index 9ebe1c1..afe0664 100644 (file)
@@ -56,20 +56,23 @@ extern unsigned long pf_addr;
 extern unsigned long cp_addr;
 extern unsigned long mr_addr;
 extern unsigned long exit_addr;
+extern unsigned long unmap_addr;
 extern kernel_probe_t *pf_probe;
 extern kernel_probe_t *cp_probe;
 extern kernel_probe_t *mr_probe;
 extern kernel_probe_t *exit_probe;
+extern kernel_probe_t *unmap_probe;
 extern unsigned int probes_flags;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
 extern spinlock_t ec_probe_spinlock;
 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
 
 enum {
-       PROBE_FLAG_PF_INSTLD   = (1 << 0),
-       PROBE_FLAG_CP_INSTLD   = (1 << 1),
-       PROBE_FLAG_MR_INSTLD   = (1 << 2),
-       PROBE_FLAG_EXIT_INSTLD = (1 << 3)
+       PROBE_FLAG_PF_INSTLD    = (1 << 0),
+       PROBE_FLAG_CP_INSTLD    = (1 << 1),
+       PROBE_FLAG_MR_INSTLD    = (1 << 2),
+       PROBE_FLAG_EXIT_INSTLD  = (1 << 3),
+       PROBE_FLAG_UNMAP_INSTLD = (1 << 4)
 };
 
 #endif // !defined(__PROBES_MANAGER_H__)
index 86901be..02793a9 100644 (file)
@@ -1617,7 +1617,9 @@ void pack_event_info (probe_id_t probe_id, record_type_t record_type, const char
                addr = get_probe_func_addr(fmt, args);
                va_end(args);
                if( ((addr == pf_addr) && !(probes_flags & PROBE_FLAG_PF_INSTLD)) ||
+                   ((addr == cp_addr) && !(probes_flags & PROBE_FLAG_CP_INSTLD)) ||
                    ((addr == mr_addr) && !(probes_flags & PROBE_FLAG_MR_INSTLD)) ||
+                   ((addr == unmap_addr) && !(probes_flags & PROBE_FLAG_UNMAP_INSTLD)) ||
                    ((addr == exit_addr) && !(probes_flags & PROBE_FLAG_EXIT_INSTLD)) ) {
                        return;
                }
index 13f7a57..956cd64 100644 (file)
@@ -1017,6 +1017,11 @@ int deinst_usr_space_proc (void)
        if (iRet)
                EPRINTF ("uninstall_kernel_probe(do_exit) result=%d!", iRet);
 
+       iRet = uninstall_kernel_probe (unmap_addr, US_PROC_UNMAP_INSTLD,
+                       0, &unmap_probe);
+       if (iRet)
+               EPRINTF ("uninstall_kernel_probe(do_munmap) result=%d!", iRet);
+
        if (!strcmp(us_proc_info.path,"*"))
        {
                for_each_process (task)
@@ -1248,6 +1253,14 @@ int inst_usr_space_proc (void)
                EPRINTF ("install_kernel_probe(mm_release) result=%d!", ret);
                return ret;
        }
+
+       // enable 'do_munmap' probe to detect when for remove user space probes
+       ret = install_kernel_probe (unmap_addr, US_PROC_UNMAP_INSTLD, 0, &unmap_probe);
+       if (ret != 0)
+       {
+               EPRINTF ("install_kernel_probe(do_munmap) result=%d!", ret);
+               return ret;
+       }
        return 0;
 }
 
@@ -1362,6 +1375,114 @@ void do_exit_probe_pre_code (void)
 }
 EXPORT_SYMBOL_GPL(do_exit_probe_pre_code);
 
+static int check_addr(unsigned long addr, unsigned long start, size_t len)
+{
+       if ((addr >= start) && (addr < start + (unsigned long)len)) {
+               return 1;
+       }
+
+       return 0;
+}
+
+static int remove_unmap_probes(struct task_struct *task, inst_us_proc_t* task_inst_info, unsigned long start, size_t len)
+{
+       int i, k, err;
+       us_proc_otg_ip_t *p;
+       unsigned long addr;
+       const int atomic = 1;
+
+       for (i = 0; i < task_inst_info->libs_count; ++i) {
+               for (k = 0; k < task_inst_info->p_libs[i].ips_count; ++k) {
+                       if (task_inst_info->p_libs[i].p_ips[k].installed) {
+                               addr = task_inst_info->p_libs[i].p_ips[k].jprobe.kp.addr;
+                               if (check_addr(addr, start, len)) {
+                                       err = unregister_usprobe(task, &task_inst_info->p_libs[i].p_ips[k], atomic);
+                                       if (err != 0) {
+                                               EPRINTF("failed to uninstall IP at %p. Error %d!", task_inst_info->p_libs[i].p_ips[k].jprobe.kp.addr, err);
+                                               continue;
+                                       }
+                                       task_inst_info->unres_ips_count++;
+                                       task_inst_info->p_libs[i].p_ips[k].installed = 0;
+                               }
+                       }
+               }
+               for (k = 0; k < task_inst_info->p_libs[i].vtps_count; ++k) {
+                       if (task_inst_info->p_libs[i].p_vtps[k].installed) {
+                               addr = task_inst_info->p_libs[i].p_vtps[k].jprobe.kp.addr;
+                               if (check_addr(addr, start, len)) {
+                                       dbi_unregister_ujprobe(task, &task_inst_info->p_libs[i].p_vtps[k].jprobe, atomic);
+                                       task_inst_info->unres_vtps_count++;
+                                       task_inst_info->p_libs[i].p_vtps[k].installed = 0;
+                               }
+                       }
+               }
+               task_inst_info->p_libs[i].loaded = 0;
+       }
+#ifdef __ANDROID
+       if (is_java_inst_enabled()) {
+               us_proc_ip_t *entp = &task_inst_info->libdvm_entry_ip;
+               if (entp->installed) {
+                       addr = entp->jprobe.kp.addr;
+                       if (check_addr(addr, start, len)) {
+                               unregister_usprobe(task, entp, atomic);
+                               entp->installed = 0;
+                       }
+               }
+               us_proc_ip_t *retp = &task_inst_info->libdvm_return_ip;
+               if (retp->installed) {
+                       addr = retp->jprobe.kp.addr;
+                       if (check_addr(addr, start, len)) {
+                               unregister_usprobe(task, retp, atomic);
+                               retp->installed = 0;
+                       }
+               }
+       }
+#endif /* __ANDROID */
+       list_for_each_entry_rcu (p, &otg_us_proc_info, list) {
+               if (!p->ip.installed) {
+                       continue;
+               }
+
+               addr = p->ip.jprobe.kp.addr;
+               if (check_addr(addr, start, len) == 0) {
+                       continue;
+               }
+
+               err = unregister_usprobe(task, &p->ip, atomic);
+               if (err != 0) {
+                       EPRINTF("failed to uninstall IP at %p. Error %d!",
+                                p->ip.jprobe.kp.addr, err);
+                       continue;
+               }
+               p->ip.installed = 0;
+       }
+
+       return 0;
+}
+
+void do_munmap_probe_pre_code(struct mm_struct *mm, unsigned long start, size_t len)
+{
+       inst_us_proc_t *task_inst_info = NULL;
+       struct task_struct *task = current;
+
+       //if user-space instrumentation is not set
+       if (!us_proc_info.path || task->tgid != task->pid)
+               return;
+
+       if (!strcmp(us_proc_info.path,"*")) {
+               task_inst_info = get_task_inst_node(task);
+       } else {
+               if (task->tgid == us_proc_info.tgid) {
+                       task_inst_info = &us_proc_info;
+               }
+       }
+
+       if (task_inst_info) {
+               remove_unmap_probes(task, task_inst_info, start, len);
+       }
+}
+EXPORT_SYMBOL_GPL(do_munmap_probe_pre_code);
+
 void mm_release_probe_pre_code(void)
 {
        int iRet, del = 0;
index 71e9130..78649d4 100644 (file)
@@ -34,6 +34,9 @@ extern void  otg_probe_list_clean(char*);
 /* Detects when target process exits. */
 extern void do_exit_probe_pre_code (void);
 
+/* Detects when target removes IPs. */
+extern void do_munmap_probe_pre_code(struct mm_struct *mm, unsigned long start, size_t len);
+
 /* Detects when target process removes IPs. */
 extern void mm_release_probe_pre_code(void);
 
@@ -44,10 +47,11 @@ extern int us_proc_probes;
 extern pid_t gl_nNotifyTgid;
 
 enum {
-       US_PROC_PF_INSTLD   = (1 << 0),
-       US_PROC_CP_INSTLD   = (1 << 1),
-       US_PROC_MR_INSTLD   = (1 << 2),
-       US_PROC_EXIT_INSTLD = (1 << 3)
+       US_PROC_PF_INSTLD    = (1 << 0),
+       US_PROC_CP_INSTLD    = (1 << 1),
+       US_PROC_MR_INSTLD    = (1 << 2),
+       US_PROC_EXIT_INSTLD  = (1 << 3),
+       US_PROC_UNMAP_INSTLD = (1 << 4)
 };
 
 /* forward declarations */
index f5f7f9c..e00dd81 100644 (file)
@@ -98,8 +98,9 @@ void arch_arm_uretprobe (struct kretprobe *p, struct task_struct *tsk)
 
 void arch_disarm_uprobe (struct kprobe *p, struct task_struct *tsk)
 {
-       if (!write_proc_vm_atomic (tsk, (unsigned long) p->addr, &p->opcode, sizeof (p->opcode)))
-               panic ("failed to write memory %p!\n", p->addr);
+       if (!write_proc_vm_atomic (tsk, (unsigned long) p->addr, &p->opcode, sizeof (p->opcode))) {
+               panic ("failed to write memory: tgid=%u, addr=%p!\n", tsk->tgid, p->addr);
+       }
 }
 EXPORT_SYMBOL_GPL(arch_disarm_uprobe);