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
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 ();
}
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
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
}
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
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
}
}
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) {
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;
}
} 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);
} 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);
}
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);
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);
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);
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__)
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;
}
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)
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;
}
}
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;
/* 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);
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 */
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);