-#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/limits.h>
#include <us_manager/sspt/ip.h>
-#include "preload.h"
-
+#include "pre
#include "preload_control.h"
#include "preload_probe.h"
#include "preload_module.h"
char *filename;
};
-static LIST_HEAD(target_binaries_list);
-static DEFINE_RWLOCK(target_binaries_lock);
-static int target_binaries_cnt = 0;
+struct list_desc {
+ struct list_head list;
+ rwlock_t lock;
+ int cnt;
+};
+
+static struct list_desc target = {
+ .list = LIST_HEAD_INIT(target.list),
+ .lock = __RW_LOCK_UNLOCKED(&target.lock),
+ .cnt = 0
+};
+
+static struct list_desc ignored = {
+ .list = LIST_HEAD_INIT(ignored.list),
+ .lock = __RW_LOCK_UNLOCKED(&ignored.lock),
+ .cnt = 0
+};
static inline struct task_struct *__get_task_struct(void)
{
return current;
}
-static struct bin_desc *__alloc_target_binary(struct dentry *dentry,
- char *name, int namelen)
+static struct bin_desc *__alloc_binary(struct dentry *dentry, char *name,
+ int namelen)
{
struct bin_desc *p = NULL;
return NULL;
}
-static void __free_target_binary(struct bin_desc *p)
+static void __free_binary(struct bin_desc *p)
{
kfree(p->filename);
kfree(p);
}
-static void __free_target_binaries(void)
+static void __free_binaries(struct list_desc *tl)
{
struct bin_desc *p, *n;
struct list_head rm_head;
INIT_LIST_HEAD(&rm_head);
- write_lock(&target_binaries_lock);
- list_for_each_entry_safe(p, n, &target_binaries_list, list) {
+ write_lock(&tl->lock);
+ list_for_each_entry_safe(p, n, &tl->list, list) {
list_move(&p->list, &rm_head);
}
- target_binaries_cnt = 0;
- write_unlock(&target_binaries_lock);
+ tl->cnt = 0;
+ write_unlock(&tl->lock);
list_for_each_entry_safe(p, n, &rm_head, list) {
list_del(&p->list);
put_dentry(p->dentry);
- __free_target_binary(p);
+ __free_binary(p);
}
}
-static bool __check_dentry_already_exist(struct dentry *dentry)
+static bool __check_dentry_already_exist(struct dentry *dentry,
+ struct list_desc *tl)
{
struct bin_desc *p;
bool ret = false;
- read_lock(&target_binaries_lock);
- list_for_each_entry(p, &target_binaries_list, list) {
+ read_lock(&tl->lock);
+ list_for_each_entry(p, &tl->list, list) {
if (p->dentry == dentry) {
ret = true;
goto out;
}
}
out:
- read_unlock(&target_binaries_lock);
+ read_unlock(&tl->lock);
return ret;
}
-static int __add_target_binary(struct dentry *dentry, char *filename)
+static int __add_binary(struct dentry *dentry, char *filename,
+ struct list_desc *tl)
{
struct bin_desc *p;
size_t len;
- if (__check_dentry_already_exist(dentry)) {
+ if (__check_dentry_already_exist(dentry, tl)) {
printk(PRELOAD_PREFIX "Binary already exist\n");
return EALREADY;
}
if (len == PATH_MAX)
return -EINVAL;
- p = __alloc_target_binary(dentry, filename, len);
+ p = __alloc_binary(dentry, filename, len);
if (!p)
return -ENOMEM;
- write_lock(&target_binaries_lock);
- list_add_tail(&p->list, &target_binaries_list);
- target_binaries_cnt++;
- write_unlock(&target_binaries_lock);
+ write_lock(&tl->lock);
+ list_add_tail(&p->list, &tl->list);
+ tl->cnt++;
+ write_unlock(&tl->lock);
return 0;
}
static bool __check_if_instrumented(struct task_struct *task,
struct dentry *dentry)
{
- return __check_dentry_already_exist(dentry);
+ return __check_dentry_already_exist(dentry, &target);
}
static bool __is_instrumented(void *caller)
return __check_if_instrumented(task, caller_dentry);
}
+static unsigned int __get_names(struct list_desc *tl, char ***filenames_p)
+{
+ unsigned int i, ret = 0;
+ struct bin_desc *p;
+ char **a = NULL;
+
+ read_lock(&tl->lock);
+ if (tl->cnt == 0)
+ goto out;
+
+ a = kmalloc(sizeof(*a) * tl->cnt, GFP_KERNEL);
+ if (!a)
+ goto out;
+
+ i = 0;
+ list_for_each_entry(p, &tl->list, list) {
+ if (i >= tl->cnt)
+ break;
+ a[i++] = p->filename;
+ }
+
+ *filenames_p = a;
+ ret = i;
+out:
+ read_unlock(&tl->lock);
+ return ret;
+}
+
/* Called only form handlers. If we're there, then it is instrumented. */
enum preload_call_type preload_control_call_type_always_inst(void *caller)
if (dentry == NULL)
return -EINVAL;
- res = __add_target_binary(dentry, filename);
+ res = __add_binary(dentry, filename, &target);
if (res != 0)
put_dentry(dentry);
int preload_control_clean_instrumented_bins(void)
{
- __free_target_binaries();
+ __free_binaries(&target);
return 0;
}
-unsigned int preload_control_get_bin_names(char ***filenames_p)
+int preload_control_add_ignored_binary(char *filename)
{
- unsigned int i, ret = 0;
- struct bin_desc *p;
- char **a = NULL;
+ struct dentry *dentry = get_dentry(filename);
+ int res = 0;
- read_lock(&target_binaries_lock);
- if (target_binaries_cnt == 0)
- goto out;
+ if (dentry == NULL)
+ return -EINVAL;
- a = kmalloc(sizeof(*a) * target_binaries_cnt, GFP_KERNEL);
- if (!a)
- goto out;
+ res = __add_binary(dentry, filename, &ignored);
+ if (res != 0)
+ put_dentry(dentry);
- i = 0;
- list_for_each_entry(p, &target_binaries_list, list) {
- if (i >= target_binaries_cnt)
- break;
- a[i++] = p->filename;
- }
+ return res > 0 ? 0 : res;
+}
- *filenames_p = a;
- ret = i;
-out:
- read_unlock(&target_binaries_lock);
- return ret;
+int preload_control_clean_ignored_bins(void)
+{
+ __free_binaries(&ignored);
+
+ return 0;
}
-void preload_control_release_bin_names(char ***filenames_p)
+unsigned int preload_control_get_target_names(char ***filenames_p)
+{
+ return __get_names(&target, filenames_p);
+}
+
+void preload_control_release_target_names(char ***filenames_p)
{
kfree(*filenames_p);
}
+unsigned int preload_control_get_ignored_names(char ***filenames_p)
+{
+ return __get_names(&ignored, filenames_p);
+}
+
+void preload_control_release_ignored_names(char ***filenames_p)
+{
+ kfree(*filenames_p);
+}
+
+bool preload_control_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 preload_control_init(void)
{
return 0;
void preload_control_exit(void)
{
- __free_target_binaries();
+ __free_binaries(&target);
+ __free_binaries(&ignored);
}
-
enum preload_call_type preload_control_call_type(struct us_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);
-unsigned int preload_control_get_bin_names(char ***filenames_p);
-void preload_control_release_bin_names(char ***filenames_p);
+unsigned int preload_control_get_target_names(char ***filenames_p);
+void preload_control_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);
+
+bool preload_control_check_dentry_is_ignored(struct dentry *dentry);
#endif /* __PRELOAD_CONTROL_H__ */
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_BINARIES[] = "target_binaries";
+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 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_list = NULL;
+static struct dentry *ignored_add = NULL;
+static struct dentry *ignored_remove = NULL;
+
static unsigned long r_debug_offset = 0;
static DEFINE_SPINLOCK(__dentry_lock);
path[len - 1] = '\0';
- if (preload_control_add_instrumented_binary(path) != 0) {
+ if (file->f_path.dentry == target_add)
+ ret = preload_control_add_instrumented_binary(path);
+ else if (file->f_path.dentry == ignored_add)
+ ret = preload_control_add_ignored_binary(path);
+ else {
+ /* Should never occur */
+ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+ file->f_path.dentry->d_name.name);
+ ret = -EINVAL;
+ goto bin_add_write_out;
+ }
+
+
+ if (ret != 0) {
printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
ret = -EINVAL;
goto bin_add_write_out;
{
ssize_t ret;
- ret = preload_control_clean_instrumented_bins();
+ if (file->f_path.dentry == target_remove)
+ ret = preload_control_clean_instrumented_bins();
+ else if (file->f_path.dentry == ignored_remove)
+ ret = preload_control_clean_ignored_bins();
+ else {
+ /* Should never occur */
+ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+ file->f_path.dentry->d_name.name);
+ ret = -EINVAL;
+ goto bin_remove_write_out;
+ }
+
if (ret != 0) {
printk(PRELOAD_PREFIX "Error during clean!\n");
ret = -EINVAL;
char *buf = NULL;
char *ptr = NULL;
- files_cnt = preload_control_get_bin_names(&filenames);
+ if (file->f_path.dentry == target_list)
+ files_cnt = preload_control_get_target_names(&filenames);
+ else if (file->f_path.dentry == ignored_list)
+ files_cnt = preload_control_get_ignored_names(&filenames);
+ else {
+ /* Should never occur */
+ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+ file->f_path.dentry->d_name.name);
+ ret = 0;
+ goto bin_list_read_out;
+ }
if (files_cnt == 0) {
printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
ptr += 1;
}
- preload_control_release_bin_names(&filenames);
+ if (file->f_path.dentry == target_list)
+ preload_control_release_target_names(&filenames);
+ else if (file->f_path.dentry == ignored_list)
+ preload_control_release_ignored_names(&filenames);
+ else {
+ /* Should never occur */
+ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+ file->f_path.dentry->d_name.name);
+ ret = 0;
+ goto bin_list_read_out;
+ }
return simple_read_from_buffer(usr_buf, count, ppos, buf, len);
bin_list_read_fail:
- preload_control_release_bin_names(&filenames);
+ if (file->f_path.dentry == target_list)
+ preload_control_release_target_names(&filenames);
+ else if (file->f_path.dentry == ignored_list)
+ preload_control_release_ignored_names(&filenames);
+ else {
+ /* Should never occur */
+ printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
+ file->f_path.dentry->d_name.name);
+ ret = 0;
+ }
bin_list_read_out:
return ret;
int preload_debugfs_init(void)
{
struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
- *bin_path, *bin_list, *bin_add, *bin_remove,
- *linker_dir, *linker_path, *linker_offset, *handlers_path;
+ *target_path, *ignored_path, *linker_dir, *linker_path,
+ *linker_offset, *handlers_path;
int ret;
ret = -ENODEV;
goto remove;
}
- bin_path = debugfs_create_dir(PRELOAD_BINARIES, root);
- if (IS_ERR_OR_NULL(bin_path)) {
+ target_path = debugfs_create_dir(PRELOAD_TARGET, root);
+ if (IS_ERR_OR_NULL(target_path)) {
+ ret = -ENOMEM;
+ goto remove;
+ }
+
+ target_list = debugfs_create_file(PRELOAD_BINARIES_LIST,
+ PRELOAD_DEFAULT_PERMS, target_path, NULL,
+ &bin_list_file_ops);
+ if (IS_ERR_OR_NULL(target_list)) {
+ ret = -ENOMEM;
+ goto remove;
+ }
+
+ target_add = debugfs_create_file(PRELOAD_BINARIES_ADD,
+ PRELOAD_DEFAULT_PERMS, target_path, NULL,
+ &bin_add_file_ops);
+ if (IS_ERR_OR_NULL(target_add)) {
+ ret = -ENOMEM;
+ goto remove;
+ }
+
+ target_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
+ PRELOAD_DEFAULT_PERMS, target_path,
+ NULL, &bin_remove_file_ops);
+ if (IS_ERR_OR_NULL(target_remove)) {
+ ret = -ENOMEM;
+ goto remove;
+ }
+
+ ignored_path = debugfs_create_dir(PRELOAD_IGNORED, root);
+ if (IS_ERR_OR_NULL(ignored_path)) {
ret = -ENOMEM;
goto remove;
}
- bin_list = debugfs_create_file(PRELOAD_BINARIES_LIST, PRELOAD_DEFAULT_PERMS,
- bin_path, NULL, &bin_list_file_ops);
- if (IS_ERR_OR_NULL(bin_list)) {
+ ignored_list = debugfs_create_file(PRELOAD_BINARIES_LIST,
+ PRELOAD_DEFAULT_PERMS, ignored_path,
+ NULL, &bin_list_file_ops);
+ if (IS_ERR_OR_NULL(ignored_list)) {
ret = -ENOMEM;
goto remove;
}
- bin_add = debugfs_create_file(PRELOAD_BINARIES_ADD, PRELOAD_DEFAULT_PERMS,
- bin_path, NULL, &bin_add_file_ops);
- if (IS_ERR_OR_NULL(bin_add)) {
+ ignored_add = debugfs_create_file(PRELOAD_BINARIES_ADD,
+ PRELOAD_DEFAULT_PERMS, ignored_path, NULL,
+ &bin_add_file_ops);
+ if (IS_ERR_OR_NULL(ignored_add)) {
ret = -ENOMEM;
goto remove;
}
- bin_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
- PRELOAD_DEFAULT_PERMS, bin_path, NULL,
- &bin_remove_file_ops);
- if (IS_ERR_OR_NULL(bin_remove)) {
+ ignored_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
+ PRELOAD_DEFAULT_PERMS, ignored_path, NULL,
+ &bin_remove_file_ops);
+ if (IS_ERR_OR_NULL(ignored_remove)) {
ret = -ENOMEM;
goto remove;
}
{
if (preload_root)
debugfs_remove_recursive(preload_root);
+ target_list = NULL;
+ target_add = NULL;
+ target_remove = NULL;
+ ignored_list = NULL;
+ ignored_add = NULL;
+ ignored_remove = NULL;
preload_root = NULL;
preload_module_set_not_ready();
return NULL;
}
-static struct vm_area_struct *__get_libc_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *libc_info;
-
- libc_info = preload_storage_get_libc_info();
-
- if (!libc_info) {
- printk(PRELOAD_PREFIX "Cannot get libc 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 == libc_info->dentry) {
- preload_storage_put_libc_info(libc_info);
- return vma;
- }
- }
-
- preload_storage_put_libc_info(libc_info);
- return NULL;
-}
-
-static struct vm_area_struct *__get_libpthread_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *libpthread_info;
-
- libpthread_info = preload_storage_get_libpthread_info();
-
- if (!libpthread_info) {
- printk(PRELOAD_PREFIX "Cannot get libpthread 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 == libpthread_info->dentry) {
- preload_storage_put_libpthread_info(libpthread_info);
- return vma;
- }
- }
-
- preload_storage_put_libpthread_info(libpthread_info);
- return NULL;
-}
-
-static struct vm_area_struct *__get_libsmack_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *libsmack_info;
-
- libsmack_info = preload_storage_get_libsmack_info();
-
- if (!libsmack_info) {
- printk(PRELOAD_PREFIX "Cannot get libsmack 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 == libsmack_info->dentry) {
- preload_storage_put_libsmack_info(libsmack_info);
- return vma;
- }
- }
-
- preload_storage_put_libsmack_info(libsmack_info);
- return NULL;
-}
-
static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task,
unsigned long caller_addr)
{
return !state;
}
-static bool __not_system_caller(struct task_struct *task,
- struct vm_area_struct *caller)
-{
- struct vm_area_struct *linker_vma = __get_linker_vma(task);
- struct vm_area_struct *libc_vma = __get_libc_vma(task);
- struct vm_area_struct *libpthread_vma = __get_libpthread_vma(task);
- struct vm_area_struct *libsmack_vma = __get_libsmack_vma(task);
-
- if (linker_vma == NULL ||
- libc_vma == NULL ||
- libpthread_vma == NULL ||
- libsmack_vma == NULL ||
- caller == NULL ||
- caller == linker_vma ||
- caller == libc_vma ||
- caller == libpthread_vma ||
- caller == libsmack_vma)
- return false;
-
- return true;
-}
-
static bool __should_we_preload_handlers(struct task_struct *task,
struct pt_regs *regs)
{
struct vm_area_struct *cvma = __get_vma_by_addr(current, caller_addr);
if (!__is_proc_mmap_mappable(task) ||
- !__not_system_caller(task, cvma))
+ ((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;
/* jump only if caller is instumented and it is not a system lib -
* this leads to some errors */
- if (__not_system_caller(current, cvma) &&
+ if (((cvma->vm_file != NULL) &&
+ (cvma->vm_file->f_path.dentry != NULL) &&
+ !preload_control_check_dentry_is_ignored(cvma->vm_file->f_path.dentry)) &&
__check_flag_and_call_type(ip, ct) &&
!__is_handlers_call(cvma)) {
if (preload_threads_set_data(current,
static struct bin_info __handlers_info = { NULL, NULL };
static struct bin_info __linker_info = { NULL, NULL };
-static struct bin_info __libc_info;
-static struct bin_info __libpthread_info;
-static struct bin_info __libsmack_info;
static inline struct bin_info *__get_handlers_info(void)
{
return NULL;
}
-static inline void __drop_libc_info(void)
-{
- if (__libc_info.dentry)
- put_dentry(__libc_info.dentry);
-
- __libc_info.path = NULL;
- __libc_info.dentry = NULL;
-}
-
-static inline void __drop_libpthread_info(void)
-{
- if (__libpthread_info.dentry)
- put_dentry(__libpthread_info.dentry);
-
- __libpthread_info.path = NULL;
- __libpthread_info.dentry = NULL;
-}
-
-static inline void __drop_libsmack_info(void)
-{
- if (__libsmack_info.dentry)
- put_dentry(__libsmack_info.dentry);
-
- __libsmack_info.path = NULL;
- __libsmack_info.dentry = NULL;
-}
-
void preload_storage_put_linker_info(struct bin_info *info)
{
}
-struct bin_info *preload_storage_get_libc_info(void)
-{
- return &__libc_info;
-}
-
-struct bin_info *preload_storage_get_libpthread_info(void)
-{
- return &__libpthread_info;
-}
-
-struct bin_info *preload_storage_get_libsmack_info(void)
-{
- return &__libsmack_info;
-}
-
-void preload_storage_put_libc_info(struct bin_info *info)
-{
-}
-
-void preload_storage_put_libpthread_info(struct bin_info *info)
-{
-}
-
-void preload_storage_put_libsmack_info(struct bin_info *info)
-{
-}
-
int preload_storage_init(void)
{
- __libc_info.path = "/lib/libc.so.6";
- __libc_info.dentry = get_dentry(__libc_info.path);
-
- if (!__libc_info.dentry)
- return -ENOENT;
-
- /* TODO check if we have not library */
- __libpthread_info.path = "/lib/libpthread.so.0";
- __libpthread_info.dentry = get_dentry(__libpthread_info.path);
-
- if (!__libpthread_info.dentry)
- return -ENOENT;
-
- /* TODO check if we have not library */
- __libsmack_info.path = "/usr/lib/libsmack.so.1.0.0";
- __libsmack_info.dentry = get_dentry(__libsmack_info.path);
-
- if (!__libsmack_info.dentry)
- return -ENOENT;
-
return 0;
}
void preload_storage_exit(void)
{
- __drop_libsmack_info();
- __drop_libpthread_info();
- __drop_libc_info();
__drop_handlers_info();
__drop_linker_info();
}
struct bin_info *preload_storage_get_linker_info(void);
void preload_storage_put_linker_info(struct bin_info *info);
-struct bin_info *preload_storage_get_libc_info(void);
-void preload_storage_put_libc_info(struct bin_info *info);
-
-struct bin_info *preload_storage_get_libpthread_info(void);
-void preload_storage_put_libpthread_info(struct bin_info *info);
-
-struct bin_info *preload_storage_get_libsmack_info(void);
-void preload_storage_put_libsmack_info(struct bin_info *info);
-
int preload_storage_init(void);
void preload_storage_exit(void);