From d9a47199f58786b456bab8d8c5527c659084c212 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Wed, 6 Apr 2016 15:46:57 +0300 Subject: [PATCH] [IMPROVE] storing sspt_proc in group_leader's stack Change-Id: I3ea8e4809efe461c24949ab543ba11e317847504 Signed-off-by: Vyacheslav Cherkashin --- energy/energy.c | 2 +- preload/preload_module.c | 6 +- preload/preload_pd.c | 2 +- us_manager/helper.c | 67 ++++++++++++++--- us_manager/pf/pf_group.c | 95 ++++++++++++++++++++----- us_manager/sspt/sspt.h | 2 +- us_manager/sspt/sspt_file.c | 2 +- us_manager/sspt/sspt_filter.c | 2 +- us_manager/sspt/sspt_page.c | 2 +- us_manager/sspt/sspt_proc.c | 162 ++++++++++++++++++++++++++++-------------- us_manager/sspt/sspt_proc.h | 17 +++-- us_manager/us_manager.c | 18 ++++- 12 files changed, 280 insertions(+), 97 deletions(-) diff --git a/energy/energy.c b/energy/energy.c index 6eb863c..5a44dae 100644 --- a/energy/energy.c +++ b/energy/energy.c @@ -295,7 +295,7 @@ static struct energy_data *get_energy_data(struct task_struct *task) void *data = NULL; struct sspt_proc *proc; - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc) data = sspt_get_feature_data(proc->feature, feature_id); diff --git a/preload/preload_module.c b/preload/preload_module.c index b8d613d..650e7bb 100644 --- a/preload/preload_module.c +++ b/preload/preload_module.c @@ -266,7 +266,7 @@ static bool __is_proc_mmap_mappable(struct task_struct *task) return false; r_debug_addr += r_state_offset; - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc) proc->r_state_addr = r_debug_addr; @@ -333,7 +333,7 @@ static int mmap_entry_handler(struct kretprobe_instance *ri, return 0; } - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (!proc) return 0; @@ -372,7 +372,7 @@ static int mmap_ret_handler(struct kretprobe_instance *ri, if (IS_ERR_VALUE(vaddr)) return 0; - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (!proc) return 0; diff --git a/preload/preload_pd.c b/preload/preload_pd.c index 17aa742..62c242d 100644 --- a/preload/preload_pd.c +++ b/preload/preload_pd.c @@ -407,7 +407,7 @@ static void *pd_create(struct sspt_proc *proc) { struct pd_t *pd; - pd = do_create_pd(proc->task); + pd = do_create_pd(proc->leader); return (void *)pd; } diff --git a/us_manager/helper.c b/us_manager/helper.c index 92d829b..7bdb801 100644 --- a/us_manager/helper.c +++ b/us_manager/helper.c @@ -69,7 +69,7 @@ static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs) #endif /* CONFIG_arch */ if (data->addr) { - struct sspt_proc * proc = sspt_proc_get_by_task(current); + struct sspt_proc *proc = sspt_proc_by_task(current); if (proc && (proc->r_state_addr == data->addr)) /* skip ret_handler_pf() for current task */ @@ -212,7 +212,7 @@ static void rm_uprobes_child(struct kretprobe_instance *ri, }; sspt_proc_write_lock(); - proc = sspt_proc_get_by_task_no_lock(current); + proc = sspt_proc_by_task(current); if (proc) { sspt_proc_on_each_ip(proc, func_uinst_creare, (void *)&cdata.head); urinst_info_get_current_hlist(&cdata.rhead, false); @@ -359,7 +359,7 @@ static unsigned long mr_cb(void *data) /* TODO: this lock for synchronizing to disarm urp */ down_write(&mm->mmap_sem); - if (task->tgid != task->pid) { + if (task != task->group_leader) { struct sspt_proc *proc; struct hlist_head head = HLIST_HEAD_INIT; @@ -371,7 +371,7 @@ static unsigned long mr_cb(void *data) /* if the thread is killed we need to discard pending * uretprobe instances which have not triggered yet */ sspt_proc_write_lock(); - proc = sspt_proc_get_by_task_no_lock(task); + proc = sspt_proc_by_task(task); if (proc) { urinst_info_get_current_hlist(&head, true); } @@ -481,7 +481,7 @@ static void __remove_unmap_probes(struct sspt_proc *proc, if (sspt_proc_get_files_by_region(proc, &head, start, len)) { struct sspt_file *file, *n; unsigned long end = start + len; - struct task_struct *task = proc->task; + struct task_struct *task = proc->leader; list_for_each_entry_safe(file, n, &head, list) { if (file->vm_start >= end) @@ -503,7 +503,7 @@ static void remove_unmap_probes(struct task_struct *task, sspt_proc_write_lock(); - proc = sspt_proc_get_by_task_no_lock(task); + proc = sspt_proc_by_task(task); if (proc) { struct msg_unmap_data msg_data = { .start = umd->start, @@ -615,7 +615,7 @@ static int ret_handler_mmap(struct kretprobe_instance *ri, if (IS_ERR_VALUE(start_addr)) return 0; - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc == NULL) return 0; @@ -723,6 +723,43 @@ static void unregister_comm(void) +/* + ****************************************************************************** + * release_task() * + ****************************************************************************** + */ +static int release_task_h(struct kprobe *p, struct pt_regs *regs) +{ + struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0); + struct task_struct *cur = current; + + if (cur->flags & PF_KTHREAD) + return 0; + + /* EXEC: change group leader */ + if (cur != task && task->pid == cur->pid) + sspt_change_leader(task, cur); + + return 0; +} + +struct kprobe release_task_kp = { + .pre_handler = release_task_h, +}; + +static int reg_release_task(void) +{ + return swap_register_kprobe(&release_task_kp); +} + +static void unreg_release_task(void) +{ + swap_unregister_kprobe(&release_task_kp); +} + + + + /** * @brief Registration of helper @@ -735,13 +772,18 @@ int register_helper(void) atomic_set(&stop_flag, 0); + /* tracking group leader changing */ + ret = reg_release_task(); + if (ret) + return ret; + /* * install probe on 'set_task_comm' to detect when field comm struct * task_struct changes */ ret = register_comm(); if (ret) - return ret; + goto unreg_rel_task; /* install probe on 'do_munmap' to detect when for remove US probes */ ret = register_unmap(); @@ -788,6 +830,9 @@ unreg_unmap: unreg_comm: unregister_comm(); +unreg_rel_task: + unreg_release_task(); + return ret; } @@ -814,6 +859,7 @@ void unregister_helper_bottom(void) unregister_mr(); unregister_unmap(); unregister_comm(); + unreg_release_task(); } /** @@ -856,6 +902,11 @@ int once_helper(void) if (comm_kretprobe.kp.addr == NULL) goto not_found; + sym = "release_task"; + release_task_kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (release_task_kp.addr == NULL) + goto not_found; + return 0; not_found: diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c index 5bafc1b..3665b09 100644 --- a/us_manager/pf/pf_group.c +++ b/us_manager/pf/pf_group.c @@ -158,6 +158,26 @@ static int pfg_add_proc(struct pf_group *pfg, struct sspt_proc *proc) return 0; } +static int pfg_del_proc(struct pf_group *pfg, struct sspt_proc *proc) +{ + struct pl_struct *pls, *pls_free = NULL; + + spin_lock(&pfg->pl_lock); + list_for_each_entry(pls, &pfg->proc_list, list) { + if (pls->proc == proc) { + list_del(&pls->list); + pls_free = pls; + break; + } + } + spin_unlock(&pfg->pl_lock); + + if (pls_free) + free_pl_struct(pls_free); + + return !!pls_free; +} + /* called with pfg_list_lock held */ static void pfg_add_to_list(struct pf_group *pfg) @@ -186,10 +206,10 @@ static void msg_info(struct sspt_filter *f, void *data) dentry = (struct dentry *)f->pfg->filter.priv; if (cb->msg_info) - cb->msg_info(f->proc->task, dentry); + cb->msg_info(f->proc->leader, dentry); if (cb->msg_status_info) - cb->msg_status_info(f->proc->task); + cb->msg_status_info(f->proc->leader); } } } @@ -492,7 +512,7 @@ static enum pf_inst_flag pfg_check_task(struct task_struct *task) continue; if (proc == NULL) - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc) { flag = flag == PIF_NONE ? PIF_SECOND : flag; @@ -521,6 +541,16 @@ static enum pf_inst_flag pfg_check_task(struct task_struct *task) return flag; } +static void pfg_all_del_proc(struct sspt_proc *proc) +{ + struct pf_group *pfg; + + pfg_list_rlock(); + list_for_each_entry(pfg, &pfg_list, list) + pfg_del_proc(pfg, proc); + pfg_list_runlock(); +} + /** * @brief Check task and install probes on demand * @@ -536,7 +566,7 @@ void check_task_and_install(struct task_struct *task) switch (flag) { case PIF_FIRST: case PIF_ADD_PFG: - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc) first_install(task, proc); break; @@ -563,13 +593,13 @@ void call_page_fault(struct task_struct *task, unsigned long page_addr) switch (flag) { case PIF_FIRST: case PIF_ADD_PFG: - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc) first_install(task, proc); break; case PIF_SECOND: - proc = sspt_proc_get_by_task(task); + proc = sspt_proc_by_task(task); if (proc) subsequent_install(task, proc, page_addr); break; @@ -589,12 +619,38 @@ void call_page_fault(struct task_struct *task, unsigned long page_addr) /* called with sspt_proc_write_lock() */ void uninstall_proc(struct sspt_proc *proc) { - struct task_struct *task = proc->task; + struct task_struct *task = proc->leader; sspt_proc_uninstall(proc, task, US_UNREGS_PROBE); sspt_proc_cleanup(proc); } + +static void mmr_from_exit(struct sspt_proc *proc) +{ + BUG_ON(proc->leader != current); + + sspt_proc_write_lock(); + list_del(&proc->list); + sspt_proc_write_unlock(); + + uninstall_proc(proc); + + pfg_all_del_proc(proc); + sspt_reset_proc(proc->leader); +} + +static void mmr_from_exec(struct sspt_proc *proc) +{ + BUG_ON(proc->leader != current); + + if (proc->suspect.after_exec) { + sspt_proc_uninstall(proc, proc->leader, US_UNREGS_PROBE); + } else { + mmr_from_exit(proc); + } +} + /** * @brief Remove probes from the task on demand * @@ -605,14 +661,13 @@ void call_mm_release(struct task_struct *task) { struct sspt_proc *proc; - sspt_proc_write_lock(); - proc = sspt_proc_get_by_task_no_lock(task); - if (proc) - list_del(&proc->list); - sspt_proc_write_unlock(); - - if (proc) - uninstall_proc(proc); + proc = sspt_proc_by_task(task); + if (proc) { + if (task->flags & PF_EXITING) + mmr_from_exit(proc); + else + mmr_from_exec(proc); + } } /** @@ -650,7 +705,7 @@ static void tasks_get(struct list_head *head) if (task->flags & PF_KTHREAD) continue; - if (sspt_proc_get_by_task(task)) + if (sspt_proc_by_task(task)) continue; /* TODO: get rid of GFP_ATOMIC */ @@ -745,9 +800,11 @@ void uninstall_all(void) static void __do_get_proc(struct sspt_proc *proc, void *data) { - get_task_struct(proc->task); - proc->__task = proc->task; - proc->__mm = get_task_mm(proc->task); + struct task_struct *task = proc->leader; + + get_task_struct(task); + proc->__task = task; + proc->__mm = get_task_mm(task); } static void __do_put_proc(struct sspt_proc *proc, void *data) diff --git a/us_manager/sspt/sspt.h b/us_manager/sspt/sspt.h index bc8b6f5..8bec181 100644 --- a/us_manager/sspt/sspt.h +++ b/us_manager/sspt/sspt.h @@ -59,7 +59,7 @@ static inline int sspt_register_usprobe(struct sspt_ip *ip) } up->addr = (kprobe_opcode_t *)ip->orig_addr; - up->task = ip->page->file->proc->task; + up->task = ip->page->file->proc->leader; up->sm = ip->page->file->proc->sm; ret = probe_info_register(ip->desc->type, ip); diff --git a/us_manager/sspt/sspt_file.c b/us_manager/sspt/sspt_file.c index 2ad0b8a..c700f39 100644 --- a/us_manager/sspt/sspt_file.c +++ b/us_manager/sspt/sspt_file.c @@ -284,7 +284,7 @@ void sspt_file_install(struct sspt_file *file) page_addr >= file->vm_end) continue; - mm = page->file->proc->task->mm; + mm = page->file->proc->leader->mm; if (page_present(mm, page_addr)) sspt_register_page(page, file); } diff --git a/us_manager/sspt/sspt_filter.c b/us_manager/sspt/sspt_filter.c index 2925d7f..f7a0799 100644 --- a/us_manager/sspt/sspt_filter.c +++ b/us_manager/sspt/sspt_filter.c @@ -29,7 +29,7 @@ void sspt_filter_free(struct sspt_filter *fl) struct pfg_msg_cb *cb = pfg_msg_cb_get(fl->pfg); if (cb && cb->msg_term) - cb->msg_term(fl->proc->task); + cb->msg_term(fl->proc->leader); } kfree(fl); diff --git a/us_manager/sspt/sspt_page.c b/us_manager/sspt/sspt_page.c index 54971f9..d5e7640 100644 --- a/us_manager/sspt/sspt_page.c +++ b/us_manager/sspt/sspt_page.c @@ -144,7 +144,7 @@ int sspt_register_page(struct sspt_page *page, struct sspt_file *file) spin_lock(&page->ip_list.lock); if (list_empty(&page->ip_list.not_inst)) { - struct task_struct *task = page->file->proc->task; + struct task_struct *task = page->file->proc->leader; printk(KERN_INFO "page %lx in %s task[tgid=%u, pid=%u] " "already installed\n", diff --git a/us_manager/sspt/sspt_proc.c b/us_manager/sspt/sspt_proc.c index 2a45014..0f70788 100644 --- a/us_manager/sspt/sspt_proc.c +++ b/us_manager/sspt/sspt_proc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static LIST_HEAD(proc_probes_list); @@ -83,16 +84,79 @@ void sspt_proc_write_unlock(void) } -/** - * @brief Create sspt_proc struct - * - * @param task Pointer to the task_struct struct - * @param priv Private data - * @return Pointer to the created sspt_proc struct - */ -struct sspt_proc *sspt_proc_create(struct task_struct *task) +static void ktd_init(struct task_struct *task, void *data) +{ + struct sspt_proc **pproc = (struct sspt_proc **)data; + + *pproc = NULL; +} + +static void ktd_exit(struct task_struct *task, void *data) +{ + struct sspt_proc **pproc = (struct sspt_proc **)data; + + WARN_ON(*pproc); +} + +struct ktask_data ktd = { + .init = ktd_init, + .exit = ktd_exit, + .size = sizeof(struct sspt_proc *), +}; + +static struct sspt_proc **pproc_by_task(struct task_struct *task) +{ + return (struct sspt_proc **)swap_ktd(&ktd, task); +} + +int sspt_proc_init(void) +{ + return swap_ktd_reg(&ktd); +} + +void sspt_proc_uninit(void) +{ + swap_ktd_unreg(&ktd); +} + +void sspt_change_leader(struct task_struct *prev, struct task_struct *next) +{ + struct sspt_proc **prev_pproc; + + prev_pproc = pproc_by_task(prev); + if (*prev_pproc) { + struct sspt_proc **next_pproc; + + next_pproc = pproc_by_task(next); + get_task_struct(next); + + /* Change the keeper sspt_proc */ + BUG_ON(*next_pproc); + *next_pproc = *prev_pproc; + *prev_pproc = NULL; + + /* Set new the task leader to sspt_proc */ + (*next_pproc)->leader = next; + + put_task_struct(prev); + } +} + +void sspt_reset_proc(struct task_struct *task) { - struct sspt_proc *proc = kzalloc(sizeof(*proc), GFP_ATOMIC); + struct sspt_proc **pproc; + + pproc = pproc_by_task(task->group_leader); + *pproc = NULL; +} + + + + + +static struct sspt_proc *sspt_proc_create(struct task_struct *leader) +{ + struct sspt_proc *proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc) { proc->feature = sspt_create_feature(); @@ -102,18 +166,19 @@ struct sspt_proc *sspt_proc_create(struct task_struct *task) } INIT_LIST_HEAD(&proc->list); - proc->tgid = task->tgid; - proc->task = task->group_leader; - proc->sm = create_sm_us(task); + proc->tgid = leader->tgid; + proc->leader = leader; + /* FIXME: change the task leader */ + proc->sm = create_sm_us(leader); INIT_LIST_HEAD(&proc->file_head); mutex_init(&proc->filters.mtx); INIT_LIST_HEAD(&proc->filters.head); atomic_set(&proc->usage, 1); - get_task_struct(proc->task); + get_task_struct(proc->leader); - /* add to list */ - list_add(&proc->list, &proc_probes_list); + proc->suspect.after_exec = 1; + proc->suspect.after_fork = 0; } return proc; @@ -163,41 +228,16 @@ void sspt_proc_put(struct sspt_proc *proc) proc->__task = NULL; } - put_task_struct(proc->task); + put_task_struct(proc->leader); kfree(proc); } } -struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task) +struct sspt_proc *sspt_proc_by_task(struct task_struct *task) { - struct sspt_proc *proc; - - sspt_proc_read_lock(); - proc = sspt_proc_get_by_task_no_lock(task); - sspt_proc_read_unlock(); - - return proc; + return *pproc_by_task(task->group_leader); } -EXPORT_SYMBOL_GPL(sspt_proc_get_by_task); - -/** - * @brief Get sspt_proc by task - * - * @param task Pointer on the task_struct struct - * @return Pointer on the sspt_proc struct - */ -struct sspt_proc *sspt_proc_get_by_task_no_lock(struct task_struct *task) -{ - struct sspt_proc *proc, *tmp; - - list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) { - if (proc->tgid == task->tgid) - return proc; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(sspt_proc_get_by_task_no_lock); +EXPORT_SYMBOL_GPL(sspt_proc_by_task); /** * @brief Call func() on each proc (no lock) @@ -239,15 +279,29 @@ EXPORT_SYMBOL_GPL(on_each_proc); */ struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task) { - struct sspt_proc *proc; - - sspt_proc_write_lock(); - proc = sspt_proc_get_by_task_no_lock(task); - if (proc == NULL) - proc = sspt_proc_create(task); - sspt_proc_write_unlock(); + static DEFINE_MUTEX(local_mutex); + struct sspt_proc **pproc; + struct task_struct *leader = task->group_leader; + + pproc = pproc_by_task(leader); + if (*pproc) + goto out; + + /* This lock for synchronizing to create sspt_proc */ + mutex_lock(&local_mutex); + pproc = pproc_by_task(leader); + if (*pproc == NULL) { + *pproc = sspt_proc_create(leader); + if (*pproc) { + sspt_proc_write_lock(); + list_add(&(*pproc)->list, &proc_probes_list); + sspt_proc_write_unlock(); + } + } + mutex_unlock(&local_mutex); - return proc; +out: + return *pproc; } /** @@ -322,7 +376,7 @@ struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc, */ void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr) { - struct mm_struct *mm = proc->task->mm; + struct mm_struct *mm = proc->leader->mm; struct vm_area_struct *vma; vma = find_vma_intersection(mm, page_addr, page_addr + 1); @@ -350,7 +404,7 @@ void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr) void sspt_proc_install(struct sspt_proc *proc) { struct vm_area_struct *vma; - struct mm_struct *mm = proc->task->mm; + struct mm_struct *mm = proc->leader->mm; proc->first_install = 1; diff --git a/us_manager/sspt/sspt_proc.h b/us_manager/sspt/sspt_proc.h index 740c9c2..54eb80d 100644 --- a/us_manager/sspt/sspt_proc.h +++ b/us_manager/sspt/sspt_proc.h @@ -52,12 +52,17 @@ struct sspt_proc { struct list_head file_head; /**< For sspt_file */ pid_t tgid; /**< Thread group ID */ - struct task_struct *task; /**< Ptr to the task */ + struct task_struct *leader; /**< Ptr to the task leader */ struct mm_struct *__mm; struct task_struct *__task; struct slot_manager *sm; /**< Ptr to the manager slot */ struct { + unsigned after_exec:1; + unsigned after_fork:1; + } suspect; + + struct { struct mutex mtx; /**< Mutex for filter list */ struct list_head head; /**< Filter head */ } filters; @@ -79,7 +84,6 @@ struct sspt_proc_cb { struct list_head *sspt_proc_list(void); -struct sspt_proc *sspt_proc_create(struct task_struct *task); void sspt_proc_cleanup(struct sspt_proc *proc); struct sspt_proc *sspt_proc_get(struct sspt_proc *proc); void sspt_proc_put(struct sspt_proc *proc); @@ -88,8 +92,7 @@ void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *), void *data); void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data); -struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task); -struct sspt_proc *sspt_proc_get_by_task_no_lock(struct task_struct *task); +struct sspt_proc *sspt_proc_by_task(struct task_struct *task); struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task); void sspt_proc_free_all(void); @@ -131,4 +134,10 @@ int sspt_proc_cb_set(struct sspt_proc_cb *cb); void sspt_proc_priv_create(struct sspt_proc *proc); void sspt_proc_priv_destroy(struct sspt_proc *proc); +void sspt_reset_proc(struct task_struct *task); +void sspt_change_leader(struct task_struct *prev, struct task_struct *next); +int sspt_proc_init(void); +void sspt_proc_uninit(void); + + #endif /* __SSPT_PROC__ */ diff --git a/us_manager/us_manager.c b/us_manager/us_manager.c index 25c6c31..9b66b6e 100644 --- a/us_manager/us_manager.c +++ b/us_manager/us_manager.c @@ -200,7 +200,7 @@ static int us_filter(struct task_struct *task) struct sspt_proc *proc; /* FIXME: add read lock (deadlock in sampler) */ - proc = sspt_proc_get_by_task_no_lock(task); + proc = sspt_proc_by_task(task); if (proc) return sspt_proc_is_send_event(proc); @@ -245,13 +245,24 @@ static int init_us_manager(void) { int ret; - ret = pin_init(); + ret = sspt_proc_init(); if (ret) return ret; + ret = pin_init(); + if (ret) + goto uninit_proc; + ret = init_us_filter(); if (ret) - pin_exit(); + goto uninit_pin; + + return 0; + +uninit_pin: + pin_exit(); +uninit_proc: + sspt_proc_uninit(); return ret; } @@ -265,6 +276,7 @@ static void exit_us_manager(void) exit_us_filter(); pin_exit(); + sspt_proc_uninit(); } SWAP_LIGHT_INIT_MODULE(usm_once, init_us_manager, exit_us_manager, -- 2.7.4