[FIX] preload: move swap_do_mmap out of atomic context 86/44786/5
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 27 Jul 2015 14:44:20 +0000 (17:44 +0300)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Thu, 27 Aug 2015 11:42:39 +0000 (04:42 -0700)
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 <v.cherkashin@samsung.com>
preload/preload_module.c
preload/preload_pd.c
preload/preload_pd.h
us_manager/pf/pf_group.c
us_manager/sspt/sspt_proc.c
us_manager/sspt/sspt_proc.h

index 069596f..4269000 100644 (file)
@@ -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)
index b75dde2..568b310 100644 (file)
@@ -6,15 +6,14 @@
 #include <linux/mman.h>
 #include <linux/hardirq.h>
 #include <us_manager/us_manager_common.h>
+#include <us_manager/sspt/sspt_proc.h>
 #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(&current->mm->mmap_sem);
+               page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ,
+                                   MAP_ANONYMOUS | MAP_PRIVATE, 0);
+               up_write(&current->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(&current->mm->mmap_sem);
-#endif
-
-       page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ,
-                           MAP_ANONYMOUS | MAP_PRIVATE, 0);
-#ifdef CONFIG_ARM
-       up_write(&current->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;
index 88facd2..bff469d 100644 (file)
@@ -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);
 
index 5fb56a3..f91a5c6 100644 (file)
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/namei.h>
-
+#include <linux/mman.h>
 #include "pf_group.h"
 #include "proc_filters.h"
 #include "../sspt/sspt_filter.h"
+#include "../us_manager_common.h"
 #include <us_manager/img/img_proc.h>
 #include <us_manager/img/img_file.h>
 #include <us_manager/img/img_ip.h>
@@ -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);
index 88ea025..fff5d16 100644 (file)
@@ -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);
+}
index 1b0f9d2..8597322 100644 (file)
@@ -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__ */