From 9b74288b0bd3f0f22cea51957d396f08cbec3341 Mon Sep 17 00:00:00 2001 From: Alexander Aksenov Date: Mon, 8 Feb 2016 20:50:37 +0300 Subject: [PATCH] [REFACTOR] Loader separated from preload Change-Id: I04159e8f3066ff8c5d0584661b91b6fd4219e7df Signed-off-by: Alexander Aksenov --- Kbuild | 1 + loader/Kbuild | 8 + loader/loader.h | 8 + loader/loader_control.c | 214 ++++++ loader/loader_control.h | 17 + loader/loader_debugfs.c | 456 ++++++++++++ loader/loader_debugfs.h | 14 + loader/loader_module.c | 648 ++++++++++++++++ loader/loader_module.h | 39 + preload/preload_pd.c => loader/loader_pd.c | 70 +- loader/loader_pd.h | 43 ++ .../preload_storage.c => loader/loader_storage.c | 149 ++-- loader/loader_storage.h | 33 + packaging/swap-modules.spec | 2 + preload/Kbuild | 7 +- preload/preload_control.c | 28 +- preload/preload_control.h | 28 +- preload/preload_debugfs.c | 287 +------- preload/preload_debugfs.h | 17 +- preload/preload_handlers.c | 474 ------------ preload/preload_handlers.h | 18 - preload/preload_module.c | 818 +++++++++------------ preload/preload_module.h | 40 +- preload/preload_pd.h | 41 -- preload/preload_probe.c | 74 +- preload/preload_probe.h | 6 +- preload/preload_storage.h | 36 - preload/preload_threads.c | 28 +- preload/preload_threads.h | 35 +- 29 files changed, 2035 insertions(+), 1604 deletions(-) create mode 100644 loader/Kbuild create mode 100644 loader/loader.h create mode 100644 loader/loader_control.c create mode 100644 loader/loader_control.h create mode 100644 loader/loader_debugfs.c create mode 100644 loader/loader_debugfs.h create mode 100644 loader/loader_module.c create mode 100644 loader/loader_module.h rename preload/preload_pd.c => loader/loader_pd.c (80%) create mode 100644 loader/loader_pd.h rename preload/preload_storage.c => loader/loader_storage.c (54%) create mode 100644 loader/loader_storage.h delete mode 100644 preload/preload_handlers.c delete mode 100644 preload/preload_handlers.h delete mode 100644 preload/preload_pd.h delete mode 100644 preload/preload_storage.h diff --git a/Kbuild b/Kbuild index 3757b1d..473585c 100644 --- a/Kbuild +++ b/Kbuild @@ -13,6 +13,7 @@ obj-m := master/ \ uprobe/ \ us_manager/ \ ks_features/ \ + loader/ \ sampler/ \ energy/ \ parser/ \ diff --git a/loader/Kbuild b/loader/Kbuild new file mode 100644 index 0000000..f6cd9f7 --- /dev/null +++ b/loader/Kbuild @@ -0,0 +1,8 @@ +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_loader.o +swap_loader-y := loader_module.o \ + loader_debugfs.o \ + loader_storage.o \ + loader_control.o \ + loader_pd.o diff --git a/loader/loader.h b/loader/loader.h new file mode 100644 index 0000000..92b4cb3 --- /dev/null +++ b/loader/loader.h @@ -0,0 +1,8 @@ +#ifndef __LOADER__ +#define __LOADER__ + +#define LOADER_PREFIX "SWAP_LOADER: " +#define LOADER_MAX_ATTEMPTS 10 +#define LOADER_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */ + +#endif /* __LOADER__ */ diff --git a/loader/loader_control.c b/loader/loader_control.c new file mode 100644 index 0000000..a6d3be0 --- /dev/null +++ b/loader/loader_control.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include + +#include "loader.h" +#include "loader_control.h" +#include "loader_module.h" + +struct bin_desc { + struct list_head list; + struct dentry *dentry; + char *filename; +}; + +struct list_desc { + struct list_head list; + rwlock_t lock; + int cnt; +}; + +static struct list_desc ignored = { + .list = LIST_HEAD_INIT(ignored.list), + .lock = __RW_LOCK_UNLOCKED(&ignored.lock), + .cnt = 0 +}; + +static struct bin_desc *__alloc_binary(struct dentry *dentry, char *name, + int namelen) +{ + struct bin_desc *p = NULL; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return NULL; + + INIT_LIST_HEAD(&p->list); + p->filename = kmalloc(namelen + 1, GFP_KERNEL); + if (!p->filename) + goto fail; + memcpy(p->filename, name, namelen); + p->filename[namelen] = '\0'; + p->dentry = dentry; + + return p; +fail: + kfree(p); + return NULL; +} + +static void __free_binary(struct bin_desc *p) +{ + kfree(p->filename); + kfree(p); +} + +static void __free_ign_binaries(void) +{ + struct bin_desc *p, *n; + struct list_head rm_head; + + INIT_LIST_HEAD(&rm_head); + write_lock(&ignored.lock); + list_for_each_entry_safe(p, n, &ignored.list, list) { + list_move(&p->list, &rm_head); + } + ignored.cnt = 0; + write_unlock(&ignored.lock); + + list_for_each_entry_safe(p, n, &rm_head, list) { + list_del(&p->list); + put_dentry(p->dentry); + __free_binary(p); + } +} + +static bool __check_dentry_already_exist(struct dentry *dentry) +{ + struct bin_desc *p; + bool ret = false; + + read_lock(&ignored.lock); + list_for_each_entry(p, &ignored.list, list) { + if (p->dentry == dentry) { + ret = true; + goto out; + } + } +out: + read_unlock(&ignored.lock); + + return ret; +} + +static int __add_ign_binary(struct dentry *dentry, char *filename) +{ + struct bin_desc *p; + size_t len; + + if (__check_dentry_already_exist(dentry)) { + printk(LOADER_PREFIX "Binary already exist\n"); + return EALREADY; + } + + /* Filename should be < PATH_MAX */ + len = strnlen(filename, PATH_MAX); + if (len == PATH_MAX) + return -EINVAL; + + p = __alloc_binary(dentry, filename, len); + if (!p) + return -ENOMEM; + + write_lock(&ignored.lock); + list_add_tail(&p->list, &ignored.list); + ignored.cnt++; + write_unlock(&ignored.lock); + + return 0; +} + +static unsigned int __get_ign_names(char ***filenames_p) +{ + unsigned int i, ret = 0; + struct bin_desc *p; + char **a = NULL; + + read_lock(&ignored.lock); + if (ignored.cnt == 0) + goto out; + + a = kmalloc(sizeof(*a) * ignored.cnt, GFP_KERNEL); + if (!a) + goto out; + + i = 0; + list_for_each_entry(p, &ignored.list, list) { + if (i >= ignored.cnt) + break; + a[i++] = p->filename; + } + + *filenames_p = a; + ret = i; +out: + read_unlock(&ignored.lock); + return ret; +} + + + +int lc_add_ignored_binary(char *filename) +{ + struct dentry *dentry = get_dentry(filename); + int res = 0; + + if (dentry == NULL) + return -EINVAL; + + res = __add_ign_binary(dentry, filename); + if (res != 0) + put_dentry(dentry); + + return res > 0 ? 0 : res; +} + +int lc_clean_ignored_bins(void) +{ + __free_ign_binaries(); + + return 0; +} + +unsigned int lc_get_ignored_names(char ***filenames_p) +{ + return __get_ign_names(filenames_p); +} + +void lc_release_ignored_names(char ***filenames_p) +{ + kfree(*filenames_p); +} + +bool lc_check_dentry_is_ignored(struct dentry *dentry) +{ + struct bin_desc *p; + bool ret = false; + + if (dentry == NULL) + return false; + + read_lock(&ignored.lock); + + list_for_each_entry(p, &ignored.list, list) { + if (p->dentry == dentry) { + ret = true; + break; + } + } + + read_unlock(&ignored.lock); + + return ret; +} + +int lc_init(void) +{ + return 0; +} + +void lc_exit(void) +{ + __free_ign_binaries(); +} diff --git a/loader/loader_control.h b/loader/loader_control.h new file mode 100644 index 0000000..37988df --- /dev/null +++ b/loader/loader_control.h @@ -0,0 +1,17 @@ +#ifndef __LOADER_CONTROL_H__ +#define __LOADER_CONTROL_H__ + +struct dentry; + +int lc_init(void); +void lc_exit(void); + +int lc_add_ignored_binary(char *filename); +int lc_clean_ignored_bins(void); + +unsigned int lc_get_ignored_names(char ***filenames_p); +void lc_release_ignored_names(char ***filenames_p); + +bool lc_check_dentry_is_ignored(struct dentry *dentry); + +#endif /* __LOADER_CONTROL_H__ */ diff --git a/loader/loader_debugfs.c b/loader/loader_debugfs.c new file mode 100644 index 0000000..58c7736 --- /dev/null +++ b/loader/loader_debugfs.c @@ -0,0 +1,456 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "loader.h" +#include "loader_debugfs.h" +#include "loader_module.h" +#include "loader_control.h" +#include "loader_storage.h" + +static const char LOADER_FOLDER[] = "loader"; +static const char LOADER_LOADER[] = "loader"; +static const char LOADER_LOADER_OFFSET[] = "loader_offset"; +static const char LOADER_LOADER_PATH[] = "loader_path"; +static const char LOADER_IGNORED[] = "ignored_binaries"; +static const char LOADER_BINARIES_LIST[] = "bins_list"; +static const char LOADER_BINARIES_ADD[] = "bins_add"; +static const char LOADER_BINARIES_REMOVE[] = "bins_remove"; +static const char LOADER_CALLER[] = "caller"; +static const char LOADER_LINKER_DATA[] = "linker"; +static const char LOADER_LINKER_PATH[] = "linker_path"; +static const char LOADER_LINKER_R_DEBUG_OFFSET[] = "r_debug_offset"; + +struct loader_info { + char *path; + unsigned long offset; + struct dentry *dentry; +}; + +static struct dentry *loader_root; +static struct loader_info __loader_info; + +static unsigned long r_debug_offset = 0; +static DEFINE_SPINLOCK(__dentry_lock); + +static inline void dentry_lock(void) +{ + spin_lock(&__dentry_lock); +} + +static inline void dentry_unlock(void) +{ + spin_unlock(&__dentry_lock); +} + + +static void set_loader_file(char *path) +{ + __loader_info.path = path; + dentry_lock(); + __loader_info.dentry = get_dentry(__loader_info.path); + dentry_unlock(); +} + +struct dentry *ld_get_loader_dentry(void) +{ + struct dentry *dentry; + + dentry_lock(); + dentry = __loader_info.dentry; + dentry_unlock(); + + return dentry; +} + +unsigned long ld_get_loader_offset(void) +{ + /* TODO Think about sync */ + return __loader_info.offset; +} + +static void clean_loader_info(void) +{ + if (__loader_info.path != NULL) + kfree(__loader_info.path); + __loader_info.path = NULL; + + dentry_lock(); + if (__loader_info.dentry != NULL) + put_dentry(__loader_info.dentry); + + __loader_info.dentry = NULL; + __loader_info.offset = 0; + + dentry_unlock(); +} + +struct dentry *debugfs_create_ptr(const char *name, mode_t mode, + struct dentry *parent, + unsigned long *value) +{ + struct dentry *dentry; + +#if BITS_PER_LONG == 32 + dentry = debugfs_create_x32(name, mode, parent, (u32 *)value); +#elif BITS_PER_LONG == 64 + dentry = debugfs_create_x64(name, mode, parent, (u64 *)value); +#else +#error Unsupported BITS_PER_LONG value +#endif + + return dentry; +} + + +/* =========================================================================== + * = LOADER PATH = + * =========================================================================== + */ + +static ssize_t loader_path_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + ssize_t ret; + char *path; + + if (loader_module_is_running()) + return -EBUSY; + + clean_loader_info(); + + path = kmalloc(len, GFP_KERNEL); + if (path == NULL) { + return -ENOMEM; + } + + if (copy_from_user(path, buf, len)) { + ret = -EINVAL; + goto err; + } + + path[len - 1] = '\0'; + set_loader_file(path); + + ret = lc_add_ignored_binary(path); + if (ret < 0) { + printk(LOADER_PREFIX "Cannot add loader %s to ignored list\n", path); + goto err; + } + + ret = len; + + return ret; +err: + kfree(path); + return ret; +} + + +static const struct file_operations loader_path_file_ops = { + .owner = THIS_MODULE, + .write = loader_path_write, +}; + + +/* =========================================================================== + * = BIN PATH = + * =========================================================================== + */ + +static ssize_t bin_add_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + ssize_t ret; + char *path; + + path = kmalloc(len, GFP_KERNEL); + if (path == NULL) { + ret = -ENOMEM; + goto bin_add_write_out; + } + + if (copy_from_user(path, buf, len)) { + ret = -EINVAL; + goto bin_add_write_out; + } + + path[len - 1] = '\0'; + + ret = lc_add_ignored_binary(path); + if (ret != 0) { + printk(LOADER_PREFIX "Cannot add binary %s\n", path); + ret = -EINVAL; + goto bin_add_write_out; + } + + ret = len; + +bin_add_write_out: + kfree(path); + + return ret; +} + +static ssize_t bin_remove_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + ssize_t ret; + + ret = lc_clean_ignored_bins(); + if (ret != 0) { + printk(LOADER_PREFIX "Error during clean!\n"); + ret = -EINVAL; + goto bin_remove_write_out; + } + + ret = len; + +bin_remove_write_out: + return ret; +} + +static ssize_t bin_list_read(struct file *file, char __user *usr_buf, + size_t count, loff_t *ppos) +{ + unsigned int i; + unsigned int files_cnt = 0; + ssize_t len = 0, tmp, ret = 0; + char **filenames = NULL; + char *buf = NULL; + char *ptr = NULL; + + files_cnt = lc_get_ignored_names(&filenames); + if (files_cnt == 0) { + printk(LOADER_PREFIX "Cannot read binaries names!\n"); + ret = 0; + goto bin_list_read_fail; + } + + for (i = 0; i < files_cnt; i++) + len += strlen(filenames[i]); + + buf = kmalloc(len + files_cnt, GFP_KERNEL); + if (buf == NULL) { + ret = 0; + goto bin_list_read_fail; + } + + ptr = buf; + + for (i = 0; i < files_cnt; i++) { + tmp = strlen(filenames[i]); + memcpy(ptr, filenames[i], tmp); + ptr += tmp; + *ptr = '\n'; + ptr += 1; + } + + ret = simple_read_from_buffer(usr_buf, count, ppos, buf, len); + + kfree(buf); + +bin_list_read_fail: + lc_release_ignored_names(&filenames); + + return ret; +} + +static const struct file_operations bin_list_file_ops = { + .owner = THIS_MODULE, + .read = bin_list_read +}; + +static const struct file_operations bin_add_file_ops = { + .owner = THIS_MODULE, + .write = bin_add_write, +}; + +static const struct file_operations bin_remove_file_ops = { + .owner = THIS_MODULE, + .write = bin_remove_write, +}; + + +/* =========================================================================== + * = LINKER PATH = + * =========================================================================== + */ + + +static ssize_t linker_path_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + ssize_t ret; + char *path; + + path = kmalloc(len, GFP_KERNEL); + if (path == NULL) { + ret = -ENOMEM; + goto linker_path_write_out; + } + + if (copy_from_user(path, buf, len)) { + ret = -EINVAL; + goto linker_path_write_out; + } + + path[len - 1] = '\0'; + + if (ls_set_linker_info(path) != 0) { + printk(LOADER_PREFIX "Cannot set linker path %s\n", path); + ret = -EINVAL; + goto linker_path_write_out; + } + + ret = lc_add_ignored_binary(path); + if (ret < 0) { + printk(LOADER_PREFIX "Cannot add linker %s to ignored list\n", path); + goto linker_path_write_out; + } + + ret = len; + +linker_path_write_out: + kfree(path); + + return ret; +} + +static const struct file_operations linker_path_file_ops = { + .owner = THIS_MODULE, + .write = linker_path_write, +}; + + + + + +unsigned long ld_r_debug_offset(void) +{ + return r_debug_offset; +} + +int ld_init(void) +{ + struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path, + *ignored_path, *linker_dir, *linker_path, + *linker_offset, *ignored_list, + *ignored_add, *ignored_remove; + int ret; + + ret = -ENODEV; + if (!debugfs_initialized()) + goto fail; + + ret = -ENOENT; + swap_dentry = swap_debugfs_getdir(); + if (!swap_dentry) + goto fail; + + ret = -ENOMEM; + root = debugfs_create_dir(LOADER_FOLDER, swap_dentry); + if (IS_ERR_OR_NULL(root)) + goto fail; + + loader_root = root; + + loader = debugfs_create_dir(LOADER_LOADER, root); + if (IS_ERR_OR_NULL(root)) { + ret = -ENOMEM; + goto remove; + } + + open_p = debugfs_create_ptr(LOADER_LOADER_OFFSET, LOADER_DEFAULT_PERMS, + loader, &__loader_info.offset); + if (IS_ERR_OR_NULL(open_p)) { + ret = -ENOMEM; + goto remove; + } + + lib_path = debugfs_create_file(LOADER_LOADER_PATH, LOADER_DEFAULT_PERMS, + loader, NULL, &loader_path_file_ops); + if (IS_ERR_OR_NULL(lib_path)) { + ret = -ENOMEM; + goto remove; + } + + ignored_path = debugfs_create_dir(LOADER_IGNORED, root); + if (IS_ERR_OR_NULL(ignored_path)) { + ret = -ENOMEM; + goto remove; + } + + ignored_list = debugfs_create_file(LOADER_BINARIES_LIST, + LOADER_DEFAULT_PERMS, ignored_path, + NULL, &bin_list_file_ops); + if (IS_ERR_OR_NULL(ignored_list)) { + ret = -ENOMEM; + goto remove; + } + + ignored_add = debugfs_create_file(LOADER_BINARIES_ADD, + LOADER_DEFAULT_PERMS, ignored_path, NULL, + &bin_add_file_ops); + if (IS_ERR_OR_NULL(ignored_add)) { + ret = -ENOMEM; + goto remove; + } + + ignored_remove = debugfs_create_file(LOADER_BINARIES_REMOVE, + LOADER_DEFAULT_PERMS, ignored_path, NULL, + &bin_remove_file_ops); + if (IS_ERR_OR_NULL(ignored_remove)) { + ret = -ENOMEM; + goto remove; + } + + linker_dir = debugfs_create_dir(LOADER_LINKER_DATA, root); + if (IS_ERR_OR_NULL(linker_dir)) { + ret = -ENOMEM; + goto remove; + } + + linker_path = debugfs_create_file(LOADER_LINKER_PATH, + LOADER_DEFAULT_PERMS, linker_dir, NULL, + &linker_path_file_ops); + if (IS_ERR_OR_NULL(linker_path)) { + ret = -ENOMEM; + goto remove; + } + + linker_offset = debugfs_create_ptr(LOADER_LINKER_R_DEBUG_OFFSET, + LOADER_DEFAULT_PERMS, linker_dir, + &r_debug_offset); + if (IS_ERR_OR_NULL(linker_offset)) { + ret = -ENOMEM; + goto remove; + } + + return 0; + +remove: + + debugfs_remove_recursive(root); + +fail: + printk(LOADER_PREFIX "Debugfs initialization failure: %d\n", ret); + + return ret; +} + +void ld_exit(void) +{ + if (loader_root) + debugfs_remove_recursive(loader_root); + loader_root = NULL; + + loader_module_set_not_ready(); + clean_loader_info(); +} diff --git a/loader/loader_debugfs.h b/loader/loader_debugfs.h new file mode 100644 index 0000000..f07b6f0 --- /dev/null +++ b/loader/loader_debugfs.h @@ -0,0 +1,14 @@ +#ifndef __LOADER_DEBUGFS_H__ +#define __LOADER_DEBUGFS_H__ + +struct dentry; + +int ld_init(void); +void ld_exit(void); + +struct dentry *ld_get_loader_dentry(void); +unsigned long ld_get_loader_offset(void); + +unsigned long ld_r_debug_offset(void); + +#endif /* __LOADER_DEBUGFS_H__ */ diff --git a/loader/loader_module.c b/loader/loader_module.c new file mode 100644 index 0000000..1680311 --- /dev/null +++ b/loader/loader_module.c @@ -0,0 +1,648 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "loader.h" +#include "loader_debugfs.h" +#include "loader_module.h" +#include "loader_storage.h" +#include "loader_control.h" +#include "loader_pd.h" + + +struct us_priv { + struct pt_regs regs; + unsigned long arg0; + unsigned long arg1; + unsigned long raddr; + unsigned long origin; +}; + +static atomic_t dentry_balance = ATOMIC_INIT(0); + +enum loader_status_t { + SWAP_LOADER_NOT_READY = 0, + SWAP_LOADER_READY = 1, + SWAP_LOADER_RUNNING = 2 +}; + +static enum loader_status_t __loader_status = SWAP_LOADER_NOT_READY; + +static int __loader_cbs_start_h = -1; +static int __loader_cbs_stop_h = -1; + + +static struct dentry *__get_dentry(struct dentry *dentry) +{ + atomic_inc(&dentry_balance); + return dget(dentry); +} + + + +bool loader_module_is_running(void) +{ + if (__loader_status == SWAP_LOADER_RUNNING) + return true; + + return false; +} + +bool loader_module_is_ready(void) +{ + if (__loader_status == SWAP_LOADER_READY) + return true; + + return false; +} + +bool loader_module_is_not_ready(void) +{ + if (__loader_status == SWAP_LOADER_NOT_READY) + return true; + + return false; +} + +void loader_module_set_ready(void) +{ + __loader_status = SWAP_LOADER_READY; +} + +void loader_module_set_running(void) +{ + __loader_status = SWAP_LOADER_RUNNING; +} + +void loader_module_set_not_ready(void) +{ + __loader_status = SWAP_LOADER_NOT_READY; +} + +struct dentry *get_dentry(const char *filepath) +{ + struct path path; + struct dentry *dentry = NULL; + + if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) { + dentry = __get_dentry(path.dentry); + path_put(&path); + } + + return dentry; +} + +void put_dentry(struct dentry *dentry) +{ + atomic_dec(&dentry_balance); + dput(dentry); +} + +static inline void __prepare_ujump(struct uretprobe_instance *ri, + struct pt_regs *regs, + unsigned long vaddr) +{ +#ifdef CONFIG_ARM + ri->preload.use = true; + ri->preload.thumb = !!thumb_mode(regs); +#endif /* CONFIG_ARM */ + + swap_set_instr_ptr(regs, vaddr); +} + +static inline int __push(struct pt_regs *regs, void *buf, size_t len) +{ + unsigned long sp = swap_get_stack_ptr(regs) - len; + + sp = PTR_ALIGN(sp, sizeof(unsigned long)); + if (copy_to_user((void __user *)sp, buf, len)) + return -EIO; + swap_set_stack_ptr(regs, sp); + + return 0; +} + +static inline void __save_uregs(struct uretprobe_instance *ri, + struct pt_regs *regs) +{ + struct us_priv *priv = (struct us_priv *)ri->data; + + memcpy(ri->data, regs, sizeof(*regs)); + priv->arg0 = swap_get_arg(regs, 0); + priv->arg1 = swap_get_arg(regs, 1); + priv->raddr = swap_get_ret_addr(regs); +} + +static inline void __restore_uregs(struct uretprobe_instance *ri, + struct pt_regs *regs) +{ + struct us_priv *priv = (struct us_priv *)ri->data; + + memcpy(regs, ri->data, sizeof(*regs)); + swap_set_arg(regs, 0, priv->arg0); + swap_set_arg(regs, 1, priv->arg1); + swap_set_ret_addr(regs, priv->raddr); +#ifndef CONFIG_ARM + /* need to do it only on x86 */ + regs->EREG(ip) -= 1; +#endif /* !CONFIG_ARM */ + /* we have just restored the registers => no need to do it in + * trampoline_uprobe_handler */ + ri->ret_addr = NULL; +} + +static inline void print_regs(const char *prefix, struct pt_regs *regs, + struct uretprobe_instance *ri, struct hd_t *hd) +{ + struct dentry *dentry = lpd_get_dentry(hd); + +#ifdef CONFIG_ARM + printk(LOADER_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, + dentry != NULL ? (char *)(dentry->d_name.name) : + (char *)("NULL"), + (int)lpd_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(LOADER_PREFIX "%s[%d/%d] %s (%d) %s addr(%08lx), " + "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n", + current->comm, current->tgid, current->pid, + dentry != NULL ? (char *)(dentry->d_name.name) : + (char *)("NULL"), + (int)lpd_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)); +#endif /* CONFIG_ARM */ +} + +static inline unsigned long __get_r_debug_off(struct vm_area_struct *linker_vma) +{ + unsigned long start_addr; + unsigned long offset = ld_r_debug_offset(); + + if (linker_vma == NULL) + return 0; + + start_addr = linker_vma->vm_start; + + return (offset ? start_addr + offset : 0); +} + +static struct vm_area_struct *__get_linker_vma(struct task_struct *task) +{ + struct vm_area_struct *vma = NULL; + struct bin_info *ld_info; + + ld_info = ls_get_linker_info(); + if (ld_info == NULL) { + printk(LOADER_PREFIX "Cannot get linker info [%u %u %s]!\n", + task->tgid, task->pid, task->comm); + return NULL; + } + + for (vma = task->mm->mmap; vma; vma = vma->vm_next) { + if (vma->vm_file && vma->vm_flags & VM_EXEC + && vma->vm_file->f_dentry == ld_info->dentry) { + ls_put_linker_info(ld_info); + return vma; + } + } + + ls_put_linker_info(ld_info); + return NULL; +} + +static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task, + unsigned long caller_addr) +{ + struct vm_area_struct *vma = NULL; + + if (task->mm == NULL) + return NULL; + vma = find_vma_intersection(task->mm, caller_addr, caller_addr + 1); + + return vma; +} + + + + + + + + + +static bool __is_proc_mmap_mappable(struct task_struct *task) +{ + struct vm_area_struct *linker_vma = __get_linker_vma(task); + struct sspt_proc *proc; + unsigned long r_debug_addr; + unsigned int state; + enum { r_state_offset = sizeof(int) + sizeof(void *) + sizeof(long) }; + + if (linker_vma == NULL) + return false; + + r_debug_addr = __get_r_debug_off(linker_vma); + if (r_debug_addr == 0) + return false; + + r_debug_addr += r_state_offset; + proc = sspt_proc_get_by_task(task); + if (proc) { + proc->r_state_addr = r_debug_addr; + sspt_proc_put(proc); + } + + if (get_user(state, (unsigned long *)r_debug_addr)) + return false; + + return !state; +} + +static bool __should_we_load_handlers(struct task_struct *task, + struct pt_regs *regs) +{ + unsigned long caller_addr = get_regs_ret_func(regs); + struct vm_area_struct *cvma = __get_vma_by_addr(current, caller_addr); + + if (!__is_proc_mmap_mappable(task) || + ((cvma != NULL) && (cvma->vm_file != NULL) && + (cvma->vm_file->f_path.dentry != NULL) && + lc_check_dentry_is_ignored(cvma->vm_file->f_path.dentry))) + return false; + + return true; +} + + + + + +struct mmap_priv { + struct dentry *dentry; +}; + +static inline bool check_prot(unsigned long prot) +{ + return !!((prot & PROT_READ) && (prot & PROT_EXEC)); +} + +static int mmap_entry_handler(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + 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 pd_t *pd; + struct hd_t *hd; + struct sspt_proc *proc; + + priv->dentry = NULL; + if (!check_prot(prot)) + return 0; + + if (!file) + return 0; + + dentry = file->f_dentry; + if (dentry == NULL) + return 0; + + loader_dentry = ld_get_loader_dentry(); + if (dentry == loader_dentry) { + priv->dentry = loader_dentry; + return 0; + } + + proc = sspt_proc_get_by_task(task); + if (!proc) + return 0; + + pd = lpd_get(proc); + if (pd == NULL) { + printk(LOADER_PREFIX "%d: No process data! Current %d %s\n", + __LINE__, current->tgid, current->comm); + return 0; + } + + hd = lpd_get_hd(pd, dentry); + if (hd != NULL) + priv->dentry = lpd_get_dentry(hd); + + return 0; +} + +static int mmap_ret_handler(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + 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; + unsigned long vaddr; + + if (!task->mm) + return 0; + + if (priv->dentry == NULL) + return 0; + + vaddr = (unsigned long)regs_return_value(regs); + if (IS_ERR_VALUE(vaddr)) + return 0; + + proc = sspt_proc_get_by_task(task); + if (!proc) + return 0; + + pd = lpd_get(proc); + if (pd == NULL) { + printk(LOADER_PREFIX "%d: No process data! Current %d %s\n", + __LINE__, current->tgid, current->comm); + return 0; + } + + loader_dentry = ld_get_loader_dentry(); + if (priv->dentry == loader_dentry) + lpd_set_loader_base(pd, vaddr); + + + hd = lpd_get_hd(pd, priv->dentry); + if (hd != NULL) + lpd_set_handlers_base(hd, vaddr); + + return 0; +} + +static struct kretprobe mmap_rp = { + .kp.symbol_name = "do_mmap_pgoff", + .data_size = sizeof(struct mmap_priv), + .entry_handler = mmap_entry_handler, + .handler = mmap_ret_handler +}; + +static void loader_start_cb(void) +{ + int res; + + res = swap_register_kretprobe(&mmap_rp); + if (res != 0) + printk(KERN_ERR LOADER_PREFIX "Registering do_mmap_pgoff probe failed\n"); +} + +static void loader_stop_cb(void) +{ + swap_unregister_kretprobe(&mmap_rp); +} + +static unsigned long __not_loaded_entry(struct uretprobe_instance *ri, + struct pt_regs *regs, + struct pd_t *pd, struct hd_t *hd) +{ + char __user *path = NULL; + unsigned long vaddr = 0; + unsigned long base; + + /* if linker is still doing its work, we do nothing */ + if (!__should_we_load_handlers(current, regs)) + return 0; + + base = lpd_get_loader_base(pd); + if (base == 0) + return 0; /* loader isn't mapped */ + + /* jump to loader code if ready */ + vaddr = base + ld_get_loader_offset(); + if (vaddr) { + /* save original regs state */ + __save_uregs(ri, regs); + print_regs("ORIG", regs, ri, hd); + + path = lpd_get_path(pd, hd); + + /* set dlopen args: filename, flags */ + swap_set_arg(regs, 0, (unsigned long)path/*swap_get_stack_ptr(regs)*/); + swap_set_arg(regs, 1, 2 /* RTLD_NOW */); + + /* do the jump to dlopen */ + __prepare_ujump(ri, regs, vaddr); + /* set new state */ + lpd_set_state(hd, LOADING); + } + + return vaddr; +} + +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 loading has been completed */ + vaddr = lpd_get_loader_base(pd) + + ld_get_loader_offset(); + if (vaddr && (priv->origin == vaddr)) { + lpd_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 loading done */ + + if (lpd_get_handle(hd)) { + lpd_set_state(hd, LOADED); + } else { + lpd_dec_attempts(hd); + lpd_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 (lpd_get_attempts(hd)) + lpd_set_state(hd, NOT_LOADED); +} + + + +unsigned long loader_not_loaded_entry(struct uretprobe_instance *ri, + struct pt_regs *regs, struct pd_t *pd, + struct hd_t *hd) +{ + return __not_loaded_entry(ri, regs, pd, hd); +} +EXPORT_SYMBOL_GPL(loader_not_loaded_entry); + +void loader_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs, + struct pd_t *pd, struct hd_t *hd) +{ + __loading_ret(ri, regs, pd, hd); +} +EXPORT_SYMBOL_GPL(loader_loading_ret); + +void loader_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs, + struct pd_t *pd, struct hd_t *hd) +{ + __failed_ret(ri, regs, pd, hd); +} +EXPORT_SYMBOL_GPL(loader_failed_ret); + +void loader_module_prepare_ujump(struct uretprobe_instance *ri, + struct pt_regs *regs, unsigned long addr) +{ + __prepare_ujump(ri, regs, addr); +} +EXPORT_SYMBOL_GPL(loader_module_prepare_ujump); + +void loader_set_rp_data_size(struct uretprobe *rp) +{ + rp->data_size = sizeof(struct us_priv); +} +EXPORT_SYMBOL_GPL(loader_set_rp_data_size); + +void loader_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr) +{ + struct us_priv *priv = (struct us_priv *)ri->data; + + priv->origin = addr; +} +EXPORT_SYMBOL_GPL(loader_set_priv_origin); + +unsigned long loader_get_priv_origin(struct uretprobe_instance *ri) +{ + struct us_priv *priv = (struct us_priv *)ri->data; + + return priv->origin; +} +EXPORT_SYMBOL_GPL(loader_get_priv_origin); + + +int loader_set(void) +{ + if (loader_module_is_running()) + return -EBUSY; + + return 0; +} + +void loader_unset(void) +{ + swap_unregister_kretprobe(&mmap_rp); + /*module_put(THIS_MODULE);*/ + loader_module_set_not_ready(); +} + +int loader_add_handler(char *path) +{ + return ls_add_handler(path); +} +EXPORT_SYMBOL_GPL(loader_add_handler); + + +static int loader_module_init(void) +{ + int ret; + + ret = ld_init(); + if (ret) + goto out_err; + + ret = ls_init(); + if (ret) + goto exit_debugfs; + + ret = lpd_init(); + if (ret) + goto exit_storage; + + /* TODO do not forget to remove set (it is just for debugging) */ + ret = loader_set(); + if (ret) + goto exit_pd; + + ret = lc_init(); + if (ret) + goto exit_set; + + __loader_cbs_start_h = us_manager_reg_cb(START_CB, loader_start_cb); + if (__loader_cbs_start_h < 0) + goto exit_start_cb; + + __loader_cbs_stop_h = us_manager_reg_cb(STOP_CB, loader_stop_cb); + if (__loader_cbs_stop_h < 0) + goto exit_stop_cb; + + return 0; + +exit_stop_cb: + us_manager_unreg_cb(__loader_cbs_start_h); + +exit_start_cb: + lc_exit(); + +exit_set: + loader_unset(); + +exit_pd: + lpd_uninit(); + +exit_storage: + ls_exit(); + +exit_debugfs: + ld_exit(); + +out_err: + return ret; +} + +static void loader_module_exit(void) +{ + int balance; + + us_manager_unreg_cb(__loader_cbs_start_h); + us_manager_unreg_cb(__loader_cbs_stop_h); + lc_exit(); + loader_unset(); + lpd_uninit(); + ls_exit(); + ld_exit(); + + balance = atomic_read(&dentry_balance); + atomic_set(&dentry_balance, 0); + + WARN(balance, "Bad GET/PUT dentry balance: %d\n", balance); +} + +SWAP_LIGHT_INIT_MODULE(NULL, loader_module_init, loader_module_exit, + NULL, NULL); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SWAP Loader Module"); +MODULE_AUTHOR("Vasiliy Ulyanov " + "Alexander Aksenov "); diff --git a/loader/loader_module.h b/loader/loader_module.h new file mode 100644 index 0000000..df5da70 --- /dev/null +++ b/loader/loader_module.h @@ -0,0 +1,39 @@ +#ifndef __LOADER_MODULE_H__ +#define __LOADER_MODULE_H__ + +#include + +struct dentry; +struct pd_t; +struct hd_t; +struct uretprobe; +struct uretprobe_instance; + +bool loader_module_is_ready(void); +bool loader_module_is_running(void); +bool loader_module_is_not_ready(void); +void loader_module_set_ready(void); +void loader_module_set_running(void); +void loader_module_set_not_ready(void); + +struct dentry *get_dentry(const char *filepath); +void put_dentry(struct dentry *dentry); + +void loader_module_prepare_ujump(struct uretprobe_instance *ri, + struct pt_regs *regs, unsigned long addr); + +unsigned long loader_not_loaded_entry(struct uretprobe_instance *ri, + struct pt_regs *regs, struct pd_t *pd, + struct hd_t *hd); +void loader_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs, + struct pd_t *pd, struct hd_t *hd); +void loader_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs, + struct pd_t *pd, struct hd_t *hd); + +void loader_set_rp_data_size(struct uretprobe *rp); +void loader_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr); +unsigned long loader_get_priv_origin(struct uretprobe_instance *ri); +int loader_add_handler(char *path); + + +#endif /* __LOADER_MODULE_H__ */ diff --git a/preload/preload_pd.c b/loader/loader_pd.c similarity index 80% rename from preload/preload_pd.c rename to loader/loader_pd.c index 62c242d..beb5c54 100644 --- a/preload/preload_pd.c +++ b/loader/loader_pd.c @@ -8,11 +8,10 @@ #include #include #include -#include "preload_pd.h" -#include "preload_threads.h" -#include "preload_debugfs.h" -#include "preload_storage.h" -#include "preload.h" +#include "loader_pd.h" +#include "loader_debugfs.h" +#include "loader_storage.h" +#include "loader.h" struct pd_t { unsigned long loader_base; @@ -136,7 +135,7 @@ static struct pd_t *__create_pd(void) MAP_ANONYMOUS | MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); if (IS_ERR_VALUE(page)) { - printk(KERN_ERR PRELOAD_PREFIX + printk(KERN_ERR LOADER_PREFIX "Cannot alloc page for %u\n", current->tgid); goto create_pd_fail; } @@ -160,7 +159,7 @@ static size_t __copy_path(char *src, unsigned long page, unsigned long offset) /* set handler path */ if (copy_to_user((void __user *)dest, src, len) != 0) { - printk(KERN_ERR PRELOAD_PREFIX + printk(KERN_ERR LOADER_PREFIX "Cannot copy string to user!\n"); return 0; } @@ -171,7 +170,7 @@ static size_t __copy_path(char *src, unsigned long page, unsigned long offset) static void __set_ld_mapped(struct pd_t *pd, struct mm_struct *mm) { struct vm_area_struct *vma; - struct dentry *ld = preload_debugfs_get_loader_dentry(); + struct dentry *ld = ld_get_loader_dentry(); down_read(&mm->mmap_sem); if (ld) { @@ -212,7 +211,7 @@ static int __get_handlers(struct pd_t *pd, struct task_struct *task) size_t len; int ret = 0; - handlers = preload_storage_get_handlers(); + handlers = ls_get_handlers(); if (handlers == NULL) return -EINVAL; @@ -225,7 +224,7 @@ static int __get_handlers(struct pd_t *pd, struct task_struct *task) hd = kzalloc(sizeof(*hd), GFP_ATOMIC); if (hd == NULL) { - printk(KERN_ERR PRELOAD_PREFIX "No atomic mem!\n"); + printk(KERN_ERR LOADER_PREFIX "No atomic mem!\n"); ret = -ENOMEM; goto get_handlers_out; } @@ -236,7 +235,7 @@ static int __get_handlers(struct pd_t *pd, struct task_struct *task) hd->dentry = bin->dentry; hd->offset = offset; __set_handler_mapped(hd, task->mm); - __set_attempts(hd, PRELOAD_MAX_ATTEMPTS); + __set_attempts(hd, LOADER_MAX_ATTEMPTS); list_add_tail(&hd->list, &pd->handlers); /* inc handlers path's on page */ @@ -245,25 +244,26 @@ static int __get_handlers(struct pd_t *pd, struct task_struct *task) get_handlers_out: /* TODO Cleanup already created */ - preload_storage_put_handlers(); + ls_put_handlers(); return ret; } -enum ps_t preload_pd_get_state(struct hd_t *hd) +enum ps_t lpd_get_state(struct hd_t *hd) { if (hd == NULL) return 0; return __get_state(hd); } +EXPORT_SYMBOL_GPL(lpd_get_state); -void preload_pd_set_state(struct hd_t *hd, enum ps_t state) +void lpd_set_state(struct hd_t *hd, enum ps_t state) { if (hd == NULL) { - printk(PRELOAD_PREFIX "%d: No handler data! Current %d %s\n", + printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n", __LINE__, current->tgid, current->comm); return; } @@ -271,7 +271,7 @@ void preload_pd_set_state(struct hd_t *hd, enum ps_t state) __set_state(hd, state); } -unsigned long preload_pd_get_loader_base(struct pd_t *pd) +unsigned long lpd_get_loader_base(struct pd_t *pd) { if (pd == NULL) return 0; @@ -279,25 +279,26 @@ unsigned long preload_pd_get_loader_base(struct pd_t *pd) return __get_loader_base(pd); } -void preload_pd_set_loader_base(struct pd_t *pd, unsigned long vaddr) +void lpd_set_loader_base(struct pd_t *pd, unsigned long vaddr) { __set_loader_base(pd, vaddr); } -unsigned long preload_pd_get_handlers_base(struct hd_t *hd) +unsigned long lpd_get_handlers_base(struct hd_t *hd) { if (hd == NULL) return 0; return __get_handlers_base(hd); } +EXPORT_SYMBOL_GPL(lpd_get_handlers_base); -void preload_pd_set_handlers_base(struct hd_t *hd, unsigned long vaddr) +void lpd_set_handlers_base(struct hd_t *hd, unsigned long vaddr) { __set_handlers_base(hd, vaddr); } -char __user *preload_pd_get_path(struct pd_t *pd, struct hd_t *hd) +char __user *lpd_get_path(struct pd_t *pd, struct hd_t *hd) { unsigned long page = __get_data_page(pd); unsigned long offset = __get_offset(hd); @@ -307,7 +308,7 @@ char __user *preload_pd_get_path(struct pd_t *pd, struct hd_t *hd) -void *preload_pd_get_handle(struct hd_t *hd) +void *lpd_get_handle(struct hd_t *hd) { if (hd == NULL) return NULL; @@ -315,10 +316,10 @@ void *preload_pd_get_handle(struct hd_t *hd) return __get_handle(hd); } -void preload_pd_set_handle(struct hd_t *hd, void __user *handle) +void lpd_set_handle(struct hd_t *hd, void __user *handle) { if (hd == NULL) { - printk(PRELOAD_PREFIX "%d: No handler data! Current %d %s\n", + printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n", __LINE__, current->tgid, current->comm); return; } @@ -326,7 +327,7 @@ void preload_pd_set_handle(struct hd_t *hd, void __user *handle) __set_handle(hd, handle); } -long preload_pd_get_attempts(struct hd_t *hd) +long lpd_get_attempts(struct hd_t *hd) { if (hd == NULL) return -EINVAL; @@ -334,12 +335,12 @@ long preload_pd_get_attempts(struct hd_t *hd) return __get_attempts(hd); } -void preload_pd_dec_attempts(struct hd_t *hd) +void lpd_dec_attempts(struct hd_t *hd) { long attempts; if (hd == NULL) { - printk(PRELOAD_PREFIX "%d: No handler data! Current %d %s\n", + printk(LOADER_PREFIX "%d: No handler data! Current %d %s\n", __LINE__, current->tgid, current->comm); return; } @@ -349,22 +350,24 @@ void preload_pd_dec_attempts(struct hd_t *hd) __set_attempts(hd, attempts); } -struct dentry *preload_pd_get_dentry(struct hd_t *hd) +struct dentry *lpd_get_dentry(struct hd_t *hd) { return hd->dentry; } -struct pd_t *preload_pd_get_parent_pd(struct hd_t *hd) +struct pd_t *lpd_get_parent_pd(struct hd_t *hd) { return hd->parent; } +EXPORT_SYMBOL_GPL(lpd_get_parent_pd); -struct pd_t *preload_pd_get(struct sspt_proc *proc) +struct pd_t *lpd_get(struct sspt_proc *proc) { return (struct pd_t *)proc->private_data; } +EXPORT_SYMBOL_GPL(lpd_get); -struct hd_t *preload_pd_get_hd(struct pd_t *pd, struct dentry *dentry) +struct hd_t *lpd_get_hd(struct pd_t *pd, struct dentry *dentry) { struct hd_t *hd; @@ -375,6 +378,7 @@ struct hd_t *preload_pd_get_hd(struct pd_t *pd, struct dentry *dentry) return NULL; } +EXPORT_SYMBOL_GPL(lpd_get_hd); static struct pd_t *do_create_pd(struct task_struct *task) { @@ -399,7 +403,7 @@ free_pd: kfree(pd); create_pd_exit: - printk(KERN_ERR PRELOAD_PREFIX "do_pd_create_pd: error=%d\n", ret); + printk(KERN_ERR LOADER_PREFIX "do_pd_create_pd: error=%d\n", ret); return NULL; } @@ -422,7 +426,7 @@ struct sspt_proc_cb pd_cb = { .priv_destroy = pd_destroy }; -int preload_pd_init(void) +int lpd_init(void) { int ret; @@ -431,7 +435,7 @@ int preload_pd_init(void) return ret; } -void preload_pd_uninit(void) +void lpd_uninit(void) { sspt_proc_cb_set(NULL); diff --git a/loader/loader_pd.h b/loader/loader_pd.h new file mode 100644 index 0000000..73fcb2a --- /dev/null +++ b/loader/loader_pd.h @@ -0,0 +1,43 @@ +#ifndef __LOADER_PD_H__ +#define __LOADER_PD_H__ + +#include + +struct pd_t; +struct hd_t; +struct sspt_proc; +struct dentry; +struct list_head; + +/* process loader states */ +enum ps_t { + NOT_LOADED, + LOADING, + LOADED, + FAILED, + ERROR +}; + +struct pd_t *lpd_get(struct sspt_proc *proc); +unsigned long lpd_get_loader_base(struct pd_t *pd); +void lpd_set_loader_base(struct pd_t *pd, unsigned long vaddr); + +struct hd_t *lpd_get_hd(struct pd_t *pd, struct dentry *dentry); +struct dentry *lpd_get_dentry(struct hd_t *hd); +struct pd_t *lpd_get_parent_pd(struct hd_t *hd); +enum ps_t lpd_get_state(struct hd_t *hd); +void lpd_set_state(struct hd_t *hd, enum ps_t state); +unsigned long lpd_get_handlers_base(struct hd_t *hd); +void lpd_set_handlers_base(struct hd_t *hd, unsigned long vaddr); +void *lpd_get_handle(struct hd_t *hd); +void lpd_set_handle(struct hd_t *hd, void __user *handle); +long lpd_get_attempts(struct hd_t *hd); +void lpd_dec_attempts(struct hd_t *hd); + +char __user *lpd_get_path(struct pd_t *pd, struct hd_t *hd); + +int lpd_init(void); +void lpd_uninit(void); + + +#endif /* __LOADER_PD_H__*/ diff --git a/preload/preload_storage.c b/loader/loader_storage.c similarity index 54% rename from preload/preload_storage.c rename to loader/loader_storage.c index f2c9ff1..8386cb8 100644 --- a/preload/preload_storage.c +++ b/loader/loader_storage.c @@ -4,24 +4,29 @@ #include #include #include -#include "preload.h" -#include "preload_module.h" -#include "preload_storage.h" -#include "preload_handlers.h" +#include "loader.h" +#include "loader_module.h" +#include "loader_storage.h" -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; -} -static inline bool __check_handlers_info(void) +static bool __check_dentry_already_exist(struct dentry *dentry) { - return (__handlers_info.dentry != NULL); /* TODO */ + struct bin_info_el *bin; + bool ret = false; + + list_for_each_entry(bin, &handlers_list, list) { + if (bin->dentry == dentry) { + ret = true; + goto out; + } + } + +out: + return ret; } static inline int __add_handler(char *path) @@ -31,10 +36,21 @@ static inline int __add_handler(char *path) struct bin_info_el *bin; int ret = 0; + dentry = get_dentry(path); + if (!dentry) { + ret = -ENOENT; + goto add_handler_out; + } + + if (__check_dentry_already_exist(dentry)) { + ret = 1; + goto add_handler_out; + } + bin = kmalloc(sizeof(*bin), GFP_KERNEL); if (bin == NULL) { ret = -ENOMEM; - goto add_handler_fail; + goto add_handler_fail_release_dentry; } bin->path = kmalloc(len + 1, GFP_KERNEL); @@ -43,12 +59,6 @@ static inline int __add_handler(char *path) 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'; @@ -57,13 +67,13 @@ static inline int __add_handler(char *path) return ret; -add_handler_fail_free_path: - kfree(bin->path); - add_handler_fail_free_bin: kfree(bin); -add_handler_fail: +add_handler_fail_release_dentry: + put_dentry(dentry); + +add_handler_out: return ret; } @@ -83,47 +93,6 @@ static inline void __remove_handlers(void) __remove_handler(bin); } -static inline int __init_handlers_info(char *path) -{ - struct dentry *dentry; - size_t len = strnlen(path, PATH_MAX); - int ret = 0; - - __handlers_info.path = kmalloc(len + 1, GFP_KERNEL); - if (__handlers_info.path == NULL) { - ret = -ENOMEM; - goto init_handlers_fail; - } - - dentry = get_dentry(path); - if (!dentry) { - ret = -ENOENT; - goto init_handlers_fail_free; - } - - strncpy(__handlers_info.path, path, len); - __handlers_info.path[len] = '\0'; - __handlers_info.dentry = dentry; - - return ret; - -init_handlers_fail_free: - kfree(__handlers_info.path); - -init_handlers_fail: - return ret; -} - -static inline void __drop_handlers_info(void) -{ - kfree(__handlers_info.path); - __handlers_info.path = NULL; - - if (__handlers_info.dentry) - put_dentry(__handlers_info.dentry); - __handlers_info.dentry = NULL; -} - static inline struct bin_info *__get_linker_info(void) { return &__linker_info; @@ -180,65 +149,36 @@ static inline void __drop_linker_info(void) -int preload_storage_set_handlers_info(char *path) +int ls_add_handler(char *path) { int ret; - ret = __init_handlers_info(path); - if (ret != 0) - return ret; - + /* If ret is positive - handler was not added, because it is + * already exists */ ret = __add_handler(path); - if (ret != 0) + if (ret < 0) return ret; - ph_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) -{ - struct bin_info *info = __get_handlers_info(); - - if (__check_handlers_info()) - return info; - - return NULL; + return 0; } -struct list_head *preload_storage_get_handlers(void) +struct list_head *ls_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) +void ls_put_handlers(void) { /* TODO dec counter, release sync */ } -int preload_storage_set_linker_info(char *path) +int ls_set_linker_info(char *path) { return __init_linker_info(path); } -struct bin_info *preload_storage_get_linker_info(void) +struct bin_info *ls_get_linker_info(void) { struct bin_info *info = __get_linker_info(); @@ -248,18 +188,17 @@ struct bin_info *preload_storage_get_linker_info(void) return NULL; } -void preload_storage_put_linker_info(struct bin_info *info) +void ls_put_linker_info(struct bin_info *info) { } -int preload_storage_init(void) +int ls_init(void) { return 0; } -void preload_storage_exit(void) +void ls_exit(void) { - __drop_handlers_info(); __drop_linker_info(); __remove_handlers(); } diff --git a/loader/loader_storage.h b/loader/loader_storage.h new file mode 100644 index 0000000..4f84a9c --- /dev/null +++ b/loader/loader_storage.h @@ -0,0 +1,33 @@ +#ifndef __LOADER_STORAGE_H__ +#define __LOADER_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 ls_add_handler(char *path); +struct list_head *ls_get_handlers(void); +void ls_put_handlers(void); + +int ls_set_linker_info(char *path); +struct bin_info *ls_get_linker_info(void); +void ls_put_linker_info(struct bin_info *info); + +int ls_init(void); +void ls_exit(void); + +#endif /* __LOADER_HANDLERS_H__ */ diff --git a/packaging/swap-modules.spec b/packaging/swap-modules.spec index 43d4f59..b2a6709 100755 --- a/packaging/swap-modules.spec +++ b/packaging/swap-modules.spec @@ -57,6 +57,7 @@ install -m 666 energy/swap_energy.ko -t %{buildroot}/opt/swap/sdk install -m 666 parser/swap_message_parser.ko -t %{buildroot}/opt/swap/sdk install -m 666 retprobe/swap_retprobe.ko -t %{buildroot}/opt/swap/sdk install -m 666 webprobe/swap_webprobe.ko -t %{buildroot}/opt/swap/sdk +install -m 666 loader/swap_loader.ko -t %{buildroot}/opt/swap/sdk install -m 666 preload/swap_preload.ko -t %{buildroot}/opt/swap/sdk install -m 666 fbiprobe/swap_fbiprobe.ko -t %{buildroot}/opt/swap/sdk install -m 666 wsp/swap_wsp.ko -t %{buildroot}/opt/swap/sdk @@ -84,6 +85,7 @@ cp LICENSE.GPL-2.0+ %{buildroot}/usr/share/license/%{name} /opt/swap/sdk/swap_message_parser.ko /opt/swap/sdk/swap_retprobe.ko /opt/swap/sdk/swap_webprobe.ko +/opt/swap/sdk/swap_loader.ko /opt/swap/sdk/swap_preload.ko /opt/swap/sdk/swap_fbiprobe.ko /opt/swap/sdk/swap_wsp.ko diff --git a/preload/Kbuild b/preload/Kbuild index e118bce..425a43d 100644 --- a/preload/Kbuild +++ b/preload/Kbuild @@ -2,10 +2,7 @@ EXTRA_CFLAGS := $(extra_cflags) obj-m := swap_preload.o swap_preload-y := preload_module.o \ - preload_handlers.o \ + preload_control.o \ preload_debugfs.o \ - preload_storage.o \ preload_probe.o \ - preload_control.o \ - preload_threads.o \ - preload_pd.o + preload_threads.o diff --git a/preload/preload_control.c b/preload/preload_control.c index 841ab28..f895f81 100644 --- a/preload/preload_control.c +++ b/preload/preload_control.c @@ -6,9 +6,9 @@ #include #include "preload.h" +#include "preload_module.h" #include "preload_control.h" #include "preload_probe.h" -#include "preload_module.h" struct bin_desc { struct list_head list; @@ -202,7 +202,7 @@ out: /* Called only form handlers. If we're there, then it is instrumented. */ -enum preload_call_type preload_control_call_type_always_inst(void *caller) +enum preload_call_type pc_call_type_always_inst(void *caller) { if (__is_instrumented(caller)) return INTERNAL_CALL; @@ -211,7 +211,7 @@ enum preload_call_type preload_control_call_type_always_inst(void *caller) } -enum preload_call_type preload_control_call_type(struct sspt_ip *ip, void *caller) +enum preload_call_type pc_call_type(struct sspt_ip *ip, void *caller) { if (__is_instrumented(caller)) return INTERNAL_CALL; @@ -222,7 +222,7 @@ enum preload_call_type preload_control_call_type(struct sspt_ip *ip, void *calle return NOT_INSTRUMENTED; } -int preload_control_add_instrumented_binary(char *filename) +int pc_add_instrumented_binary(char *filename) { struct dentry *dentry = get_dentry(filename); int res = 0; @@ -237,14 +237,14 @@ int preload_control_add_instrumented_binary(char *filename) return res > 0 ? 0 : res; } -int preload_control_clean_instrumented_bins(void) +int pc_clean_instrumented_bins(void) { __free_binaries(&target); return 0; } -int preload_control_add_ignored_binary(char *filename) +int pc_add_ignored_binary(char *filename) { struct dentry *dentry = get_dentry(filename); int res = 0; @@ -259,34 +259,34 @@ int preload_control_add_ignored_binary(char *filename) return res > 0 ? 0 : res; } -int preload_control_clean_ignored_bins(void) +int pc_clean_ignored_bins(void) { __free_binaries(&ignored); return 0; } -unsigned int preload_control_get_target_names(char ***filenames_p) +unsigned int pc_get_target_names(char ***filenames_p) { return __get_names(&target, filenames_p); } -void preload_control_release_target_names(char ***filenames_p) +void pc_release_target_names(char ***filenames_p) { kfree(*filenames_p); } -unsigned int preload_control_get_ignored_names(char ***filenames_p) +unsigned int pc_get_ignored_names(char ***filenames_p) { return __get_names(&ignored, filenames_p); } -void preload_control_release_ignored_names(char ***filenames_p) +void pc_release_ignored_names(char ***filenames_p) { kfree(*filenames_p); } -bool preload_control_check_dentry_is_ignored(struct dentry *dentry) +bool pc_check_dentry_is_ignored(struct dentry *dentry) { struct bin_desc *p; bool ret = false; @@ -308,12 +308,12 @@ bool preload_control_check_dentry_is_ignored(struct dentry *dentry) return ret; } -int preload_control_init(void) +int pc_init(void) { return 0; } -void preload_control_exit(void) +void pc_exit(void) { __free_binaries(&target); __free_binaries(&ignored); diff --git a/preload/preload_control.h b/preload/preload_control.h index 419d61e..4e6f1d0 100644 --- a/preload/preload_control.h +++ b/preload/preload_control.h @@ -9,22 +9,22 @@ enum preload_call_type { INTERNAL_CALL }; -int preload_control_init(void); -void preload_control_exit(void); +int pc_init(void); +void pc_exit(void); -enum preload_call_type preload_control_call_type_always_inst(void *caller); -enum preload_call_type preload_control_call_type(struct sspt_ip *ip, void *caller); -int preload_control_add_instrumented_binary(char *filename); -int preload_control_clean_instrumented_bins(void); -int preload_control_add_ignored_binary(char *filename); -int preload_control_clean_ignored_bins(void); +enum preload_call_type pc_call_type_always_inst(void *caller); +enum preload_call_type pc_call_type(struct sspt_ip *ip, void *caller); +int pc_add_instrumented_binary(char *filename); +int pc_clean_instrumented_bins(void); +int pc_add_ignored_binary(char *filename); +int pc_clean_ignored_bins(void); -unsigned int preload_control_get_target_names(char ***filenames_p); -void preload_control_release_target_names(char ***filenames_p); +unsigned int pc_get_target_names(char ***filenames_p); +void pc_release_target_names(char ***filenames_p); -unsigned int preload_control_get_ignored_names(char ***filenames_p); -void preload_control_release_ignored_names(char ***filenames_p); +unsigned int pc_get_ignored_names(char ***filenames_p); +void pc_release_ignored_names(char ***filenames_p); -bool preload_control_check_dentry_is_ignored(struct dentry *dentry); +bool pc_check_dentry_is_ignored(struct dentry *dentry); -#endif /* __PRELOAD_CONTROL_H__ */ +#endif /* __PRELOAD_HANDLERS_CONTROL_H__ */ diff --git a/preload/preload_debugfs.c b/preload/preload_debugfs.c index 9896aef..b525b05 100644 --- a/preload/preload_debugfs.c +++ b/preload/preload_debugfs.c @@ -9,36 +9,20 @@ #include #include #include "preload.h" -#include "preload_debugfs.h" #include "preload_module.h" +#include "preload_debugfs.h" #include "preload_control.h" -#include "preload_storage.h" static const char PRELOAD_FOLDER[] = "preload"; -static const char PRELOAD_LOADER[] = "loader"; -static const char PRELOAD_LOADER_OFFSET[] = "loader_offset"; -static const char PRELOAD_LOADER_PATH[] = "loader_path"; +static const char PRELOAD_HANDLER[] = "handler"; static const char PRELOAD_TARGET[] = "target_binaries"; static const char PRELOAD_IGNORED[] = "ignored_binaries"; static const char PRELOAD_BINARIES_LIST[] = "bins_list"; static const char PRELOAD_BINARIES_ADD[] = "bins_add"; static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove"; -static const char PRELOAD_CALLER[] = "caller"; -static const char PRELOAD_HANDLERS_PATH[] = "handlers_path"; -static const char PRELOAD_LINKER_DATA[] = "linker"; -static const char PRELOAD_LINKER_PATH[] = "linker_path"; -static const char PRELOAD_LINKER_R_DEBUG_OFFSET[] = "r_debug_offset"; -struct loader_info { - char *path; - unsigned long offset; - struct dentry *dentry; -}; static struct dentry *preload_root; -static struct loader_info __loader_info; - - static struct dentry *target_list = NULL; static struct dentry *target_add = NULL; static struct dentry *target_remove = NULL; @@ -46,128 +30,6 @@ static struct dentry *ignored_list = NULL; static struct dentry *ignored_add = NULL; static struct dentry *ignored_remove = NULL; -static unsigned long r_debug_offset = 0; -static DEFINE_SPINLOCK(__dentry_lock); - -static inline void dentry_lock(void) -{ - spin_lock(&__dentry_lock); -} - -static inline void dentry_unlock(void) -{ - spin_unlock(&__dentry_lock); -} - - -static void set_loader_file(char *path) -{ - __loader_info.path = path; - dentry_lock(); - __loader_info.dentry = get_dentry(__loader_info.path); - dentry_unlock(); -} - -struct dentry *preload_debugfs_get_loader_dentry(void) -{ - struct dentry *dentry; - - dentry_lock(); - dentry = __loader_info.dentry; - dentry_unlock(); - - return dentry; -} - -unsigned long preload_debugfs_get_loader_offset(void) -{ - /* TODO Think about sync */ - return __loader_info.offset; -} - -static void clean_loader_info(void) -{ - if (__loader_info.path != NULL) - kfree(__loader_info.path); - __loader_info.path = NULL; - - dentry_lock(); - if (__loader_info.dentry != NULL) - put_dentry(__loader_info.dentry); - - __loader_info.dentry = NULL; - __loader_info.offset = 0; - - dentry_unlock(); -} - -struct dentry *debugfs_create_ptr(const char *name, mode_t mode, - struct dentry *parent, - unsigned long *value) -{ - struct dentry *dentry; - -#if BITS_PER_LONG == 32 - dentry = debugfs_create_x32(name, mode, parent, (u32 *)value); -#elif BITS_PER_LONG == 64 - dentry = debugfs_create_x64(name, mode, parent, (u64 *)value); -#else -#error Unsupported BITS_PER_LONG value -#endif - - return dentry; -} - - -/* =========================================================================== - * = LOADER PATH = - * =========================================================================== - */ - -static ssize_t loader_path_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - ssize_t ret; - char *path; - - if (preload_module_is_running()) - return -EBUSY; - - clean_loader_info(); - - path = kmalloc(len, GFP_KERNEL); - if (path == NULL) { - return -ENOMEM; - } - - if (copy_from_user(path, buf, len)) { - ret = -EINVAL; - goto err; - } - - path[len - 1] = '\0'; - set_loader_file(path); - - ret = preload_control_add_ignored_binary(path); - if (ret < 0) { - printk(PRELOAD_PREFIX "Cannot add loader %s to ignored list\n", path); - goto err; - } - - ret = len; - - return ret; -err: - kfree(path); - return ret; -} - - -static const struct file_operations loader_path_file_ops = { - .owner = THIS_MODULE, - .write = loader_path_write, -}; - /* =========================================================================== * = BIN PATH = @@ -194,9 +56,9 @@ static ssize_t bin_add_write(struct file *file, const char __user *buf, path[len - 1] = '\0'; if (file->f_path.dentry == target_add) - ret = preload_control_add_instrumented_binary(path); + ret = pc_add_instrumented_binary(path); else if (file->f_path.dentry == ignored_add) - ret = preload_control_add_ignored_binary(path); + ret = pc_add_ignored_binary(path); else { /* Should never occur */ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__, @@ -226,9 +88,9 @@ static ssize_t bin_remove_write(struct file *file, const char __user *buf, ssize_t ret; if (file->f_path.dentry == target_remove) - ret = preload_control_clean_instrumented_bins(); + ret = pc_clean_instrumented_bins(); else if (file->f_path.dentry == ignored_remove) - ret = preload_control_clean_ignored_bins(); + ret = pc_clean_ignored_bins(); else { /* Should never occur */ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__, @@ -260,9 +122,9 @@ static ssize_t bin_list_read(struct file *file, char __user *usr_buf, char *ptr = NULL; if (file->f_path.dentry == target_list) { - files_cnt = preload_control_get_target_names(&filenames); + files_cnt = pc_get_target_names(&filenames); } else if (file->f_path.dentry == ignored_list) { - files_cnt = preload_control_get_ignored_names(&filenames); + files_cnt = pc_get_ignored_names(&filenames); } else { /* Should never occur */ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__, @@ -302,9 +164,9 @@ static ssize_t bin_list_read(struct file *file, char __user *usr_buf, bin_list_read_fail: if (file->f_path.dentry == target_list) { - preload_control_release_target_names(&filenames); + pc_release_target_names(&filenames); } else if (file->f_path.dentry == ignored_list) { - preload_control_release_ignored_names(&filenames); + pc_release_ignored_names(&filenames); } else { /* Should never occur */ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__, @@ -331,66 +193,14 @@ static const struct file_operations bin_remove_file_ops = { .write = bin_remove_write, }; - /* =========================================================================== - * = LINKER PATH = + * = HANDLER = * =========================================================================== */ -static ssize_t linker_path_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - ssize_t ret; - char *path; - - path = kmalloc(len, GFP_KERNEL); - if (path == NULL) { - ret = -ENOMEM; - goto linker_path_write_out; - } - - if (copy_from_user(path, buf, len)) { - ret = -EINVAL; - goto linker_path_write_out; - } - - path[len - 1] = '\0'; - - if (preload_storage_set_linker_info(path) != 0) { - printk(PRELOAD_PREFIX "Cannot set linker path %s\n", path); - ret = -EINVAL; - goto linker_path_write_out; - } - - ret = preload_control_add_ignored_binary(path); - if (ret < 0) { - printk(PRELOAD_PREFIX "Cannot add linker %s to ignored list\n", path); - goto linker_path_write_out; - } - - ret = len; - -linker_path_write_out: - kfree(path); - - return ret; -} - -static const struct file_operations linker_path_file_ops = { - .owner = THIS_MODULE, - .write = linker_path_write, -}; - - -/* =========================================================================== - * = HANDLERS PATH = - * =========================================================================== - */ - - -static ssize_t handlers_path_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) +static ssize_t handler_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) { ssize_t ret; char *path; @@ -408,7 +218,7 @@ static ssize_t handlers_path_write(struct file *file, const char __user *buf, path[len - 1] = '\0'; - if (preload_storage_set_handlers_info(path) != 0) { + if (pm_set_handler(path) != 0) { printk(PRELOAD_PREFIX "Cannot set handler path %s\n", path); ret = -EINVAL; goto handlers_path_write_out; @@ -422,24 +232,17 @@ handlers_path_write_out: return ret; } -static const struct file_operations handlers_path_file_ops = { +static const struct file_operations handler_file_ops = { .owner = THIS_MODULE, - .write = handlers_path_write, + .write = handler_write, }; -unsigned long preload_debugfs_r_debug_offset(void) +int pd_init(void) { - return r_debug_offset; -} - -int preload_debugfs_init(void) -{ - struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path, - *target_path, *ignored_path, *linker_dir, *linker_path, - *linker_offset, *handlers_path; + struct dentry *swap_dentry, *root, *target_path, *ignored_path, *handler; int ret; ret = -ENODEV; @@ -458,26 +261,6 @@ int preload_debugfs_init(void) preload_root = root; - loader = debugfs_create_dir(PRELOAD_LOADER, root); - if (IS_ERR_OR_NULL(root)) { - ret = -ENOMEM; - goto remove; - } - - open_p = debugfs_create_ptr(PRELOAD_LOADER_OFFSET, PRELOAD_DEFAULT_PERMS, - loader, &__loader_info.offset); - if (IS_ERR_OR_NULL(open_p)) { - ret = -ENOMEM; - goto remove; - } - - lib_path = debugfs_create_file(PRELOAD_LOADER_PATH, PRELOAD_DEFAULT_PERMS, - loader, NULL, &loader_path_file_ops); - if (IS_ERR_OR_NULL(lib_path)) { - ret = -ENOMEM; - goto remove; - } - target_path = debugfs_create_dir(PRELOAD_TARGET, root); if (IS_ERR_OR_NULL(target_path)) { ret = -ENOMEM; @@ -538,32 +321,9 @@ int preload_debugfs_init(void) goto remove; } - linker_dir = debugfs_create_dir(PRELOAD_LINKER_DATA, root); - if (IS_ERR_OR_NULL(linker_dir)) { - ret = -ENOMEM; - goto remove; - } - - linker_path = debugfs_create_file(PRELOAD_LINKER_PATH, - PRELOAD_DEFAULT_PERMS, linker_dir, NULL, - &linker_path_file_ops); - if (IS_ERR_OR_NULL(linker_path)) { - ret = -ENOMEM; - goto remove; - } - - linker_offset = debugfs_create_ptr(PRELOAD_LINKER_R_DEBUG_OFFSET, - PRELOAD_DEFAULT_PERMS, linker_dir, - &r_debug_offset); - if (IS_ERR_OR_NULL(linker_offset)) { - ret = -ENOMEM; - goto remove; - } - - handlers_path = debugfs_create_file(PRELOAD_HANDLERS_PATH, - PRELOAD_DEFAULT_PERMS, root, NULL, - &handlers_path_file_ops); - if (IS_ERR_OR_NULL(handlers_path)) { + handler = debugfs_create_file(PRELOAD_HANDLER, PRELOAD_DEFAULT_PERMS, + preload_root, NULL, &handler_file_ops); + if (IS_ERR_OR_NULL(handler)) { ret = -ENOMEM; goto remove; } @@ -580,7 +340,7 @@ fail: return ret; } -void preload_debugfs_exit(void) +void pd_exit(void) { if (preload_root) debugfs_remove_recursive(preload_root); @@ -591,7 +351,4 @@ void preload_debugfs_exit(void) ignored_add = NULL; ignored_remove = NULL; preload_root = NULL; - - preload_module_set_not_ready(); - clean_loader_info(); } diff --git a/preload/preload_debugfs.h b/preload/preload_debugfs.h index d2c457b..bae931d 100644 --- a/preload/preload_debugfs.h +++ b/preload/preload_debugfs.h @@ -1,16 +1,9 @@ -#ifndef __PRELOAD_DEBUGFS_H__ -#define __PRELOAD_DEBUGFS_H__ +#ifndef __PRELOAD_HANDLERS_DEBUGFS_H__ +#define __PRELOAD_HANDLERS_DEBUGFS_H__ struct dentry; -int preload_debugfs_init(void); -void preload_debugfs_exit(void); +int pd_init(void); +void pd_exit(void); -struct dentry *preload_debugfs_get_loader_dentry(void); -unsigned long preload_debugfs_get_loader_offset(void); - -struct dentry *preload_debugfs_create_new_thread(unsigned long tid); - -unsigned long preload_debugfs_r_debug_offset(void); - -#endif /* __PRELOAD_DEBUGFS_H__ */ +#endif /* __PRELOAD_HANDLERS_DEBUGFS_H__ */ diff --git a/preload/preload_handlers.c b/preload/preload_handlers.c deleted file mode 100644 index ec5fa84..0000000 --- a/preload/preload_handlers.c +++ /dev/null @@ -1,474 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "preload.h" -#include "preload_pd.h" -#include "preload_control.h" -#include "preload_threads.h" -#include "preload_module.h" - -#define page_to_proc(page) ((page)->file->proc) -#define ip_to_proc(ip) page_to_proc((ip)->page) -#define urp_to_ip(rp) container_of(rp, struct sspt_ip, retprobe) - -enum { - /* task preload flags */ - HANDLER_RUNNING = 0x1 -}; - -static struct dentry *handler_dentry = NULL; - - -static inline struct pd_t *__get_process_data(struct uretprobe *rp) -{ - struct sspt_ip *ip = urp_to_ip(rp); - struct sspt_proc *proc = ip_to_proc(ip); - - return preload_pd_get(proc); -} - -static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task, - unsigned long caddr) -{ - struct vm_area_struct *vma = NULL; - - if ((task == NULL) || (task->mm == NULL)) - return NULL; - vma = find_vma_intersection(task->mm, caddr, caddr + 1); - - return vma; -} - -static inline bool __is_probe_non_block(struct sspt_ip *ip) -{ - if (ip->desc->info.pl_i.flags & SWAP_PRELOAD_NON_BLOCK_PROBE) - return true; - - return false; -} - -static inline bool __inverted(struct sspt_ip *ip) -{ - unsigned long flags = ip->desc->info.pl_i.flags; - - if (flags & SWAP_PRELOAD_INVERTED_PROBE) - return true; - - return false; -} - -static inline bool __check_flag_and_call_type(struct sspt_ip *ip, - enum preload_call_type ct) -{ - bool inverted = __inverted(ip); - - if (ct != NOT_INSTRUMENTED || inverted) - return true; - - return false; -} - -static inline bool __is_handlers_call(struct vm_area_struct *caller, - struct pd_t *pd) -{ - struct hd_t *hd; - - if (caller == NULL || caller->vm_file == NULL || - caller->vm_file->f_path.dentry == NULL) { - return false; - } - - hd = preload_pd_get_hd(pd, caller->vm_file->f_path.dentry); - if (hd != NULL) - return true; - - return false; -} - -static inline bool __should_drop(struct sspt_ip *ip, enum preload_call_type ct) -{ - if (ct == NOT_INSTRUMENTED) - return true; - - return false; -} - -static inline int __msg_sanitization(char *user_msg, size_t len, - char *call_type_p, char *caller_p) -{ - if ((call_type_p < user_msg) || (call_type_p > user_msg + len) || - (caller_p < user_msg) || (caller_p > user_msg + len)) - return -EINVAL; - - return 0; -} - - - - -static unsigned long __do_preload_entry(struct uretprobe_instance *ri, - struct pt_regs *regs, - struct hd_t *hd) -{ - struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe); - unsigned long offset = ip->desc->info.pl_i.handler; - unsigned long vaddr = 0; - unsigned long base; - unsigned long disable_addr; - unsigned long caddr; - struct vm_area_struct *cvma; - enum preload_call_type ct; - - base = preload_pd_get_handlers_base(hd); - if (base == 0) - return 0; /* handlers isn't mapped */ - - /* jump to preloaded handler */ - vaddr = base + offset; - if (vaddr) { - caddr = get_regs_ret_func(regs); - cvma = __get_vma_by_addr(current, caddr); - ct = preload_control_call_type(ip, (void *)caddr); - disable_addr = __is_probe_non_block(ip) ? ip->orig_addr : 0; - - /* jump only if caller is instumented and it is not a system lib - - * this leads to some errors */ - if (cvma != NULL && cvma->vm_file != NULL && - cvma->vm_file->f_dentry != NULL) { - - struct dentry *dentry = cvma->vm_file->f_dentry; - struct pd_t *pd = preload_pd_get_parent_pd(hd); - - if (!preload_control_check_dentry_is_ignored(dentry) && - __check_flag_and_call_type(ip, ct) && - !__is_handlers_call(cvma, pd)) { - - bool drop = __should_drop(ip, ct); - if (preload_threads_set_data(current, caddr, - ct, disable_addr, - drop) != 0) - printk(PRELOAD_PREFIX "Error! Failed " - "to set caller 0x%lx for " - "%d/%d\n", caddr, - current->tgid, - current->pid); - /* args are not changed */ - preload_module_prepare_ujump(ri, regs, vaddr); - if (disable_addr == 0) - set_preload_flags(current, - HANDLER_RUNNING); - } - } - } - - return vaddr; -} - -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 old_pc = swap_get_instr_ptr(regs); - unsigned long flags = get_preload_flags(current); - struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe); - unsigned long vaddr = 0; - - if (handler_dentry == NULL) - goto out_set_orig; - - if ((flags & HANDLER_RUNNING) || - preload_threads_check_disabled_probe(current, ip->orig_addr)) - goto out_set_orig; - - 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 = preload_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: - preload_set_priv_origin(ri, vaddr); - - /* PC change check */ - return old_pc != swap_get_instr_ptr(regs); -} - -static void __do_preload_ret(struct uretprobe_instance *ri, struct hd_t *hd) -{ - struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe); - unsigned long flags = get_preload_flags(current); - unsigned long offset = ip->desc->info.pl_i.handler; - unsigned long vaddr = 0; - - if ((flags & HANDLER_RUNNING) || - preload_threads_check_disabled_probe(current, ip->orig_addr)) { - bool non_blk_probe = __is_probe_non_block(ip); - - /* drop the flag if the handler has completed */ - vaddr = preload_pd_get_handlers_base(hd) + offset; - if (vaddr && (preload_get_priv_origin(ri) == vaddr)) { - if (preload_threads_put_data(current) != 0) - printk(PRELOAD_PREFIX "Error! Failed to put " - "caller slot for %d/%d\n", current->tgid, - current->pid); - if (!non_blk_probe) { - flags &= ~HANDLER_RUNNING; - set_preload_flags(current, flags); - } - } - } -} - -static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs) -{ - struct pd_t *pd = __get_process_data(ri->rp); - struct hd_t *hd; - - if (handler_dentry == NULL) - return 0; - - hd = preload_pd_get_hd(pd, handler_dentry); - if (hd == NULL) - return 0; - - switch (preload_pd_get_state(hd)) { - case NOT_LOADED: - /* loader has not yet been mapped... just ignore */ - break; - case LOADING: - preload_loading_ret(ri, regs, pd, hd); - break; - case LOADED: - __do_preload_ret(ri, hd); - break; - case FAILED: - preload_failed_ret(ri, regs, pd, hd); - break; - case ERROR: - default: - break; - } - - return 0; -} - - - - - -static void __write_data_to_msg(char *msg, size_t len, - unsigned long call_type_off, - unsigned long caller_off, - unsigned long caller_addr) -{ - unsigned char call_type = 0; - unsigned long caller = 0; - int ret; - - if (caller_addr != 0) { - caller = caller_addr; - call_type = - preload_control_call_type_always_inst((void *)caller); - } else { - ret = preload_threads_get_caller(current, &caller); - if (ret != 0) { - caller = 0xbadbeef; - printk(PRELOAD_PREFIX "Error! Cannot get caller address" - " for %d/%d\n", current->tgid, current->pid); - } - - ret = preload_threads_get_call_type(current, &call_type); - if (ret != 0) { - call_type = 0xff; - printk(PRELOAD_PREFIX "Error! Cannot get call type for " - "%d/%d\n", current->tgid, current->pid); - } - } - - /* Using the same types as in the library. */ - *(uint32_t *)(msg + call_type_off) = (uint32_t)call_type; - *(uintptr_t *)(msg + caller_off) = (uintptr_t)caller; -} - -static int write_msg_handler(struct uprobe *p, struct pt_regs *regs) -{ - char *user_buf; - char *buf; - char *caller_p; - char *call_type_p; - size_t len; - unsigned long caller_offset; - unsigned long call_type_offset; - unsigned long caller_addr; - int ret; - - /* FIXME: swap_get_uarg uses get_user(), it might sleep */ - user_buf = (char *)swap_get_uarg(regs, 0); - len = swap_get_uarg(regs, 1); - call_type_p = (char *)swap_get_uarg(regs, 2); - caller_p = (char *)swap_get_uarg(regs, 3); - caller_addr = swap_get_uarg(regs, 4); - - ret = __msg_sanitization(user_buf, len, call_type_p, caller_p); - if (ret != 0) { - printk(PRELOAD_PREFIX "Invalid message pointers!\n"); - return 0; - } - - ret = preload_threads_get_drop(current); - if (ret > 0) - return 0; - - buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) { - printk(PRELOAD_PREFIX "No mem for buffer! Size = %d\n", len); - return 0; - } - - ret = read_proc_vm_atomic(current, (unsigned long)user_buf, buf, len); - if (ret < 0) { - printk(PRELOAD_PREFIX "Cannot copy data from userspace! Size = " - "%d ptr 0x%lx ret %d\n", len, - (unsigned long)user_buf, ret); - goto write_msg_fail; - } - - /* Evaluating call_type and caller offset in message: - * data offset = data pointer - beginning of the message. - */ - call_type_offset = (unsigned long)(call_type_p - user_buf); - caller_offset = (unsigned long)(caller_p - user_buf); - - __write_data_to_msg(buf, len, call_type_offset, caller_offset, - caller_addr); - - ret = swap_msg_raw(buf, len); - if (ret != len) - printk(PRELOAD_PREFIX "Error writing probe lib message\n"); - -write_msg_fail: - kfree(buf); - - return 0; -} - - - - - - - - - -static int get_caller_handler(struct uprobe *p, struct pt_regs *regs) -{ - unsigned long caller; - int ret; - - ret = preload_threads_get_caller(current, &caller); - if (ret != 0) { - caller = 0xbadbeef; - printk(PRELOAD_PREFIX "Error! Cannot get caller address for " - "%d/%d\n", current->tgid, current->pid); - } - - swap_put_uarg(regs, 0, caller); - - return 0; -} - -static int get_call_type_handler(struct uprobe *p, struct pt_regs *regs) -{ - unsigned char call_type; - int ret; - - ret = preload_threads_get_call_type(current, &call_type); - if (ret != 0) { - call_type = 0xff; - printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n", - current->tgid, current->pid); - } - - swap_put_uarg(regs, 0, call_type); - - return 0; -} - - - - - - -int ph_get_caller_init(struct sspt_ip *ip) -{ - struct uprobe *up = &ip->uprobe; - - up->pre_handler = get_caller_handler; - - return 0; -} - -void ph_get_caller_exit(struct sspt_ip *ip) -{ -} - -int ph_get_call_type_init(struct sspt_ip *ip) -{ - struct uprobe *up = &ip->uprobe; - - up->pre_handler = get_call_type_handler; - - return 0; -} - -void ph_get_call_type_exit(struct sspt_ip *ip) -{ -} - -int ph_write_msg_init(struct sspt_ip *ip) -{ - struct uprobe *up = &ip->uprobe; - - up->pre_handler = write_msg_handler; - - return 0; -} - -void ph_write_msg_exit(struct sspt_ip *ip) -{ -} - -void ph_set_handler_dentry(struct dentry *dentry) -{ - handler_dentry = dentry; -} - - -int ph_uprobe_init(struct sspt_ip *ip) -{ - struct uretprobe *rp = &ip->retprobe; - - rp->entry_handler = preload_us_entry; - rp->handler = preload_us_ret; - /* FIXME actually additional data_size is needed only when we jump - * to dlopen */ - preload_set_rp_data_size(rp); - - return 0; -} - -void ph_uprobe_exit(struct sspt_ip *ip) -{ -} diff --git a/preload/preload_handlers.h b/preload/preload_handlers.h deleted file mode 100644 index 04e4360..0000000 --- a/preload/preload_handlers.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __PRELOAD_HANDLERS_H__ -#define __PRELOAD_HANDLERS_H__ - -struct sspt_ip; -struct dentry; - -int ph_uprobe_init(struct sspt_ip *ip); -void ph_uprobe_exit(struct sspt_ip *ip); - -int ph_get_caller_init(struct sspt_ip *ip); -void ph_get_caller_exit(struct sspt_ip *ip); -int ph_get_call_type_init(struct sspt_ip *ip); -void ph_get_call_type_exit(struct sspt_ip *ip); -int ph_write_msg_init(struct sspt_ip *ip); -void ph_write_msg_exit(struct sspt_ip *ip); -void ph_set_handler_dentry(struct dentry *dentry); - -#endif /* __PRELOAD_HANDLERS_H__ */ diff --git a/preload/preload_module.c b/preload/preload_module.c index b614042..ce6edb7 100644 --- a/preload/preload_module.c +++ b/preload/preload_module.c @@ -1,654 +1,566 @@ -#include -#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include #include "preload.h" -#include "preload_probe.h" -#include "preload_debugfs.h" #include "preload_module.h" -#include "preload_storage.h" +#include "preload_debugfs.h" #include "preload_control.h" #include "preload_threads.h" -#include "preload_pd.h" +#define page_to_proc(page) ((page)->file->proc) +#define ip_to_proc(ip) page_to_proc((ip)->page) +#define urp_to_ip(rp) container_of(rp, struct sspt_ip, retprobe) -struct us_priv { - struct pt_regs regs; - unsigned long arg0; - unsigned long arg1; - unsigned long raddr; - unsigned long origin; +enum { + /* task preload flags */ + HANDLER_RUNNING = 0x1 }; -static atomic_t dentry_balance = ATOMIC_INIT(0); +static struct dentry *handler_dentry = NULL; -enum preload_status_t { - SWAP_PRELOAD_NOT_READY = 0, - SWAP_PRELOAD_READY = 1, - SWAP_PRELOAD_RUNNING = 2 -}; - -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 inline struct pd_t *__get_process_data(struct uretprobe *rp) +{ + struct sspt_ip *ip = urp_to_ip(rp); + struct sspt_proc *proc = ip_to_proc(ip); + return lpd_get(proc); +} -static struct dentry *__get_dentry(struct dentry *dentry) +static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task, + unsigned long caddr) { - atomic_inc(&dentry_balance); - return dget(dentry); -} + struct vm_area_struct *vma = NULL; + if ((task == NULL) || (task->mm == NULL)) + return NULL; + vma = find_vma_intersection(task->mm, caddr, caddr + 1); + return vma; +} -bool preload_module_is_running(void) +static inline bool __is_probe_non_block(struct sspt_ip *ip) { - if (__preload_status == SWAP_PRELOAD_RUNNING) + if (ip->desc->info.pl_i.flags & SWAP_PRELOAD_NON_BLOCK_PROBE) return true; return false; } -bool preload_module_is_ready(void) +static inline bool __inverted(struct sspt_ip *ip) { - if (__preload_status == SWAP_PRELOAD_READY) + unsigned long flags = ip->desc->info.pl_i.flags; + + if (flags & SWAP_PRELOAD_INVERTED_PROBE) return true; return false; } -bool preload_module_is_not_ready(void) +static inline bool __check_flag_and_call_type(struct sspt_ip *ip, + enum preload_call_type ct) { - if (__preload_status == SWAP_PRELOAD_NOT_READY) + bool inverted = __inverted(ip); + + if (ct != NOT_INSTRUMENTED || inverted) return true; return false; } -void preload_module_set_ready(void) -{ - __preload_status = SWAP_PRELOAD_READY; -} - -void preload_module_set_running(void) +static inline bool __is_handlers_call(struct vm_area_struct *caller, + struct pd_t *pd) { - __preload_status = SWAP_PRELOAD_RUNNING; -} - -void preload_module_set_not_ready(void) -{ - __preload_status = SWAP_PRELOAD_NOT_READY; -} - -struct dentry *get_dentry(const char *filepath) -{ - struct path path; - struct dentry *dentry = NULL; + struct hd_t *hd; - if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) { - dentry = __get_dentry(path.dentry); - path_put(&path); + if (caller == NULL || caller->vm_file == NULL || + caller->vm_file->f_path.dentry == NULL) { + return false; } - return dentry; -} + hd = lpd_get_hd(pd, caller->vm_file->f_path.dentry); + if (hd != NULL) + return true; -void put_dentry(struct dentry *dentry) -{ - atomic_dec(&dentry_balance); - dput(dentry); + return false; } -static inline void __prepare_ujump(struct uretprobe_instance *ri, - struct pt_regs *regs, - unsigned long vaddr) +static inline bool __should_drop(struct sspt_ip *ip, enum preload_call_type ct) { -#ifdef CONFIG_ARM - ri->preload.use = true; - ri->preload.thumb = !!thumb_mode(regs); -#endif /* CONFIG_ARM */ + if (ct == NOT_INSTRUMENTED) + return true; - swap_set_instr_ptr(regs, vaddr); + return false; } -static inline int __push(struct pt_regs *regs, void *buf, size_t len) +static inline int __msg_sanitization(char *user_msg, size_t len, + char *call_type_p, char *caller_p) { - unsigned long sp = swap_get_stack_ptr(regs) - len; - - sp = PTR_ALIGN(sp, sizeof(unsigned long)); - if (copy_to_user((void __user *)sp, buf, len)) - return -EIO; - swap_set_stack_ptr(regs, sp); + if ((call_type_p < user_msg) || (call_type_p > user_msg + len) || + (caller_p < user_msg) || (caller_p > user_msg + len)) + return -EINVAL; return 0; } -static inline void __save_uregs(struct uretprobe_instance *ri, - struct pt_regs *regs) -{ - struct us_priv *priv = (struct us_priv *)ri->data; - memcpy(ri->data, regs, sizeof(*regs)); - priv->arg0 = swap_get_arg(regs, 0); - priv->arg1 = swap_get_arg(regs, 1); - priv->raddr = swap_get_ret_addr(regs); -} -static inline void __restore_uregs(struct uretprobe_instance *ri, - struct pt_regs *regs) -{ - struct us_priv *priv = (struct us_priv *)ri->data; - - memcpy(regs, ri->data, sizeof(*regs)); - swap_set_arg(regs, 0, priv->arg0); - swap_set_arg(regs, 1, priv->arg1); - swap_set_ret_addr(regs, priv->raddr); -#ifndef CONFIG_ARM - /* need to do it only on x86 */ - regs->EREG(ip) -= 1; -#endif /* !CONFIG_ARM */ - /* we have just restored the registers => no need to do it in - * trampoline_uprobe_handler */ - ri->ret_addr = NULL; -} -static inline void print_regs(const char *prefix, struct pt_regs *regs, - 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] %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, - 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] %s (%d) %s addr(%08lx), " - "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n", - current->comm, current->tgid, current->pid, - 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)); -#endif /* CONFIG_ARM */ -} - -static inline unsigned long __get_r_debug_off(struct vm_area_struct *linker_vma) -{ - unsigned long start_addr; - unsigned long offset = preload_debugfs_r_debug_offset(); - - if (linker_vma == NULL) - return 0; - - start_addr = linker_vma->vm_start; - - return (offset ? start_addr + offset : 0); -} - -static struct vm_area_struct *__get_linker_vma(struct task_struct *task) +static unsigned long __do_preload_entry(struct uretprobe_instance *ri, + struct pt_regs *regs, + struct hd_t *hd) { - struct vm_area_struct *vma = NULL; - struct bin_info *ld_info; + struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe); + unsigned long offset = ip->desc->info.pl_i.handler; + unsigned long vaddr = 0; + unsigned long base; + unsigned long disable_addr; + unsigned long caddr; + struct vm_area_struct *cvma; + enum preload_call_type ct; - ld_info = preload_storage_get_linker_info(); - if (ld_info == NULL) { - printk(PRELOAD_PREFIX "Cannot get linker info [%u %u %s]!\n", - task->tgid, task->pid, task->comm); - return NULL; - } + base = lpd_get_handlers_base(hd); + if (base == 0) + return 0; /* handlers isn't mapped */ - for (vma = task->mm->mmap; vma; vma = vma->vm_next) { - if (vma->vm_file && vma->vm_flags & VM_EXEC - && vma->vm_file->f_dentry == ld_info->dentry) { - preload_storage_put_linker_info(ld_info); - return vma; + /* jump to preloaded handler */ + vaddr = base + offset; + if (vaddr) { + caddr = get_regs_ret_func(regs); + cvma = __get_vma_by_addr(current, caddr); + ct = pc_call_type(ip, (void *)caddr); + disable_addr = __is_probe_non_block(ip) ? ip->orig_addr : 0; + + /* jump only if caller is instumented and it is not a system lib - + * this leads to some errors */ + if (cvma != NULL && cvma->vm_file != NULL && + cvma->vm_file->f_dentry != NULL) { + + struct dentry *dentry = cvma->vm_file->f_dentry; + struct pd_t *pd = lpd_get_parent_pd(hd); + + if (!pc_check_dentry_is_ignored(dentry) && + __check_flag_and_call_type(ip, ct) && + !__is_handlers_call(cvma, pd)) { + + bool drop = __should_drop(ip, ct); + if (pt_set_data(current, caddr, + ct, disable_addr, + drop) != 0) + printk(PRELOAD_PREFIX "Error! Failed " + "to set caller 0x%lx for " + "%d/%d\n", caddr, + current->tgid, + current->pid); + /* args are not changed */ + loader_module_prepare_ujump(ri, regs, vaddr); + if (disable_addr == 0) + pt_set_flags(current, + HANDLER_RUNNING); + } } } - preload_storage_put_linker_info(ld_info); - return NULL; + return vaddr; } -static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task, - unsigned long caller_addr) +static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs) { - struct vm_area_struct *vma = NULL; - - if (task->mm == NULL) - return NULL; - vma = find_vma_intersection(task->mm, caller_addr, caller_addr + 1); + struct pd_t *pd = __get_process_data(ri->rp); + struct hd_t *hd; + unsigned long old_pc = swap_get_instr_ptr(regs); + unsigned long flags = pt_get_flags(current); + struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe); + unsigned long vaddr = 0; - return vma; -} + if (handler_dentry == NULL) + goto out_set_orig; + if ((flags & HANDLER_RUNNING) || + pt_check_disabled_probe(current, ip->orig_addr)) + goto out_set_orig; + hd = lpd_get_hd(pd, handler_dentry); + if (hd == NULL) + goto out_set_orig; + if ((flags & HANDLER_RUNNING) || + pt_check_disabled_probe(current, ip->orig_addr)) + goto out_set_orig; + if (lpd_get_state(hd) == NOT_LOADED || + lpd_get_state(hd) == FAILED) + vaddr = loader_not_loaded_entry(ri, regs, pd, hd); + else if (lpd_get_state(hd) == LOADED) + vaddr =__do_preload_entry(ri, regs, hd); +out_set_orig: + loader_set_priv_origin(ri, vaddr); + /* PC change check */ + return old_pc != swap_get_instr_ptr(regs); +} +static void __do_preload_ret(struct uretprobe_instance *ri, struct hd_t *hd) +{ + struct sspt_ip *ip = container_of(ri->rp, struct sspt_ip, retprobe); + unsigned long flags = pt_get_flags(current); + unsigned long offset = ip->desc->info.pl_i.handler; + unsigned long vaddr = 0; + if ((flags & HANDLER_RUNNING) || + pt_check_disabled_probe(current, ip->orig_addr)) { + bool non_blk_probe = __is_probe_non_block(ip); + + /* drop the flag if the handler has completed */ + vaddr = lpd_get_handlers_base(hd) + offset; + if (vaddr && (loader_get_priv_origin(ri) == vaddr)) { + if (pt_put_data(current) != 0) + printk(PRELOAD_PREFIX "Error! Failed to put " + "caller slot for %d/%d\n", current->tgid, + current->pid); + if (!non_blk_probe) { + flags &= ~HANDLER_RUNNING; + pt_set_flags(current, flags); + } + } + } +} -static bool __is_proc_mmap_mappable(struct task_struct *task) +static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs) { - struct vm_area_struct *linker_vma = __get_linker_vma(task); - struct sspt_proc *proc; - unsigned long r_debug_addr; - unsigned int state; - enum { r_state_offset = sizeof(int) + sizeof(void *) + sizeof(long) }; + struct pd_t *pd = __get_process_data(ri->rp); + struct hd_t *hd; - if (linker_vma == NULL) - return false; + if (handler_dentry == NULL) + return 0; - r_debug_addr = __get_r_debug_off(linker_vma); - if (r_debug_addr == 0) - return false; + hd = lpd_get_hd(pd, handler_dentry); + if (hd == NULL) + return 0; - r_debug_addr += r_state_offset; - proc = sspt_proc_get_by_task(task); - if (proc) { - proc->r_state_addr = r_debug_addr; - sspt_proc_put(proc); + switch (lpd_get_state(hd)) { + case NOT_LOADED: + /* loader has not yet been mapped... just ignore */ + break; + case LOADING: + loader_loading_ret(ri, regs, pd, hd); + break; + case LOADED: + __do_preload_ret(ri, hd); + break; + case FAILED: + loader_failed_ret(ri, regs, pd, hd); + break; + case ERROR: + default: + break; } - if (get_user(state, (unsigned long *)r_debug_addr)) - return false; - - return !state; + return 0; } -static bool __should_we_preload_handlers(struct task_struct *task, - struct pt_regs *regs) -{ - unsigned long caller_addr = get_regs_ret_func(regs); - struct vm_area_struct *cvma = __get_vma_by_addr(current, caller_addr); - - if (!__is_proc_mmap_mappable(task) || - ((cvma != NULL) && (cvma->vm_file != NULL) && - (cvma->vm_file->f_path.dentry != NULL) && - preload_control_check_dentry_is_ignored(cvma->vm_file->f_path.dentry))) - return false; - return true; -} +static void __write_data_to_msg(char *msg, size_t len, + unsigned long call_type_off, + unsigned long caller_off, + unsigned long caller_addr) +{ + unsigned char call_type = 0; + unsigned long caller = 0; + int ret; + if (caller_addr != 0) { + caller = caller_addr; + call_type = + pc_call_type_always_inst((void *)caller); + } else { + ret = pt_get_caller(current, &caller); + if (ret != 0) { + caller = 0xbadbeef; + printk(PRELOAD_PREFIX "Error! Cannot get caller address" + " for %d/%d\n", current->tgid, current->pid); + } -struct mmap_priv { - struct dentry *dentry; -}; + ret = pt_get_call_type(current, &call_type); + if (ret != 0) { + call_type = 0xff; + printk(PRELOAD_PREFIX "Error! Cannot get call type for " + "%d/%d\n", current->tgid, current->pid); + } + } -static inline bool check_prot(unsigned long prot) -{ - return !!((prot & PROT_READ) && (prot & PROT_EXEC)); + /* Using the same types as in the library. */ + *(uint32_t *)(msg + call_type_off) = (uint32_t)call_type; + *(uintptr_t *)(msg + caller_off) = (uintptr_t)caller; } -static int mmap_entry_handler(struct kretprobe_instance *ri, - struct pt_regs *regs) +static int write_msg_handler(struct uprobe *p, struct pt_regs *regs) { - 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 pd_t *pd; - struct hd_t *hd; - struct sspt_proc *proc; + char *user_buf; + char *buf; + char *caller_p; + char *call_type_p; + size_t len; + unsigned long caller_offset; + unsigned long call_type_offset; + unsigned long caller_addr; + int ret; - priv->dentry = NULL; - if (!check_prot(prot)) - return 0; + /* FIXME: swap_get_uarg uses get_user(), it might sleep */ + user_buf = (char *)swap_get_uarg(regs, 0); + len = swap_get_uarg(regs, 1); + call_type_p = (char *)swap_get_uarg(regs, 2); + caller_p = (char *)swap_get_uarg(regs, 3); + caller_addr = swap_get_uarg(regs, 4); - if (!file) + ret = __msg_sanitization(user_buf, len, call_type_p, caller_p); + if (ret != 0) { + printk(PRELOAD_PREFIX "Invalid message pointers!\n"); return 0; + } - dentry = file->f_dentry; - if (dentry == NULL) + ret = pt_get_drop(current); + if (ret > 0) return 0; - loader_dentry = preload_debugfs_get_loader_dentry(); - if (dentry == loader_dentry) { - priv->dentry = loader_dentry; + buf = kmalloc(len, GFP_ATOMIC); + if (buf == NULL) { + printk(PRELOAD_PREFIX "No mem for buffer! Size = %d\n", len); return 0; } - proc = sspt_proc_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; + ret = read_proc_vm_atomic(current, (unsigned long)user_buf, buf, len); + if (ret < 0) { + printk(PRELOAD_PREFIX "Cannot copy data from userspace! Size = " + "%d ptr 0x%lx ret %d\n", len, + (unsigned long)user_buf, ret); + goto write_msg_fail; } - hd = preload_pd_get_hd(pd, dentry); - if (hd != NULL) - priv->dentry = preload_pd_get_dentry(hd); + /* Evaluating call_type and caller offset in message: + * data offset = data pointer - beginning of the message. + */ + call_type_offset = (unsigned long)(call_type_p - user_buf); + caller_offset = (unsigned long)(caller_p - user_buf); - return 0; -} + __write_data_to_msg(buf, len, call_type_offset, caller_offset, + caller_addr); -static int mmap_ret_handler(struct kretprobe_instance *ri, - struct pt_regs *regs) -{ - 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; - unsigned long vaddr; + ret = swap_msg_raw(buf, len); + if (ret != len) + printk(PRELOAD_PREFIX "Error writing probe lib message\n"); - if (!task->mm) - return 0; +write_msg_fail: + kfree(buf); - if (priv->dentry == NULL) - return 0; + return 0; +} - vaddr = (unsigned long)regs_return_value(regs); - if (IS_ERR_VALUE(vaddr)) - return 0; - proc = sspt_proc_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; - } - loader_dentry = preload_debugfs_get_loader_dentry(); - if (priv->dentry == loader_dentry) - preload_pd_set_loader_base(pd, vaddr); - hd = preload_pd_get_hd(pd, priv->dentry); - if (hd != NULL) - preload_pd_set_handlers_base(hd, vaddr); - return 0; -} -static struct kretprobe mmap_rp = { - .kp.symbol_name = "do_mmap_pgoff", - .data_size = sizeof(struct mmap_priv), - .entry_handler = mmap_entry_handler, - .handler = mmap_ret_handler -}; -static void preload_start_cb(void) +static int get_caller_handler(struct uprobe *p, struct pt_regs *regs) { - int res; + unsigned long caller; + int ret; - res = swap_register_kretprobe(&mmap_rp); - if (res != 0) - printk(KERN_ERR PRELOAD_PREFIX "Registering do_mmap_pgoff probe failed\n"); -} + ret = pt_get_caller(current, &caller); + if (ret != 0) { + caller = 0xbadbeef; + printk(PRELOAD_PREFIX "Error! Cannot get caller address for " + "%d/%d\n", current->tgid, current->pid); + } -static void preload_stop_cb(void) -{ - swap_unregister_kretprobe(&mmap_rp); + swap_put_uarg(regs, 0, caller); + + return 0; } -static unsigned long __not_loaded_entry(struct uretprobe_instance *ri, - struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd) +static int get_call_type_handler(struct uprobe *p, struct pt_regs *regs) { - char __user *path = NULL; - unsigned long vaddr = 0; - unsigned long base; + unsigned char call_type; + int ret; - /* if linker is still doing its work, we do nothing */ - if (!__should_we_preload_handlers(current, regs)) - return 0; + ret = pt_get_call_type(current, &call_type); + if (ret != 0) { + call_type = 0xff; + printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n", + current->tgid, current->pid); + } - base = preload_pd_get_loader_base(pd); - if (base == 0) - return 0; /* loader isn't mapped */ + swap_put_uarg(regs, 0, call_type); - /* jump to loader code if ready */ - vaddr = base + preload_debugfs_get_loader_offset(); - if (vaddr) { - /* save original regs state */ - __save_uregs(ri, regs); - print_regs("ORIG", regs, ri, hd); + return 0; +} - 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)*/); - swap_set_arg(regs, 1, 2 /* RTLD_NOW */); - /* do the jump to dlopen */ - __prepare_ujump(ri, regs, vaddr); - /* set new state */ - preload_pd_set_state(hd, LOADING); - } - return vaddr; -} -static void __loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd) +struct dentry *get_dentry(const char *filepath) { - struct us_priv *priv = (struct us_priv *)ri->data; - unsigned long vaddr = 0; + struct path path; + struct dentry *dentry = NULL; - /* 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); - } + if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) { + dentry = dget(path.dentry); + path_put(&path); } + + return dentry; } -static void __failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd) +void put_dentry(struct dentry *dentry) { - if (preload_pd_get_attempts(hd)) - preload_pd_set_state(hd, NOT_LOADED); + dput(dentry); } +int pm_get_caller_init(struct sspt_ip *ip) +{ + struct uprobe *up = &ip->uprobe; + up->pre_handler = get_caller_handler; -unsigned long preload_not_loaded_entry(struct uretprobe_instance *ri, - struct pt_regs *regs, struct pd_t *pd, - struct hd_t *hd) -{ - return __not_loaded_entry(ri, regs, pd, hd); + return 0; } -void preload_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd) +void pm_get_caller_exit(struct sspt_ip *ip) { - __loading_ret(ri, regs, pd, hd); } -void preload_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd) +int pm_get_call_type_init(struct sspt_ip *ip) { - __failed_ret(ri, regs, pd, hd); + struct uprobe *up = &ip->uprobe; + + up->pre_handler = get_call_type_handler; + + return 0; } -void preload_module_prepare_ujump(struct uretprobe_instance *ri, - struct pt_regs *regs, unsigned long addr) +void pm_get_call_type_exit(struct sspt_ip *ip) { - __prepare_ujump(ri, regs, addr); } -void preload_set_rp_data_size(struct uretprobe *rp) +int pm_write_msg_init(struct sspt_ip *ip) { - rp->data_size = sizeof(struct us_priv); + struct uprobe *up = &ip->uprobe; + + up->pre_handler = write_msg_handler; + + return 0; } -void preload_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr) +void pm_write_msg_exit(struct sspt_ip *ip) { - struct us_priv *priv = (struct us_priv *)ri->data; - - priv->origin = addr; } -unsigned long preload_get_priv_origin(struct uretprobe_instance *ri) +int pm_set_handler(char *path) { - struct us_priv *priv = (struct us_priv *)ri->data; + struct dentry *dentry; + int ret; - return priv->origin; -} + if (handler_dentry != NULL) + put_dentry(handler_dentry); + dentry = get_dentry(path); -int preload_set(void) -{ - if (preload_module_is_running()) - return -EBUSY; + if (dentry == NULL) { + printk(KERN_WARNING PRELOAD_PREFIX "Error! Cannot get handler %s\n", + path); + return -EINVAL; + } + + ret = loader_add_handler(path); + if (ret != 0) + return ret; + + handler_dentry = dentry; return 0; } -void preload_unset(void) + +int pm_uprobe_init(struct sspt_ip *ip) { - swap_unregister_kretprobe(&mmap_rp); - /*module_put(THIS_MODULE);*/ - preload_module_set_not_ready(); + struct uretprobe *rp = &ip->retprobe; + rp->entry_handler = preload_us_entry; + rp->handler = preload_us_ret; + /* FIXME actually additional data_size is needed only when we jump + * to dlopen */ + loader_set_rp_data_size(rp); + + return 0; } +void pm_uprobe_exit(struct sspt_ip *ip) +{ +} -static int preload_module_init(void) +static int pm_init(void) { int ret; - ret = preload_debugfs_init(); + ret = pd_init(); if (ret) goto out_err; - ret = preload_storage_init(); - if (ret) - goto exit_debugfs; - - ret = preload_pd_init(); - if (ret) - goto exit_storage; - - /* TODO do not forget to remove set (it is just for debugging) */ - ret = preload_set(); - if (ret) - goto exit_pd; - - ret = preload_control_init(); + ret = pc_init(); if (ret) - goto exit_set; + goto control_init_fail; - ret = preload_threads_init(); + ret = pt_init(); if (ret) - goto exit_control; + goto threads_init_fail; ret = register_preload_probes(); if (ret) - goto exit_threads; - - __preload_cbs_start_h = us_manager_reg_cb(START_CB, preload_start_cb); - if (__preload_cbs_start_h < 0) - goto exit_start_cb; - - __preload_cbs_stop_h = us_manager_reg_cb(STOP_CB, preload_stop_cb); - if (__preload_cbs_stop_h < 0) - goto exit_stop_cb; + goto probes_register_fail; return 0; -exit_stop_cb: - us_manager_unreg_cb(__preload_cbs_start_h); - -exit_start_cb: - unregister_preload_probes(); - -exit_threads: - preload_threads_exit(); +probes_register_fail: + pt_exit(); -exit_control: - preload_control_exit(); +threads_init_fail: + pc_exit(); -exit_set: - preload_unset(); - -exit_pd: - preload_pd_uninit(); - -exit_storage: - preload_storage_exit(); - -exit_debugfs: - preload_debugfs_exit(); +control_init_fail: + pd_exit(); out_err: return ret; } -static void preload_module_exit(void) +static void pm_exit(void) { - int balance; - - us_manager_unreg_cb(__preload_cbs_start_h); - us_manager_unreg_cb(__preload_cbs_stop_h); unregister_preload_probes(); - preload_threads_exit(); - preload_control_exit(); - preload_unset(); - preload_pd_uninit(); - preload_storage_exit(); - preload_debugfs_exit(); - - balance = atomic_read(&dentry_balance); - atomic_set(&dentry_balance, 0); + pt_exit(); + pc_exit(); + pd_exit(); - WARN(balance, "Bad GET/PUT dentry balance: %d\n", balance); + if (handler_dentry != NULL) + put_dentry(handler_dentry); } -SWAP_LIGHT_INIT_MODULE(NULL, preload_module_init, preload_module_exit, - NULL, NULL); - +SWAP_LIGHT_INIT_MODULE(NULL, pm_init, pm_exit, NULL, NULL); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SWAP Preload Module"); -MODULE_AUTHOR("Vasiliy Ulyanov " - "Alexander Aksenov "); +MODULE_AUTHOR("Alexander Aksenov "); diff --git a/preload/preload_module.h b/preload/preload_module.h index 7b0ce2d..b3f5c78 100644 --- a/preload/preload_module.h +++ b/preload/preload_module.h @@ -1,41 +1,21 @@ #ifndef __PRELOAD_MODULE_H__ #define __PRELOAD_MODULE_H__ -#include - +struct sspt_ip; struct dentry; -struct pd_t; -struct hd_t; -struct uretprobe; -struct uretprobe_instance; - -bool preload_module_is_ready(void); -bool preload_module_is_running(void); -bool preload_module_is_not_ready(void); -void preload_module_set_ready(void); -void preload_module_set_running(void); -void preload_module_set_not_ready(void); +int pm_uprobe_init(struct sspt_ip *ip); +void pm_uprobe_exit(struct sspt_ip *ip); -void preload_module_set_handler_dentry(struct dentry *dentry); +int pm_get_caller_init(struct sspt_ip *ip); +void pm_get_caller_exit(struct sspt_ip *ip); +int pm_get_call_type_init(struct sspt_ip *ip); +void pm_get_call_type_exit(struct sspt_ip *ip); +int pm_write_msg_init(struct sspt_ip *ip); +void pm_write_msg_exit(struct sspt_ip *ip); +int pm_set_handler(char *path); struct dentry *get_dentry(const char *filepath); void put_dentry(struct dentry *dentry); -void preload_module_prepare_ujump(struct uretprobe_instance *ri, - struct pt_regs *regs, unsigned long addr); - -unsigned long preload_not_loaded_entry(struct uretprobe_instance *ri, - struct pt_regs *regs, struct pd_t *pd, - struct hd_t *hd); -void preload_loading_ret(struct uretprobe_instance *ri, struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd); -void preload_failed_ret(struct uretprobe_instance *ri, struct pt_regs *regs, - struct pd_t *pd, struct hd_t *hd); - -void preload_set_rp_data_size(struct uretprobe *rp); -void preload_set_priv_origin(struct uretprobe_instance *ri, unsigned long addr); -unsigned long preload_get_priv_origin(struct uretprobe_instance *ri); - - #endif /* __PRELOAD_MODULE_H__ */ diff --git a/preload/preload_pd.h b/preload/preload_pd.h deleted file mode 100644 index 9a92b42..0000000 --- a/preload/preload_pd.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __PRELOAD_PD_H__ -#define __PRELOAD_PD_H__ - -struct pd_t; -struct hd_t; -struct sspt_proc; -struct dentry; -struct list_head; - -/* process preload states */ -enum ps_t { - NOT_LOADED, - LOADING, - LOADED, - FAILED, - ERROR -}; - -struct pd_t *preload_pd_get(struct sspt_proc *proc); -unsigned long preload_pd_get_loader_base(struct pd_t *pd); -void preload_pd_set_loader_base(struct pd_t *pd, unsigned long vaddr); - -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); - - -#endif /* __PRELOAD_PD_H__*/ diff --git a/preload/preload_probe.c b/preload/preload_probe.c index 4a44139..b15466d 100644 --- a/preload/preload_probe.c +++ b/preload/preload_probe.c @@ -31,10 +31,6 @@ #include "preload_probe.h" #include "preload.h" #include "preload_module.h" -#include "preload_handlers.h" -#include "preload_debugfs.h" - -static unsigned long long probes_count = 0; static int preload_info_copy(struct probe_info *dest, const struct probe_info *source) @@ -53,80 +49,26 @@ static struct uprobe *preload_get_uprobe(struct sspt_ip *ip) return &ip->retprobe.up; } -/* We count all preload probes to know current state of the preload module: - * if there are registered probes, than it is currently running, if there is no - * probes, module is just ready to be used. - * - * If there was no registered probes and now they're appeared, change state to - * 'running'. - */ -static inline void inc_probes(void) -{ - if (probes_count == 0) - preload_module_set_running(); - - probes_count++; -} - -/* If there were probes, but now there's no of them, change state to 'ready'. - */ -static inline void dec_probes(void) -{ - if (unlikely(probes_count == 0)) - printk(KERN_ERR PRELOAD_PREFIX "Trying to remove probe when there is no one!\n"); - - probes_count--; - if (probes_count == 0) - preload_module_set_ready(); -} - -/* Checks if preload can be in 'ready' state. It is so, if loader's dentry and - * offset are specified. - */ -static inline bool can_be_ready(void) -{ - struct dentry *dentry = preload_debugfs_get_loader_dentry(); - unsigned long offset = preload_debugfs_get_loader_offset(); - - if (dentry != NULL && offset != 0) - return true; - - return false; -} - /* Registers probe if preload is 'running' or 'ready'. */ static int preload_register_probe(struct sspt_ip *ip) { - if (preload_module_is_not_ready()) { - if (can_be_ready()) { - preload_module_set_ready(); - } else { - printk(PRELOAD_PREFIX "Module is not initialized!\n"); - return -EINVAL; - } - } - - inc_probes(); - return swap_register_uretprobe(&ip->retprobe); } static void preload_unregister_probe(struct sspt_ip *ip, int disarm) { __swap_unregister_uretprobe(&ip->retprobe, disarm); - - dec_probes(); } static void preload_init(struct sspt_ip *ip) { - ph_uprobe_init(ip); + pm_uprobe_init(ip); } static void preload_uninit(struct sspt_ip *ip) { - ph_uprobe_exit(ip); + pm_uprobe_exit(ip); preload_info_cleanup(&ip->desc->info); } @@ -170,12 +112,12 @@ static void get_caller_unregister_probe(struct sspt_ip *ip, int disarm) static void get_caller_init(struct sspt_ip *ip) { - ph_get_caller_init(ip); + pm_get_caller_init(ip); } static void get_caller_uninit(struct sspt_ip *ip) { - ph_get_caller_exit(ip); + pm_get_caller_exit(ip); get_caller_info_cleanup(&ip->desc->info); } @@ -192,12 +134,12 @@ static struct probe_iface get_caller_iface = { static void get_call_type_init(struct sspt_ip *ip) { - ph_get_call_type_init(ip); + pm_get_call_type_init(ip); } static void get_call_type_uninit(struct sspt_ip *ip) { - ph_get_call_type_exit(ip); + pm_get_call_type_exit(ip); get_caller_info_cleanup(&ip->desc->info); } @@ -214,7 +156,7 @@ static struct probe_iface get_call_type_iface = { static void write_msg_init(struct sspt_ip *ip) { - ph_write_msg_init(ip); + pm_write_msg_init(ip); } static int write_msg_reg(struct sspt_ip *ip) @@ -224,7 +166,7 @@ static int write_msg_reg(struct sspt_ip *ip) static void write_msg_uninit(struct sspt_ip *ip) { - ph_write_msg_exit(ip); + pm_write_msg_exit(ip); get_caller_info_cleanup(&ip->desc->info); } diff --git a/preload/preload_probe.h b/preload/preload_probe.h index c859afd..29ac33a 100644 --- a/preload/preload_probe.h +++ b/preload/preload_probe.h @@ -22,8 +22,8 @@ * */ -#ifndef __PRELOAD_PROBE_H__ -#define __PRELOAD_PROBE_H__ +#ifndef __PRELOAD_HANDLERS_PROBE_H__ +#define __PRELOAD_HANDLERS_PROBE_H__ /* Probe flags description: * @@ -64,4 +64,4 @@ struct write_msg_info { int register_preload_probes(void); void unregister_preload_probes(void); -#endif /* __URETPROBE_H__ */ +#endif /* __PRELOAD_HANDLERS_PROBE_H__ */ diff --git a/preload/preload_storage.h b/preload/preload_storage.h deleted file mode 100644 index 1fbd3a7..0000000 --- a/preload/preload_storage.h +++ /dev/null @@ -1,36 +0,0 @@ -#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); - -int preload_storage_init(void); -void preload_storage_exit(void); - -#endif /* __PRELOAD_HANDLERS_H__ */ diff --git a/preload/preload_threads.c b/preload/preload_threads.c index 12b74ef..675fc18 100644 --- a/preload/preload_threads.c +++ b/preload/preload_threads.c @@ -8,7 +8,6 @@ #include #include "preload.h" #include "preload_threads.h" -#include "preload_debugfs.h" struct preload_td { struct list_head slots; @@ -55,13 +54,12 @@ static inline struct preload_td *get_preload_td(struct task_struct *task) return (struct preload_td *)swap_ktd(&preload_ktd, task); } -unsigned long get_preload_flags(struct task_struct *task) +unsigned long pt_get_flags(struct task_struct *task) { return get_preload_td(task)->flags; } -void set_preload_flags(struct task_struct *task, - unsigned long flags) +void pt_set_flags(struct task_struct *task, unsigned long flags) { get_preload_td(task)->flags = flags; } @@ -178,9 +176,8 @@ static inline struct thread_slot *__get_task_slot(struct task_struct *task) -int preload_threads_set_data(struct task_struct *task, unsigned long caller, - unsigned char call_type, - unsigned long disable_addr, bool drop) +int pt_set_data(struct task_struct *task, unsigned long caller, + unsigned char call_type, unsigned long disable_addr, bool drop) { struct preload_td *td = get_preload_td(task); struct thread_slot *slot; @@ -206,7 +203,7 @@ set_data_done: return ret; } -int preload_threads_get_caller(struct task_struct *task, unsigned long *caller) +int pt_get_caller(struct task_struct *task, unsigned long *caller) { struct thread_slot *slot; int ret = 0; @@ -224,7 +221,7 @@ get_caller_done: return ret; } -int preload_threads_get_call_type(struct task_struct *task, +int pt_get_call_type(struct task_struct *task, unsigned char *call_type) { struct thread_slot *slot; @@ -243,7 +240,7 @@ get_call_type_done: return ret; } -int preload_threads_get_drop(struct task_struct *task) +int pt_get_drop(struct task_struct *task) { struct thread_slot *slot; int ret = 0; @@ -261,8 +258,7 @@ get_drop_done: return ret; } -bool preload_threads_check_disabled_probe(struct task_struct *task, - unsigned long addr) +bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr) { struct thread_slot *slot; bool ret = false; @@ -274,7 +270,7 @@ bool preload_threads_check_disabled_probe(struct task_struct *task, return ret; } -void preload_threads_enable_probe(struct task_struct *task, unsigned long addr) +void pt_enable_probe(struct task_struct *task, unsigned long addr) { struct thread_slot *slot; struct disabled_addr *da; @@ -293,7 +289,7 @@ enable_probe_failed: return; /* make gcc happy: cannot place label right before '}' */ } -int preload_threads_put_data(struct task_struct *task) +int pt_put_data(struct task_struct *task) { struct thread_slot *slot; int ret = 0; @@ -309,12 +305,12 @@ put_data_done: return ret; } -int preload_threads_init(void) +int pt_init(void) { return swap_ktd_reg(&preload_ktd); } -void preload_threads_exit(void) +void pt_exit(void) { swap_ktd_unreg(&preload_ktd); } diff --git a/preload/preload_threads.h b/preload/preload_threads.h index a82c0e6..409320a 100644 --- a/preload/preload_threads.h +++ b/preload/preload_threads.h @@ -1,24 +1,21 @@ -#ifndef __PRELOAD_THREADS_H__ -#define __PRELOAD_THREADS_H__ +#ifndef __PRELOAD_HANDLERS_THREADS_H__ +#define __PRELOAD_HANLDERS_THREADS_H__ struct task_struct; -unsigned long get_preload_flags(struct task_struct *task); -void set_preload_flags(struct task_struct *task, - unsigned long flags); +unsigned long pt_get_flags(struct task_struct *task); +void pt_set_flags(struct task_struct *task, unsigned long flags); -int preload_threads_set_data(struct task_struct *task, unsigned long caller, - unsigned char call_type, - unsigned long disable_addr, bool drop); -int preload_threads_get_caller(struct task_struct *task, unsigned long *caller); -int preload_threads_get_call_type(struct task_struct *task, - unsigned char *call_type); -int preload_threads_get_drop(struct task_struct *task); -bool preload_threads_check_disabled_probe(struct task_struct *task, - unsigned long addr); -void preload_threads_enable_probe(struct task_struct *task, unsigned long addr); -int preload_threads_put_data(struct task_struct *task); -int preload_threads_init(void); -void preload_threads_exit(void); +int pt_set_data(struct task_struct *task, unsigned long caller, + unsigned char call_type, unsigned long disable_addr, + bool drop); +int pt_get_caller(struct task_struct *task, unsigned long *caller); +int pt_get_call_type(struct task_struct *task, unsigned char *call_type); +int pt_get_drop(struct task_struct *task); +bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr); +void pt_enable_probe(struct task_struct *task, unsigned long addr); +int pt_put_data(struct task_struct *task); +int pt_init(void); +void pt_exit(void); -#endif /* __PRELOAD_THREADS_H__ */ +#endif /* __PRELOAD_HANDLERS_THREADS_H__ */ -- 2.7.4