uprobe/ \
us_manager/ \
ks_features/ \
+ loader/ \
sampler/ \
energy/ \
parser/ \
--- /dev/null
+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
--- /dev/null
+#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__ */
--- /dev/null
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+
+#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();
+}
--- /dev/null
+#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__ */
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/limits.h>
+#include <asm/uaccess.h>
+#include <master/swap_debugfs.h>
+#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();
+}
--- /dev/null
+#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__ */
--- /dev/null
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/mman.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <kprobe/swap_kprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/callbacks.h>
+#include <writer/kernel_operations.h>
+#include <master/swap_initializer.h>
+#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 <v.ulyanov@samsung.com>"
+ "Alexander Aksenov <a.aksenov@samsung.com>");
--- /dev/null
+#ifndef __LOADER_MODULE_H__
+#define __LOADER_MODULE_H__
+
+#include <linux/types.h>
+
+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__ */
#include <linux/list.h>
#include <us_manager/us_manager_common.h>
#include <us_manager/sspt/sspt_proc.h>
-#include "preload_pd.h"
-#include "preload_threads.h"
-#include "preload_debugfs.h"
-#include "preload_storage.h"
-#include "preload.h"
+#include "loader_pd.h"
+#include "loader_debugfs.h"
+#include "loader_storage.h"
+#include "loader.h"
struct pd_t {
unsigned long loader_base;
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;
}
/* 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;
}
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) {
size_t len;
int ret = 0;
- handlers = preload_storage_get_handlers();
+ handlers = ls_get_handlers();
if (handlers == NULL)
return -EINVAL;
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;
}
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 */
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;
}
__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;
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);
-void *preload_pd_get_handle(struct hd_t *hd)
+void *lpd_get_handle(struct hd_t *hd)
{
if (hd == NULL)
return NULL;
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;
}
__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;
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;
}
__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;
return NULL;
}
+EXPORT_SYMBOL_GPL(lpd_get_hd);
static struct pd_t *do_create_pd(struct task_struct *task)
{
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;
}
.priv_destroy = pd_destroy
};
-int preload_pd_init(void)
+int lpd_init(void)
{
int ret;
return ret;
}
-void preload_pd_uninit(void)
+void lpd_uninit(void)
{
sspt_proc_cb_set(NULL);
--- /dev/null
+#ifndef __LOADER_PD_H__
+#define __LOADER_PD_H__
+
+#include <loader/loader.h>
+
+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__*/
#include <linux/fs.h>
#include <linux/list.h>
#include <ks_features/ks_map.h>
-#include "preload.h"
-#include "preload_module.h"
-#include "preload_storage.h"
-#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)
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);
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';
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;
}
__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;
-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();
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();
}
--- /dev/null
+#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__ */
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
/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
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
#include <us_manager/sspt/sspt_ip.h>
#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;
/* 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;
}
-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;
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;
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;
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;
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);
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__ */
#include <asm/uaccess.h>
#include <master/swap_debugfs.h>
#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;
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 =
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__,
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__,
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__,
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__,
.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;
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;
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;
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;
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;
}
return ret;
}
-void preload_debugfs_exit(void)
+void pd_exit(void)
{
if (preload_root)
debugfs_remove_recursive(preload_root);
ignored_add = NULL;
ignored_remove = NULL;
preload_root = NULL;
-
- preload_module_set_not_ready();
- clean_loader_info();
}
-#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__ */
+++ /dev/null
-#include <linux/slab.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <writer/kernel_operations.h>
-#include <writer/swap_msg.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-#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)
-{
-}
+++ /dev/null
-#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__ */
-#include <linux/module.h>
-#include <linux/dcache.h>
+#include <linux/slab.h>
#include <linux/namei.h>
-#include <linux/mman.h>
-#include <linux/err.h>
-#include <linux/types.h>
-#include <kprobe/swap_kprobes.h>
#include <kprobe/swap_kprobes_deps.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_ip.h>
-#include <us_manager/callbacks.h>
#include <writer/kernel_operations.h>
+#include <writer/swap_msg.h>
+#include <us_manager/sspt/sspt_ip.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+#include <loader/loader_pd.h>
+#include <loader/loader_module.h>
#include <master/swap_initializer.h>
#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 <v.ulyanov@samsung.com>"
- "Alexander Aksenov <a.aksenov@samsung.com>");
+MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
#ifndef __PRELOAD_MODULE_H__
#define __PRELOAD_MODULE_H__
-#include <linux/types.h>
-
+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__ */
+++ /dev/null
-#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__*/
#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)
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);
}
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);
}
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);
}
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)
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);
}
*
*/
-#ifndef __PRELOAD_PROBE_H__
-#define __PRELOAD_PROBE_H__
+#ifndef __PRELOAD_HANDLERS_PROBE_H__
+#define __PRELOAD_HANDLERS_PROBE_H__
/* Probe flags description:
*
int register_preload_probes(void);
void unregister_preload_probes(void);
-#endif /* __URETPROBE_H__ */
+#endif /* __PRELOAD_HANDLERS_PROBE_H__ */
+++ /dev/null
-#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__ */
#include <kprobe/swap_ktd.h>
#include "preload.h"
#include "preload_threads.h"
-#include "preload_debugfs.h"
struct preload_td {
struct list_head slots;
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;
}
-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;
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;
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;
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;
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;
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;
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;
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);
}
-#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__ */