[IMPROVE] Preload: split loading and probe execution 90/54090/5
authorAlexander Aksenov <a.aksenov@samsung.com>
Mon, 30 Nov 2015 10:59:43 +0000 (13:59 +0300)
committerAlexander Aksenov <a.aksenov@samsung.com>
Fri, 11 Dec 2015 12:54:01 +0000 (15:54 +0300)
Previously both loading binary in target process memory and
an execution of handlers from the SWAP library were implemented
as a one instance.
Now they are splitted, cause some features requires loading
custom binaries into a process memory, but doesn't need SWAP
library handlers execution functionality.

Change-Id: I8408f1e2a144267bb2d4b0f33706b08558ffbd26
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
preload/preload_module.c
preload/preload_module.h
preload/preload_pd.c
preload/preload_pd.h
preload/preload_storage.c
preload/preload_storage.h

index 5ecd8f7..c376086 100644 (file)
@@ -59,6 +59,8 @@ static enum preload_status_t __preload_status = SWAP_PRELOAD_NOT_READY;
 static int __preload_cbs_start_h = -1;
 static int __preload_cbs_stop_h = -1;
 
+static struct dentry *handler_dentry = NULL;
+
 static inline struct pd_t *__get_process_data(struct uretprobe *rp)
 {
        struct us_ip *ip = to_us_ip(rp);
@@ -189,24 +191,30 @@ static inline void __restore_uregs(struct uretprobe_instance *ri,
 }
 
 static inline void print_regs(const char *prefix, struct pt_regs *regs,
-                             struct uretprobe_instance *ri)
+                             struct uretprobe_instance *ri, struct hd_t *hd)
 {
+       struct dentry *dentry = preload_pd_get_dentry(hd);
+
 #ifdef CONFIG_ARM
-       printk(PRELOAD_PREFIX "%s[%d/%d] (%d) %s addr(%08lx), "
+       printk(PRELOAD_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), "
               "r0(%08lx), r1(%08lx), r2(%08lx), r3(%08lx), "
               "r4(%08lx), r5(%08lx), r6(%08lx), r7(%08lx), "
               "sp(%08lx), lr(%08lx), pc(%08lx)\n",
               current->comm, current->tgid, current->pid,
-              (int)preload_pd_get_state(__get_process_data(ri->rp)),
+              dentry != NULL ? (char *)(dentry->d_name.name) :
+                               (char *)("NULL"),
+              (int)preload_pd_get_state(hd),
               prefix, (unsigned long)ri->rp->up.addr,
               regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3,
               regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7,
               regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
 #else /* !CONFIG_ARM */
-       printk(PRELOAD_PREFIX "%s[%d/%d] (%d) %s addr(%08lx), "
+       printk(PRELOAD_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), "
               "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n",
               current->comm, current->tgid, current->pid,
-              (int)preload_pd_get_state(__get_process_data(ri->rp)),
+              dentry != NULL ? (char *)(dentry->d_name.name) :
+                               (char *)("NULL"),
+              (int)preload_pd_get_state(hd),
               prefix, (unsigned long)ri->rp->up.addr,
               regs->EREG(ip), swap_get_arg(regs, 0), swap_get_arg(regs, 1),
               swap_get_ret_addr(regs));
@@ -299,31 +307,21 @@ static inline bool __is_probe_non_block(struct us_ip *ip)
        return false;
 }
 
-static inline bool __is_handlers_call(struct vm_area_struct *caller)
+static inline bool __is_handlers_call(struct vm_area_struct *caller,
+                                     struct pd_t *pd)
 {
-       /* TODO Optimize using start/stop callbacks */
-
-       struct bin_info *hi = preload_storage_get_handlers_info();
-       bool res = false;
-
-       if (hi == NULL) {
-               printk(PRELOAD_PREFIX "Cannot get handlers dentry!\n");
-               goto is_handlers_call_out;
-       }
+       struct hd_t *hd;
 
        if (caller == NULL || caller->vm_file == NULL ||
-               caller->vm_file->f_dentry == NULL) {
-               goto is_handlers_call_out;
+               caller->vm_file->f_path.dentry == NULL) {
+               return false;
        }
 
-       if (hi->dentry == caller->vm_file->f_dentry)
-               res = true;
-
-is_handlers_call_out:
-
-       preload_storage_put_handlers_info(hi);
+       hd = preload_pd_get_hd(pd, caller->vm_file->f_path.dentry);
+       if (hd != NULL)
+               return true;
 
-       return res;
+       return false;
 }
 
 static inline int __msg_sanitization(char *user_msg, size_t len,
@@ -432,8 +430,11 @@ static int mmap_entry_handler(struct kretprobe_instance *ri,
        struct file *file = (struct file *)swap_get_karg(regs, 0);
        unsigned long prot = swap_get_karg(regs, 3);
        struct mmap_priv *priv = (struct mmap_priv *)ri->data;
+       struct task_struct *task = current->group_leader;
        struct dentry *dentry, *loader_dentry;
-       struct bin_info *hi;
+       struct pd_t *pd;
+       struct hd_t *hd;
+       struct sspt_proc *proc;
 
        priv->dentry = NULL;
        if (!check_prot(prot))
@@ -441,24 +442,31 @@ static int mmap_entry_handler(struct kretprobe_instance *ri,
 
        if (!file)
                return 0;
+
        dentry = file->f_dentry;
        if (dentry == NULL)
                return 0;
 
-       hi = preload_storage_get_handlers_info();
-       if (hi == NULL) {
-               printk(PRELOAD_PREFIX "Cannot get handlers info [%u %u %s]\n",
-                      current->tgid, current->pid, current->comm);
+       loader_dentry = preload_debugfs_get_loader_dentry();
+       if (dentry == loader_dentry) {
+               priv->dentry = loader_dentry;
                return 0;
        }
 
-       loader_dentry = preload_debugfs_get_loader_dentry();
-       if (dentry == loader_dentry)
-               priv->dentry = loader_dentry;
-       else if (hi->dentry != NULL && dentry == hi->dentry)
-               priv->dentry = hi->dentry;
+       proc = sspt_proc_get_by_task(task);
+       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;
+       }
 
-       preload_storage_put_handlers_info(hi);
+       hd = preload_pd_get_hd(pd, dentry);
+       if (hd != NULL)
+               priv->dentry = preload_pd_get_dentry(hd);
 
        return 0;
 }
@@ -469,9 +477,9 @@ 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 pd_t *pd;
+       struct hd_t *hd;
        struct sspt_proc *proc;
        struct dentry *loader_dentry;
-       struct bin_info *hi;
        unsigned long vaddr;
 
        if (!task->mm)
@@ -495,21 +503,14 @@ static int mmap_ret_handler(struct kretprobe_instance *ri,
                return 0;
        }
 
-       hi = preload_storage_get_handlers_info();
-       if (hi == NULL) {
-               printk(PRELOAD_PREFIX "Cannot get handlers info [%u %u %s]\n",
-                      current->tgid, current->pid, current->comm);
-               return 0;
-       }
-
        loader_dentry = preload_debugfs_get_loader_dentry();
-
        if (priv->dentry == loader_dentry)
                preload_pd_set_loader_base(pd, vaddr);
-       else if (priv->dentry == hi->dentry)
-               preload_pd_set_handlers_base(pd, vaddr);
 
-       preload_storage_put_handlers_info(hi);
+
+       hd = preload_pd_get_hd(pd, priv->dentry);
+       if (hd != NULL)
+               preload_pd_set_handlers_base(hd, vaddr);
 
        return 0;
 }
@@ -537,7 +538,7 @@ static void preload_stop_cb(void)
 
 static unsigned long __not_loaded_entry(struct uretprobe_instance *ri,
                                        struct pt_regs *regs,
-                                       struct pd_t *pd)
+                                       struct pd_t *pd, struct hd_t *hd)
 {
        char __user *path = NULL;
        unsigned long vaddr = 0;
@@ -556,9 +557,9 @@ static unsigned long __not_loaded_entry(struct uretprobe_instance *ri,
        if (vaddr) {
                /* save original regs state */
                __save_uregs(ri, regs);
-               print_regs("PROBE ORIG", regs, ri);
+               print_regs("ORIG", regs, ri, hd);
 
-               path = preload_pd_get_path(pd);
+               path = preload_pd_get_path(pd, hd);
 
                /* set dlopen args: filename, flags */
                swap_set_arg(regs, 0, (unsigned long)path/*swap_get_stack_ptr(regs)*/);
@@ -567,15 +568,51 @@ static unsigned long __not_loaded_entry(struct uretprobe_instance *ri,
                /* do the jump to dlopen */
                __prepare_ujump(ri, regs, vaddr);
                /* set new state */
-               preload_pd_set_state(pd, LOADING);
+               preload_pd_set_state(hd, LOADING);
        }
 
        return vaddr;
 }
 
-static unsigned long __loaded_entry(struct uretprobe_instance *ri,
-                                   struct pt_regs *regs,
-                                   struct pd_t *pd)
+static void __loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                         struct pd_t *pd, struct hd_t *hd)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+       unsigned long vaddr = 0;
+
+       /* check if preloading has been completed */
+       vaddr = preload_pd_get_loader_base(pd) +
+               preload_debugfs_get_loader_offset();
+       if (vaddr && (priv->origin == vaddr)) {
+               preload_pd_set_handle(hd,
+                                     (void __user *)regs_return_value(regs));
+
+               /* restore original regs state */
+               __restore_uregs(ri, regs);
+               print_regs("REST", regs, ri, hd);
+               /* check if preloading done */
+
+               if (preload_pd_get_handle(hd)) {
+                       preload_pd_set_state(hd, LOADED);
+               } else {
+                       preload_pd_dec_attempts(hd);
+                       preload_pd_set_state(hd, FAILED);
+               }
+       }
+}
+
+static void __failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
+                        struct pd_t *pd, struct hd_t *hd)
+{
+       if (preload_pd_get_attempts(hd))
+               preload_pd_set_state(hd, NOT_LOADED);
+}
+
+
+
+static unsigned long __do_preload_entry(struct uretprobe_instance *ri,
+                                       struct pt_regs *regs,
+                                       struct hd_t *hd)
 {
        struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
        unsigned long offset = ip->desc->info.pl_i.handler;
@@ -586,7 +623,7 @@ static unsigned long __loaded_entry(struct uretprobe_instance *ri,
        struct vm_area_struct *cvma;
        enum preload_call_type ct;
 
-       base = preload_pd_get_handlers_base(pd);
+       base = preload_pd_get_handlers_base(hd);
        if (base == 0)
                return 0;       /* handlers isn't mapped */
 
@@ -604,7 +641,7 @@ static unsigned long __loaded_entry(struct uretprobe_instance *ri,
                     (cvma->vm_file->f_path.dentry != NULL) &&
                     !preload_control_check_dentry_is_ignored(cvma->vm_file->f_path.dentry)) &&
                    __check_flag_and_call_type(ip, ct) &&
-                   !__is_handlers_call(cvma)) {
+                   !__is_handlers_call(cvma, preload_pd_get_parent_pd(hd))) {
                        if (preload_threads_set_data(current, caddr, ct, disable_addr,
                                                     __should_drop(ip, ct)) != 0)
                                printk(PRELOAD_PREFIX "Error! Failed to set caller 0x%lx"
@@ -619,33 +656,42 @@ static unsigned long __loaded_entry(struct uretprobe_instance *ri,
        return vaddr;
 }
 
-static void __loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                         struct pd_t *pd)
+static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
 {
+       struct pd_t *pd = __get_process_data(ri->rp);
+       struct hd_t *hd;
+       unsigned long flags = get_preload_flags(current);
+       struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
        struct us_priv *priv = (struct us_priv *)ri->data;
        unsigned long vaddr = 0;
 
-       /* check if preloading has been completed */
-       vaddr = preload_pd_get_loader_base(pd) + preload_debugfs_get_loader_offset();
-       if (vaddr && (priv->origin == vaddr)) {
-               preload_pd_set_handle(pd, (void __user *)regs_return_value(regs));
+       if (handler_dentry == NULL)
+               goto out_set_orig;
 
-               /* restore original regs state */
-               __restore_uregs(ri, regs);
-               print_regs("PROBE REST", regs, ri);
-               /* check if preloading done */
+       if ((flags & HANDLER_RUNNING) ||
+           preload_threads_check_disabled_probe(current, ip->orig_addr))
+               goto out_set_orig;
 
-               if (preload_pd_get_handle(pd)) {
-                       preload_pd_set_state(pd, LOADED);
-               } else {
-                       preload_pd_dec_attempts(pd);
-                       preload_pd_set_state(pd, FAILED);
-               }
-       }
+       hd = preload_pd_get_hd(pd, handler_dentry);
+       if (hd == NULL)
+               goto out_set_orig;
+
+       if ((flags & HANDLER_RUNNING) ||
+           preload_threads_check_disabled_probe(current, ip->orig_addr))
+               goto out_set_orig;
+
+       if (preload_pd_get_state(hd) == NOT_LOADED ||
+           preload_pd_get_state(hd) == FAILED)
+               vaddr = __not_loaded_entry(ri, regs, pd, hd);
+       else if (preload_pd_get_state(hd) == LOADED)
+               vaddr =__do_preload_entry(ri, regs, hd);
+
+out_set_orig:
+       priv->origin = vaddr;
+       return 0;
 }
 
-static void __loaded_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                        struct pd_t *pd)
+static void __do_preload_ret(struct uretprobe_instance *ri, struct hd_t *hd)
 {
        struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
        struct us_priv *priv = (struct us_priv *)ri->data;
@@ -658,7 +704,7 @@ static void __loaded_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
                bool non_blk_probe = __is_probe_non_block(ip);
 
                /* drop the flag if the handler has completed */
-               vaddr = preload_pd_get_handlers_base(pd) + offset;
+               vaddr = preload_pd_get_handlers_base(hd) + offset;
                if (vaddr && (priv->origin == vaddr)) {
                        if (preload_threads_put_data(current) != 0)
                                printk(PRELOAD_PREFIX "Error! Failed to put caller slot"
@@ -671,64 +717,30 @@ static void __loaded_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
        }
 }
 
-static void __failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs,
-                        struct pd_t *pd)
-{
-       if (preload_pd_get_attempts(pd)) {
-               preload_pd_set_state(pd, NOT_LOADED);
-       }
-}
-
-static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
+static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
 {
        struct pd_t *pd = __get_process_data(ri->rp);
-       struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
-       struct us_priv *priv = (struct us_priv *)ri->data;
-       unsigned long flags = get_preload_flags(current);
-       unsigned long vaddr = 0;
-
-       if ((flags & HANDLER_RUNNING) ||
-           preload_threads_check_disabled_probe(current, ip->orig_addr))
-               goto out_set_origin;
+       struct hd_t *hd;
 
-       switch (preload_pd_get_state(pd)) {
-       case NOT_LOADED:
-               vaddr = __not_loaded_entry(ri, regs, pd);
-               break;
-       case LOADING:
-               /* handlers have not yet been loaded... just ignore */
-               break;
-       case LOADED:
-               vaddr = __loaded_entry(ri, regs, pd);
-               break;
-       case FAILED:
-       case ERROR:
-       default:
-               /* do nothing */
-               break;
-       }
-
-out_set_origin:
-       priv->origin = vaddr;
-       return 0;
-}
+       if (handler_dentry == NULL)
+               return 0;
 
-static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
-       struct pd_t *pd = __get_process_data(ri->rp);
+       hd = preload_pd_get_hd(pd, handler_dentry);
+       if (hd == NULL)
+               return 0;
 
-       switch (preload_pd_get_state(pd)) {
+       switch (preload_pd_get_state(hd)) {
        case NOT_LOADED:
                /* loader has not yet been mapped... just ignore */
                break;
        case LOADING:
-               __loading_ret(ri, regs, pd);
+               __loading_ret(ri, regs, pd, hd);
                break;
        case LOADED:
-               __loaded_ret(ri, regs, pd);
+               __do_preload_ret(ri, hd);
                break;
        case FAILED:
-               __failed_ret(ri, regs, pd);
+               __failed_ret(ri, regs, pd, hd);
                break;
        case ERROR:
        default:
@@ -910,6 +922,11 @@ void preload_unset(void)
 
 }
 
+void preload_module_set_handler_dentry(struct dentry *dentry)
+{
+       handler_dentry = dentry;
+}
+
 static int preload_module_init(void)
 {
        int ret;
index 62f0bfd..3e0fd07 100644 (file)
@@ -23,6 +23,8 @@ void preload_module_get_call_type_exit(struct us_ip *ip);
 int preload_module_write_msg_init(struct us_ip *ip);
 void preload_module_write_msg_exit(struct us_ip *ip);
 
+void preload_module_set_handler_dentry(struct dentry *dentry);
+
 struct dentry *get_dentry(const char *filepath);
 void put_dentry(struct dentry *dentry);
 
index 634dede..17aa742 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/hardirq.h>
+#include <linux/list.h>
 #include <us_manager/us_manager_common.h>
 #include <us_manager/sspt/sspt_proc.h>
 #include "preload_pd.h"
 #include "preload.h"
 
 struct pd_t {
-       enum ps_t state;
        unsigned long loader_base;
-       unsigned long handlers_base;
        unsigned long data_page;
+       struct list_head handlers;
+};
+
+struct hd_t {
+       struct list_head list;
+       struct dentry *dentry;
+       enum ps_t state;
+       struct pd_t *parent;
+       unsigned long base;
+       unsigned long offset;
        void __user *handle;
        long attempts;
 };
 
 
-static struct bin_info *handlers_info;
-
-
-
 static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
 {
        struct file *file = vma->vm_file;
@@ -34,107 +39,236 @@ static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
        return (file && (vma->vm_flags & VM_EXEC) && (file->f_dentry == dentry));
 }
 
-static inline enum ps_t __get_state(struct pd_t *pd)
+static inline unsigned long __get_loader_base(struct pd_t *pd)
 {
-       return pd->state;
+       return pd->loader_base;
 }
 
-static inline void __set_state(struct pd_t *pd,
-                                  enum ps_t state)
+static inline void __set_loader_base(struct pd_t *pd,
+                                    unsigned long addr)
 {
-       pd->state = state;
+       pd->loader_base = addr;
 }
 
-static inline unsigned long __get_loader_base(struct pd_t *pd)
+static inline unsigned long __get_data_page(struct pd_t *pd)
 {
-       return pd->loader_base;
+       return pd->data_page;
 }
 
-static inline void __set_loader_base(struct pd_t *pd,
-                                    unsigned long addr)
+static inline void __set_data_page(struct pd_t *pd, unsigned long page)
 {
-       pd->loader_base = addr;
+       pd->data_page = page;
+}
+
+
+
+static inline enum ps_t __get_state(struct hd_t *hd)
+{
+       return hd->state;
 }
 
-static inline unsigned long __get_handlers_base(struct pd_t *pd)
+static inline void __set_state(struct hd_t *hd, enum ps_t state)
 {
-       return pd->handlers_base;
+       hd->state = state;
 }
 
-static inline void __set_handlers_base(struct pd_t *pd,
+static inline unsigned long __get_handlers_base(struct hd_t *hd)
+{
+       return hd->base;
+}
+
+static inline void __set_handlers_base(struct hd_t *hd,
                                       unsigned long addr)
 {
-       pd->handlers_base = addr;
+       hd->base = addr;
 }
 
-static inline char __user *__get_path(struct pd_t *pd)
+static inline unsigned long __get_offset(struct hd_t *hd)
 {
-       return (char *)pd->data_page;
+       return hd->offset;
 }
 
-static inline unsigned long __get_data_page(struct pd_t *pd)
+static inline void *__get_handle(struct hd_t *hd)
 {
-       return pd->data_page;
+       return hd->handle;
 }
 
-static inline void __set_data_page(struct pd_t *pd, unsigned long page)
+static inline void __set_handle(struct hd_t *hd, void __user *handle)
 {
-       pd->data_page = page;
+       hd->handle = handle;
 }
 
-static inline void *__get_handle(struct pd_t *pd)
+static inline long __get_attempts(struct hd_t *hd)
 {
-       return pd->handle;
+       return hd->attempts;
 }
 
-static inline void __set_handle(struct pd_t *pd, void __user *handle)
+static inline void __set_attempts(struct hd_t *hd, long attempts)
 {
-       pd->handle = handle;
+       hd->attempts = attempts;
 }
 
-static inline long __get_attempts(struct pd_t *pd)
+
+
+static struct vm_area_struct *find_vma_by_dentry(struct mm_struct *mm,
+                                                struct dentry *dentry)
 {
-       return pd->attempts;
+       struct vm_area_struct *vma;
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next)
+               if (check_vma(vma, dentry))
+                       return vma;
+
+       return NULL;
 }
 
-static inline void __set_attempts(struct pd_t *pd, long attempts)
+static struct pd_t *__create_pd(void)
 {
-       pd->attempts = attempts;
+       struct pd_t *pd;
+       unsigned long page;
+
+       pd = kzalloc(sizeof(*pd), GFP_ATOMIC);
+       if (pd == NULL)
+               return NULL;
+
+       down_write(&current->mm->mmap_sem);
+       page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
+                           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 create_pd_fail;
+       }
+
+       __set_data_page(pd, page);
+
+       INIT_LIST_HEAD(&pd->handlers);
+
+       return pd;
+
+create_pd_fail:
+       kfree(pd);
+
+       return NULL;
 }
 
+static size_t __copy_path(char *src, unsigned long page, unsigned long offset)
+{
+       unsigned long dest = page + offset;
+       size_t len = strnlen(src, PATH_MAX);
 
+       /* set handler path */
+       if (copy_to_user((void __user *)dest, src, len) != 0) {
+               printk(KERN_ERR PRELOAD_PREFIX
+                      "Cannot copy string to user!\n");
+               return 0;
+       }
 
+       return len;
+}
 
-static int __pd_create_on_demand(void)
+static void __set_ld_mapped(struct pd_t *pd, struct mm_struct *mm)
 {
-       if (handlers_info == NULL) {
-               handlers_info = preload_storage_get_handlers_info();
-               if (handlers_info == NULL)
-                       return -EINVAL;
+       struct vm_area_struct *vma;
+       struct dentry *ld = preload_debugfs_get_loader_dentry();
+
+       down_read(&mm->mmap_sem);
+       if (ld) {
+               vma = find_vma_by_dentry(mm, ld);
+               if (vma)
+                       __set_loader_base(pd, vma->vm_start);
        }
+       up_read(&mm->mmap_sem);
+}
 
-       return 0;
+static void __set_handler_mapped(struct hd_t *hd, struct mm_struct *mm)
+{
+       struct vm_area_struct *vma;
+       struct dentry *handlers = hd->dentry;
+
+       down_read(&mm->mmap_sem);
+       if (handlers) {
+               vma = find_vma_by_dentry(mm, handlers);
+               if (vma) {
+                       __set_handlers_base(hd, vma->vm_start);
+                       __set_state(hd, LOADED);
+                       goto set_handler_mapped_out;
+               }
+       }
+       __set_state(hd, NOT_LOADED);
+
+set_handler_mapped_out:
+       up_read(&mm->mmap_sem);
+}
+
+
+static int __get_handlers(struct pd_t *pd, struct task_struct *task)
+{
+       struct list_head *handlers = NULL;
+       struct bin_info_el *bin;
+       struct hd_t *hd;
+       unsigned long offset = 0;
+       size_t len;
+       int ret = 0;
+
+       handlers = preload_storage_get_handlers();
+       if (handlers == NULL)
+               return -EINVAL;
+
+       list_for_each_entry(bin, handlers, list) {
+               len = __copy_path(bin->path, pd->data_page, offset);
+               if (len == 0) {
+                       ret = -EINVAL;
+                       goto get_handlers_out;
+               }
+
+               hd = kzalloc(sizeof(*hd), GFP_ATOMIC);
+               if (hd == NULL) {
+                       printk(KERN_ERR PRELOAD_PREFIX "No atomic mem!\n");
+                       ret = -ENOMEM;
+                       goto get_handlers_out;
+               }
+
+
+               INIT_LIST_HEAD(&hd->list);
+               hd->parent = pd;
+               hd->dentry = bin->dentry;
+               hd->offset = offset;
+               __set_handler_mapped(hd, task->mm);
+               __set_attempts(hd, PRELOAD_MAX_ATTEMPTS);
+               list_add_tail(&hd->list, &pd->handlers);
+
+               /* inc handlers path's on page */
+               offset += len + 1;
+       }
+
+get_handlers_out:
+       /* TODO Cleanup already created */
+       preload_storage_put_handlers();
+
+       return ret;
 }
 
 
 
-enum ps_t preload_pd_get_state(struct pd_t *pd)
+enum ps_t preload_pd_get_state(struct hd_t *hd)
 {
-       if (pd == NULL)
+       if (hd == NULL)
                return 0;
 
-       return __get_state(pd);
+       return __get_state(hd);
 }
 
-void preload_pd_set_state(struct pd_t *pd, enum ps_t state)
+void preload_pd_set_state(struct hd_t *hd, enum ps_t state)
 {
-       if (pd == NULL) {
-               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
-               current->tgid, current->comm);
+       if (hd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No handler data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
                return;
        }
 
-       __set_state(pd, state);
+       __set_state(hd, state);
 }
 
 unsigned long preload_pd_get_loader_base(struct pd_t *pd)
@@ -150,164 +284,114 @@ void preload_pd_set_loader_base(struct pd_t *pd, unsigned long vaddr)
        __set_loader_base(pd, vaddr);
 }
 
-unsigned long preload_pd_get_handlers_base(struct pd_t *pd)
+unsigned long preload_pd_get_handlers_base(struct hd_t *hd)
 {
-       if (pd == NULL)
+       if (hd == NULL)
                return 0;
 
-       return __get_handlers_base(pd);
+       return __get_handlers_base(hd);
 }
 
-void preload_pd_set_handlers_base(struct pd_t *pd, unsigned long vaddr)
+void preload_pd_set_handlers_base(struct hd_t *hd, unsigned long vaddr)
 {
-       __set_handlers_base(pd, vaddr);
+       __set_handlers_base(hd, vaddr);
 }
 
-char __user *preload_pd_get_path(struct pd_t *pd)
+char __user *preload_pd_get_path(struct pd_t *pd, struct hd_t *hd)
 {
-       char __user *path = __get_path(pd);
+       unsigned long page = __get_data_page(pd);
+       unsigned long offset = __get_offset(hd);
 
-       return path;
+       return (char __user *)(page + offset);
 }
 
 
 
-void *preload_pd_get_handle(struct pd_t *pd)
+void *preload_pd_get_handle(struct hd_t *hd)
 {
-       if (pd == NULL)
+       if (hd == NULL)
                return NULL;
 
-       return __get_handle(pd);
+       return __get_handle(hd);
 }
 
-void preload_pd_set_handle(struct pd_t *pd, void __user *handle)
+void preload_pd_set_handle(struct hd_t *hd, void __user *handle)
 {
-       if (pd == NULL) {
-               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
-               current->tgid, current->comm);
+       if (hd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No handler data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
                return;
        }
 
-       __set_handle(pd, handle);
+       __set_handle(hd, handle);
 }
 
-long preload_pd_get_attempts(struct pd_t *pd)
+long preload_pd_get_attempts(struct hd_t *hd)
 {
-       if (pd == NULL)
+       if (hd == NULL)
                return -EINVAL;
 
-       return __get_attempts(pd);
+       return __get_attempts(hd);
 }
 
-void preload_pd_dec_attempts(struct pd_t *pd)
+void preload_pd_dec_attempts(struct hd_t *hd)
 {
        long attempts;
 
-       if (pd == NULL) {
-               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
-               current->tgid, current->comm);
+       if (hd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No handler data! Current %d %s\n",
+                      __LINE__, current->tgid, current->comm);
                return;
        }
 
-       attempts = __get_attempts(pd);
+       attempts = __get_attempts(hd);
        attempts--;
-       __set_attempts(pd, attempts);
+       __set_attempts(hd, attempts);
 }
 
-struct pd_t *preload_pd_get(struct sspt_proc *proc)
+struct dentry *preload_pd_get_dentry(struct hd_t *hd)
 {
-       return (struct pd_t *)proc->private_data;
+       return hd->dentry;
 }
 
-static unsigned long make_preload_path(void)
+struct pd_t *preload_pd_get_parent_pd(struct hd_t *hd)
 {
-       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 | PROT_WRITE,
-                                   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;
+       return hd->parent;
 }
 
-static struct vm_area_struct *find_vma_by_dentry(struct mm_struct *mm,
-                                                struct dentry *dentry)
+struct pd_t *preload_pd_get(struct sspt_proc *proc)
 {
-       struct vm_area_struct *vma;
-
-       for (vma = mm->mmap; vma; vma = vma->vm_next)
-               if (check_vma(vma, dentry))
-                       return vma;
-
-        return NULL;
+       return (struct pd_t *)proc->private_data;
 }
 
-static void set_already_mapp(struct pd_t *pd, struct mm_struct *mm)
+struct hd_t *preload_pd_get_hd(struct pd_t *pd, struct dentry *dentry)
 {
-       struct vm_area_struct *vma;
-       struct dentry *ld = preload_debugfs_get_loader_dentry();
-       struct dentry *handlers = handlers_info->dentry;
+       struct hd_t *hd;
 
-       down_read(&mm->mmap_sem);
-       if (ld) {
-               vma = find_vma_by_dentry(mm, ld);
-               if (vma)
-                       __set_loader_base(pd, vma->vm_start);
+       list_for_each_entry(hd, &pd->handlers, list) {
+               if (hd->dentry == dentry)
+                       return hd;
        }
 
-       if (handlers) {
-               vma = find_vma_by_dentry(mm, handlers);
-               if (vma) {
-                       __set_handlers_base(pd, vma->vm_start);
-                       __set_state(pd, LOADED);
-               }
-       }
-       up_read(&mm->mmap_sem);
+       return NULL;
 }
 
 static struct pd_t *do_create_pd(struct task_struct *task)
 {
        struct pd_t *pd;
-       unsigned long page;
        int ret;
 
-       ret = __pd_create_on_demand();
-       if (ret)
-               goto create_pd_exit;
-
-       pd = kzalloc(sizeof(*pd), GFP_ATOMIC);
+       pd = __create_pd();
        if (pd == NULL) {
                ret = -ENOMEM;
                goto create_pd_exit;
        }
 
-       page = make_preload_path();
-       if (IS_ERR_VALUE(page)) {
-               ret = (long)page;
+       ret = __get_handlers(pd, task);
+       if (ret)
                goto free_pd;
-       }
 
-       __set_data_page(pd, page);
-       __set_attempts(pd, PRELOAD_MAX_ATTEMPTS);
-       set_already_mapp(pd, task->mm);
+       __set_ld_mapped(pd, task->mm);
 
        return pd;
 
@@ -351,7 +435,5 @@ void preload_pd_uninit(void)
 {
        sspt_proc_cb_set(NULL);
 
-       if (handlers_info)
-               preload_storage_put_handlers_info(handlers_info);
-       handlers_info = NULL;
+       /* TODO Cleanup */
 }
index dd11d50..9a92b42 100644 (file)
@@ -2,7 +2,10 @@
 #define __PRELOAD_PD_H__
 
 struct pd_t;
+struct hd_t;
 struct sspt_proc;
+struct dentry;
+struct list_head;
 
 /* process preload states */
 enum ps_t {
@@ -14,20 +17,22 @@ enum ps_t {
 };
 
 struct pd_t *preload_pd_get(struct sspt_proc *proc);
-
-enum ps_t preload_pd_get_state(struct pd_t *pd);
-void preload_pd_set_state(struct pd_t *pd, enum ps_t state);
 unsigned long preload_pd_get_loader_base(struct pd_t *pd);
 void preload_pd_set_loader_base(struct pd_t *pd, unsigned long vaddr);
-unsigned long preload_pd_get_handlers_base(struct pd_t *pd);
-void preload_pd_set_handlers_base(struct pd_t *pd, unsigned long vaddr);
-void *preload_pd_get_handle(struct pd_t *pd);
-void preload_pd_set_handle(struct pd_t *pd, void __user *handle);
-
-long preload_pd_get_attempts(struct pd_t *pd);
-void preload_pd_dec_attempts(struct pd_t *pd);
 
-char __user *preload_pd_get_path(struct pd_t *pd);
+struct hd_t *preload_pd_get_hd(struct pd_t *pd, struct dentry *dentry);
+struct dentry *preload_pd_get_dentry(struct hd_t *hd);
+struct pd_t *preload_pd_get_parent_pd(struct hd_t *hd);
+enum ps_t preload_pd_get_state(struct hd_t *hd);
+void preload_pd_set_state(struct hd_t *hd, enum ps_t state);
+unsigned long preload_pd_get_handlers_base(struct hd_t *hd);
+void preload_pd_set_handlers_base(struct hd_t *hd, unsigned long vaddr);
+void *preload_pd_get_handle(struct hd_t *hd);
+void preload_pd_set_handle(struct hd_t *hd, void __user *handle);
+long preload_pd_get_attempts(struct hd_t *hd);
+void preload_pd_dec_attempts(struct hd_t *hd);
+
+char __user *preload_pd_get_path(struct pd_t *pd, struct hd_t *hd);
 
 int preload_pd_init(void);
 void preload_pd_uninit(void);
index 3cfa2e6..bf2bad2 100644 (file)
@@ -1,8 +1,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <ks_features/ks_map.h>
 #include <linux/fs.h>
+#include <linux/list.h>
+#include <ks_features/ks_map.h>
 #include "preload.h"
 #include "preload_module.h"
 #include "preload_storage.h"
@@ -10,6 +11,8 @@
 static struct bin_info __handlers_info = { NULL, NULL };
 static struct bin_info __linker_info = { NULL, NULL };
 
+static LIST_HEAD(handlers_list);
+
 static inline struct bin_info *__get_handlers_info(void)
 {
        return &__handlers_info;
@@ -20,6 +23,65 @@ static inline bool __check_handlers_info(void)
        return (__handlers_info.dentry != NULL); /* TODO */
 }
 
+static inline int __add_handler(char *path)
+{
+       struct dentry *dentry;
+       size_t len = strnlen(path, PATH_MAX);
+       struct bin_info_el *bin;
+       int ret = 0;
+
+       bin = kmalloc(sizeof(*bin), GFP_KERNEL);
+       if (bin == NULL) {
+               ret = -ENOMEM;
+               goto add_handler_fail;
+       }
+
+       bin->path = kmalloc(len + 1, GFP_KERNEL);
+       if (bin->path == NULL) {
+               ret = -ENOMEM;
+               goto add_handler_fail_free_bin;
+       }
+
+       dentry = get_dentry(path);
+       if (!dentry) {
+               ret = -ENOENT;
+               goto add_handler_fail_free_path;
+       }
+
+       INIT_LIST_HEAD(&bin->list);
+       strncpy(bin->path, path, len);
+       bin->path[len] = '\0';
+       bin->dentry = dentry;
+       list_add_tail(&bin->list, &handlers_list);
+
+       return ret;
+
+add_handler_fail_free_path:
+       kfree(bin->path);
+
+add_handler_fail_free_bin:
+       kfree(bin);
+
+add_handler_fail:
+       return ret;
+}
+
+static inline void __remove_handler(struct bin_info_el *bin)
+{
+       list_del(&bin->list);
+       put_dentry(bin->dentry);
+       kfree(bin->path);
+       kfree(bin);
+}
+
+static inline void __remove_handlers(void)
+{
+       struct bin_info_el *bin, *tmp;
+
+       list_for_each_entry_safe(bin, tmp, &handlers_list, list)
+               __remove_handler(bin);
+}
+
 static inline int __init_handlers_info(char *path)
 {
        struct dentry *dentry;
@@ -119,7 +181,30 @@ static inline void __drop_linker_info(void)
 
 int preload_storage_set_handlers_info(char *path)
 {
-       return __init_handlers_info(path);
+       int ret;
+
+       ret = __init_handlers_info(path);
+       if (ret != 0)
+               return ret;
+
+       ret = __add_handler(path);
+       if (ret != 0)
+               return ret;
+
+       preload_module_set_handler_dentry(__handlers_info.dentry);
+
+       return ret;
+}
+
+int preload_storage_add_handler(char *path)
+{
+       int ret;
+
+       ret = __add_handler(path);
+       if (ret != 0)
+               return ret;
+
+       return ret;
 }
 
 struct bin_info *preload_storage_get_handlers_info(void)
@@ -132,10 +217,21 @@ struct bin_info *preload_storage_get_handlers_info(void)
        return NULL;
 }
 
+struct list_head *preload_storage_get_handlers(void)
+{
+       /* TODO counter, syncs */
+       return &handlers_list;
+}
+
 void preload_storage_put_handlers_info(struct bin_info *info)
 {
 }
 
+void preload_storage_put_handlers(void)
+{
+       /* TODO dec counter, release sync */
+}
+
 int preload_storage_set_linker_info(char *path)
 {
        return __init_linker_info(path);
@@ -164,4 +260,5 @@ void preload_storage_exit(void)
 {
        __drop_handlers_info();
        __drop_linker_info();
+       __remove_handlers();
 }
index 86c7919..1fbd3a7 100644 (file)
@@ -1,16 +1,31 @@
 #ifndef __PRELOAD_STORAGE_H__
 #define __PRELOAD_STORAGE_H__
 
+struct list_head;
+struct dentry;
+
 struct bin_info {
        char *path;
        /* ghot */
        struct dentry *dentry;
 };
 
+struct bin_info_el {
+       struct list_head list;
+       char *path;
+       /* ghot */
+       struct dentry *dentry;
+};
+
+
 int preload_storage_set_handlers_info(char *path);
 struct bin_info *preload_storage_get_handlers_info(void);
 void preload_storage_put_handlers_info(struct bin_info *info);
 
+int preload_storage_add_handler(char *path);
+struct list_head *preload_storage_get_handlers(void);
+void preload_storage_put_handlers(void);
+
 int preload_storage_set_linker_info(char *path);
 struct bin_info *preload_storage_get_linker_info(void);
 void preload_storage_put_linker_info(struct bin_info *info);