From 361a237b7603bfea67fc3cdb2c5cbed345509471 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Mon, 27 Jul 2015 17:44:20 +0300 Subject: [PATCH] [FIX] preload: move swap_do_mmap out of atomic context For page mapping we should acquire memory lock. It is not possible atomic context. move swap_do_mmap to safe place when mm->mmap_sem is locked. Change-Id: I02847628d800a162f3395a6d73c9cd07240344e0 Signed-off-by: Vyacheslav Cherkashin --- preload/preload_module.c | 46 ++++++----- preload/preload_pd.c | 195 ++++++++++++++++++-------------------------- preload/preload_pd.h | 6 +- us_manager/pf/pf_group.c | 5 +- us_manager/sspt/sspt_proc.c | 26 ++++++ us_manager/sspt/sspt_proc.h | 10 +++ 6 files changed, 146 insertions(+), 142 deletions(-) diff --git a/preload/preload_module.c b/preload/preload_module.c index 069596f..4269000 100644 --- a/preload/preload_module.c +++ b/preload/preload_module.c @@ -62,12 +62,10 @@ static int __preload_cbs_stop_h = -1; static inline struct process_data *__get_process_data(struct uretprobe *rp) { - struct process_data *pd; - struct us_ip *ip = to_us_ip(rp); - - pd = ip_to_proc(ip)->private_data; + struct us_ip *ip = to_us_ip(rp); + struct sspt_proc *proc = ip_to_proc(ip); - return pd; + return preload_pd_get(proc); } static struct dentry *__get_dentry(struct dentry *dentry) @@ -516,6 +514,7 @@ static int mmap_ret_handler(struct kretprobe_instance *ri, { struct mmap_priv *priv = (struct mmap_priv *)ri->data; struct task_struct *task = current->group_leader; + struct process_data *pd; struct sspt_proc *proc; unsigned long vaddr; @@ -530,12 +529,19 @@ static int mmap_ret_handler(struct kretprobe_instance *ri, if (!proc) return 0; + pd = preload_pd_get(proc); + if (pd == NULL) { + printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", + __LINE__, current->tgid, current->comm); + return 0; + } + switch (priv->type) { case MMAP_LOADER: - preload_pd_set_loader_base(proc->private_data, vaddr); + preload_pd_set_loader_base(pd, vaddr); break; case MMAP_HANDLERS: - preload_pd_set_handlers_base(proc->private_data, vaddr); + preload_pd_set_handlers_base(pd, vaddr); break; case MMAP_SKIP: default: @@ -574,6 +580,7 @@ static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs) unsigned long flags = get_preload_flags(current); unsigned long offset = ip->info->pl_i.handler; unsigned long vaddr = 0; + unsigned long base; char __user *path = NULL; if ((flags & HANDLER_RUNNING) || @@ -586,8 +593,12 @@ static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs) if (!__should_we_preload_handlers(current, regs)) goto out_set_origin; + base = preload_pd_get_loader_base(pd); + if (base == 0) + break; /* loader isn't mapped */ + /* jump to loader code if ready */ - vaddr = preload_pd_get_loader_base(pd) + preload_debugfs_get_loader_offset(); + vaddr = base + preload_debugfs_get_loader_offset(); if (vaddr) { /* save original regs state */ __save_uregs(ri, regs); @@ -609,8 +620,12 @@ static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs) /* handlers have not yet been loaded... just ignore */ break; case LOADED: + base = preload_pd_get_handlers_base(pd); + if (base == 0) + break; /* handlers isn't mapped */ + /* jump to preloaded handler */ - vaddr = preload_pd_get_handlers_base(pd) + offset; + vaddr = base + offset; if (vaddr) { unsigned long disable_addr; unsigned long caddr = get_regs_ret_func(regs); @@ -860,14 +875,6 @@ void preload_module_write_msg_exit(struct us_ip *ip) int preload_module_uprobe_init(struct us_ip *ip) { struct uretprobe *rp = &ip->retprobe; - struct sspt_proc *proc = page_to_proc(ip->page); - int ret; - - if (proc->private_data == NULL) { - ret = preload_pd_create_pd(&(proc->private_data), proc->task); - if (ret != 0) - return ret; - } rp->entry_handler = preload_us_entry; rp->handler = preload_us_ret; @@ -875,16 +882,11 @@ int preload_module_uprobe_init(struct us_ip *ip) * to dlopen */ rp->data_size = sizeof(struct us_priv); - preload_pd_inc_refs(proc->private_data); - return 0; } void preload_module_uprobe_exit(struct us_ip *ip) { - struct sspt_proc *proc = ip_to_proc(ip); - - preload_pd_dec_refs(proc->private_data); } int preload_set(void) diff --git a/preload/preload_pd.c b/preload/preload_pd.c index b75dde2..568b310 100644 --- a/preload/preload_pd.c +++ b/preload/preload_pd.c @@ -6,15 +6,14 @@ #include #include #include +#include #include "preload_pd.h" #include "preload_threads.h" #include "preload_debugfs.h" #include "preload_storage.h" -#include "preload_patcher.h" #include "preload.h" struct process_data { - char is_mapped; enum preload_state_t state; unsigned long loader_base; unsigned long handlers_base; @@ -116,36 +115,6 @@ static inline void __set_refcount(struct process_data *pd, long refcount) -static unsigned long __find_dentry_base(struct mm_struct *mm, - struct dentry *dentry) -{ - struct vm_area_struct *vma; - - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (check_vma(vma, dentry)) - return vma->vm_start; - } - - return 0; -} - -static unsigned long find_dentry_base(struct task_struct *task, - struct dentry *dentry) -{ - struct mm_struct *mm = task->mm; - unsigned long addr; - -#ifdef CONFIG_ARM - down_read(&mm->mmap_sem); -#endif /* CONFIG_ARM */ - addr = __find_dentry_base(mm, dentry); -#ifdef CONFIG_ARM - up_read(&mm->mmap_sem); -#endif /* CONFIG_ARM */ - - return addr; -} - static int __pd_create_on_demand(void) { if (handlers_info == NULL) { @@ -181,19 +150,13 @@ void preload_pd_set_state(struct process_data *pd, enum preload_state_t state) unsigned long preload_pd_get_loader_base(struct process_data *pd) { if (pd == NULL) - return ERROR; + return 0; return __get_loader_base(pd); } void preload_pd_set_loader_base(struct process_data *pd, unsigned long vaddr) { - if (pd == NULL) { - printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__, - current->tgid, current->comm); - return; - } - __set_loader_base(pd, vaddr); } @@ -207,12 +170,6 @@ unsigned long preload_pd_get_handlers_base(struct process_data *pd) void preload_pd_set_handlers_base(struct process_data *pd, unsigned long vaddr) { - if (pd == NULL) { - printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__, - current->tgid, current->comm); - return; - } - __set_handlers_base(pd, vaddr); } @@ -232,38 +189,9 @@ void preload_pd_put_path(struct process_data *pd) char __user *preload_pd_get_path(struct process_data *pd) { - /* This function should be called only for current */ - - struct task_struct *task = current; - unsigned long page = 0; - int ret; - - if (pd == NULL) - return NULL; - - page = __get_data_page(pd); + char __user *path = __get_path(pd); - if (page == 0) - return NULL; - - if (pd->is_mapped == 1) - return __get_path(pd); - - ret = preload_patcher_write_string((void *)page, handlers_info->path, - strnlen(handlers_info->path, PATH_MAX), - task); - if (ret <= 0) { - printk(KERN_ERR PRELOAD_PREFIX "Cannot copy string to user!\n"); - goto get_path_failed; - } - - pd->is_mapped = 1; - - return __get_path(pd); - -get_path_failed: - - return NULL; + return path; } @@ -348,72 +276,107 @@ long preload_pd_get_refs(struct process_data *pd) return __get_refcount(pd); } -int preload_pd_create_pd(void **target_place, struct task_struct *task) +struct process_data *preload_pd_get(struct sspt_proc *proc) +{ + return (struct process_data *)proc->private_data; +} + +static unsigned long make_preload_path(void) +{ + unsigned long page = -EINVAL; + + if (handlers_info) { + const char *path = handlers_info->path; + size_t len = strnlen(path, PATH_MAX); + + down_write(¤t->mm->mmap_sem); + page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + up_write(¤t->mm->mmap_sem); + + if (IS_ERR_VALUE(page)) { + printk(KERN_ERR PRELOAD_PREFIX + "Cannot alloc page for %u\n", current->tgid); + goto out; + } + + /* set preload_library path */ + if (copy_to_user((void __user *)page, path, len) <= 0) + printk(KERN_ERR PRELOAD_PREFIX + "Cannot copy string to user!\n"); + } + +out: + return page; +} + +static struct process_data *do_create_pd(struct task_struct *task) { struct process_data *pd; - unsigned long page = 0; - unsigned long base; - struct dentry *dentry; - int ret = 0; + unsigned long page; + int ret; ret = __pd_create_on_demand(); if (ret) - return ret; + goto create_pd_exit; pd = kzalloc(sizeof(*pd), GFP_ATOMIC); - if (pd == NULL) - return -ENOMEM; - - /* 1. check if loader is already mapped */ - dentry = preload_debugfs_get_loader_dentry(); - base = find_dentry_base(task, dentry); - if (base) - __set_loader_base(pd, base); - - /* 2. check if handlers are already mapped */ - base = find_dentry_base(task, handlers_info->dentry); - if (base) { - __set_handlers_base(pd, base); - __set_state(pd, LOADED); - } - - /* 3. map page to store path */ -#ifdef CONFIG_ARM - down_write(¤t->mm->mmap_sem); -#endif - - page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ, - MAP_ANONYMOUS | MAP_PRIVATE, 0); -#ifdef CONFIG_ARM - up_write(¤t->mm->mmap_sem); -#endif - if (IS_ERR((void *)page)) { - printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc page for %u\n", task->tgid); + if (pd == NULL) { ret = -ENOMEM; goto create_pd_exit; } - pd->is_mapped = 0; + page = make_preload_path(); + if (IS_ERR_VALUE(page)) { + ret = (long)page; + goto free_pd; + } __set_data_page(pd, page); __set_attempts(pd, PRELOAD_MAX_ATTEMPTS); - *target_place = pd; + return pd; - return ret; +free_pd: + kfree(pd); create_pd_exit: - kfree(pd); - return ret; + printk(KERN_ERR PRELOAD_PREFIX "do_pd_create_pd: error=%d\n", ret); + return NULL; +} + +static void *pd_create(struct sspt_proc *proc) +{ + struct process_data *pd; + + pd = do_create_pd(proc->task); + + return (void *)pd; +} + +static void pd_destroy(struct sspt_proc *proc, void *data) +{ + /* FIXME: to be implemented */ } +struct sspt_proc_cb pd_cb = { + .priv_create = pd_create, + .priv_destroy = pd_destroy +}; + int preload_pd_init(void) { - return 0; + int ret; + + ret = sspt_proc_cb_set(&pd_cb); + + return ret; } void preload_pd_uninit(void) { + sspt_proc_cb_set(NULL); + if (handlers_info) preload_storage_put_handlers_info(handlers_info); handlers_info = NULL; diff --git a/preload/preload_pd.h b/preload/preload_pd.h index 88facd2..bff469d 100644 --- a/preload/preload_pd.h +++ b/preload/preload_pd.h @@ -2,7 +2,7 @@ #define __PRELOAD_PD_H__ struct process_data; -struct task_struct; +struct sspt_proc; /* process preload states */ enum preload_state_t { @@ -13,6 +13,8 @@ enum preload_state_t { ERROR }; +struct process_data *preload_pd_get(struct sspt_proc *proc); + enum preload_state_t preload_pd_get_state(struct process_data *pd); void preload_pd_set_state(struct process_data *pd, enum preload_state_t state); unsigned long preload_pd_get_loader_base(struct process_data *pd); @@ -32,8 +34,6 @@ long preload_pd_get_refs(struct process_data *pd); char __user *preload_pd_get_path(struct process_data *pd); void preload_pd_put_path(struct process_data *pd); -int preload_pd_create_pd(void **target_place, struct task_struct *task); - int preload_pd_init(void); void preload_pd_uninit(void); diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c index 5fb56a3..f91a5c6 100644 --- a/us_manager/pf/pf_group.c +++ b/us_manager/pf/pf_group.c @@ -27,10 +27,11 @@ #include #include #include - +#include #include "pf_group.h" #include "proc_filters.h" #include "../sspt/sspt_filter.h" +#include "../us_manager_common.h" #include #include #include @@ -173,6 +174,8 @@ static void msg_info(struct sspt_filter *f, void *data) static void first_install(struct task_struct *task, struct sspt_proc *proc) { + sspt_proc_priv_create(proc); + down_write(&task->mm->mmap_sem); sspt_proc_on_each_filter(proc, msg_info, NULL); sspt_proc_install(proc); diff --git a/us_manager/sspt/sspt_proc.c b/us_manager/sspt/sspt_proc.c index 88ea025..fff5d16 100644 --- a/us_manager/sspt/sspt_proc.c +++ b/us_manager/sspt/sspt_proc.c @@ -515,3 +515,29 @@ bool sspt_proc_is_send_event(struct sspt_proc *proc) return is_send; } + + +static struct sspt_proc_cb *proc_cb; + +int sspt_proc_cb_set(struct sspt_proc_cb *cb) +{ + if (cb && proc_cb) + return -EBUSY; + + proc_cb = cb; + + return 0; +} +EXPORT_SYMBOL_GPL(sspt_proc_cb_set); + +void sspt_proc_priv_create(struct sspt_proc *proc) +{ + if (proc_cb && proc_cb->priv_create) + proc->private_data = proc_cb->priv_create(proc); +} + +void sspt_proc_priv_destroy(struct sspt_proc *proc) +{ + if (proc->first_install && proc_cb && proc_cb->priv_destroy) + proc_cb->priv_destroy(proc, proc->private_data); +} diff --git a/us_manager/sspt/sspt_proc.h b/us_manager/sspt/sspt_proc.h index 1b0f9d2..8597322 100644 --- a/us_manager/sspt/sspt_proc.h +++ b/us_manager/sspt/sspt_proc.h @@ -52,9 +52,15 @@ struct sspt_proc { struct list_head filter_list; /**< Filter list */ unsigned first_install:1; /**< Install flag */ struct sspt_feature *feature; /**< Ptr to the feature */ + + /* FIXME: for preload (remove those fields) */ void *private_data; /**< Process private data */ }; +struct sspt_proc_cb { + void *(*priv_create)(struct sspt_proc *); + void (*priv_destroy)(struct sspt_proc *, void *); +}; struct sspt_proc *sspt_proc_create(struct task_struct *task); void sspt_proc_free(struct sspt_proc *proc); @@ -101,4 +107,8 @@ void sspt_proc_on_each_filter(struct sspt_proc *proc, bool sspt_proc_is_send_event(struct sspt_proc *proc); +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); + #endif /* __SSPT_PROC__ */ -- 2.7.4