static struct dentry *gt_root;
-/* ===========================================================================
- * = TARGETS =
- * ===========================================================================
- */
+/* Type for function that handles string grabbed from userspace */
+typedef int (*sh_t)(char *);
-static ssize_t handler_path_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
+/* Type for function that handles unsigned long grabbed from userspace */
+typedef int (*ulh_t)(unsigned long);
+
+/* Type for function that handles pid grabbed from userspace */
+typedef int (*ph_t)(pid_t);
+
+
+static ssize_t get_string_and_call(const char __user *buf, size_t len,
+ sh_t cb)
{
+ char *string;
ssize_t ret;
- char *path;
- path = kmalloc(len, GFP_KERNEL);
- if (path == NULL) {
+ string = kmalloc(len, GFP_KERNEL);
+ if (string == NULL) {
ret = -ENOMEM;
- goto handler_path_write_out;
+ goto get_string_write_out;
}
- if (copy_from_user(path, buf, len)) {
+ if (copy_from_user(string, buf, len)) {
ret = -EINVAL;
- goto handler_path_write_out;
+ goto get_string_write_out;
}
- path[len - 1] = '\0';
- ret = gtm_set_handler_path(path);
+ string[len - 1] = '\0';
+
+ ret = cb(string);
-handler_path_write_out:
- kfree(path);
+get_string_write_out:
+ kfree(string);
return ret == 0 ? len : ret;
}
-static ssize_t handler_fixup_off_write(struct file *file,
- const char __user *buf, size_t len,
- loff_t *ppos)
+static ssize_t get_ul_and_call(const char __user *buf, size_t len, ulh_t cb)
{
ssize_t ret;
- char *off;
- unsigned long offset;
+ char *ulstring;
+ unsigned long ul;
- off = kmalloc(len, GFP_KERNEL);
- if (off == NULL) {
+ ulstring = kmalloc(len, GFP_KERNEL);
+ if (ulstring == NULL) {
ret = -ENOMEM;
- goto handler_fixup_off_write_out;
+ goto get_ul_write_out;
}
- if (copy_from_user(off, buf, len)) {
+ if (copy_from_user(ulstring, buf, len)) {
ret = -EINVAL;
- goto handler_fixup_off_write_out;
+ goto get_ul_write_out;
}
- off[len - 1] = '\0';
+ ulstring[len - 1] = '\0';
- ret = kstrtoul(off, 16, &offset);
+ ret = kstrtoul(ulstring, 16, &ul);
if (ret != 0)
- goto handler_fixup_off_write_out;
+ goto get_ul_write_out;
- ret = gtm_set_handler_fixup_off(offset);
+ ret = cb(ul);
-handler_fixup_off_write_out:
- kfree(off);
+get_ul_write_out:
+ kfree(ulstring);
return ret == 0 ? len : ret;
}
-static ssize_t handler_reloc_off_write(struct file *file,
- const char __user *buf, size_t len,
- loff_t *ppos)
+static ssize_t get_pid_and_call(const char __user *buf, size_t len, ph_t cb)
{
ssize_t ret;
- char *off;
- unsigned long offset;
+ char *pidstring;
+ pid_t pid;
- off = kmalloc(len, GFP_KERNEL);
- if (off == NULL) {
+ pidstring = kmalloc(len, GFP_KERNEL);
+ if (pidstring == NULL) {
ret = -ENOMEM;
- goto handler_reloc_off_write_out;
+ goto get_pid_write_out;
}
- if (copy_from_user(off, buf, len)) {
+ if (copy_from_user(pidstring, buf, len)) {
ret = -EINVAL;
- goto handler_reloc_off_write_out;
+ goto get_pid_write_out;
}
- off[len - 1] = '\0';
+ pidstring[len - 1] = '\0';
- ret = kstrtoul(off, 16, &offset);
+ ret = kstrtoul(pidstring, 10, (unsigned long *)&pid);
if (ret != 0)
- goto handler_reloc_off_write_out;
+ goto get_pid_write_out;
- ret = gtm_set_handler_reloc_off(offset);
+ ret = cb(pid);
-handler_reloc_off_write_out:
- kfree(off);
+get_pid_write_out:
+ kfree(pidstring);
return ret == 0 ? len : ret;
}
+/* ===========================================================================
+ * = TARGETS =
+ * ===========================================================================
+ */
+
+static ssize_t handler_path_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ return get_string_and_call(buf, len, gtm_set_handler_path);
+}
+
+static ssize_t handler_fixup_off_write(struct file *file,
+ const char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ return get_ul_and_call(buf, len, gtm_set_handler_fixup_off);
+}
+
+static ssize_t handler_reloc_off_write(struct file *file,
+ const char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ return get_ul_and_call(buf, len, gtm_set_handler_reloc_off);
+}
+
static const struct file_operations handler_path_fops = {
.owner = THIS_MODULE,
.write = handler_path_write,
static ssize_t by_path_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 target_path_add_write_out;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto target_path_add_write_out;
- }
-
- path[len - 1] = '\0';
- ret = gtm_add_by_path(path);
-
-target_path_add_write_out:
- kfree(path);
-
- return ret == 0 ? len : ret;
+ return get_string_and_call(buf, len, gtm_add_by_path);
}
static ssize_t by_path_del_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 target_path_del_write_out;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto target_path_del_write_out;
- }
-
- path[len - 1] = '\0';
- ret = gtm_del_by_path(path);
-
-target_path_del_write_out:
- kfree(path);
-
- return ret == 0 ? len : ret;
+ return get_string_and_call(buf, len, gtm_del_by_path);
}
static ssize_t by_pid_add_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
- ssize_t ret;
- unsigned long pid;
- char *pid_str;
-
- pid_str = kmalloc(len, GFP_KERNEL);
- if (pid_str == NULL) {
- ret = -ENOMEM;
- goto target_pid_add_write_out;
- }
-
- if (copy_from_user(pid_str, buf, len)) {
- ret = -EINVAL;
- goto target_pid_add_write_out;
- }
-
- pid_str[len - 1] = '\0';
-
- ret = kstrtoul(pid_str, 10, &pid);
- if (ret != 0)
- goto target_pid_add_write_out;
-
- ret = gtm_add_by_pid(pid);
-
-target_pid_add_write_out:
- kfree(pid_str);
-
- return ret == 0 ? len : ret;
+ return get_pid_and_call(buf, len, gtm_add_by_pid);
}
static ssize_t by_pid_del_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
- ssize_t ret;
- unsigned long pid;
- char *pid_str;
-
- pid_str = kmalloc(len, GFP_KERNEL);
- if (pid_str == NULL) {
- ret = -ENOMEM;
- goto target_pid_del_write_out;
- }
-
- if (copy_from_user(pid_str, buf, len)) {
- ret = -EINVAL;
- goto target_pid_del_write_out;
- }
-
- pid_str[len - 1] = '\0';
-
- ret = kstrtoul(pid_str, 10, &pid);
- if (ret != 0)
- goto target_pid_del_write_out;
-
- ret = gtm_del_by_pid(pid);
-
-target_pid_del_write_out:
- kfree(pid_str);
-
- return ret == 0 ? len : ret;
+ return get_pid_and_call(buf, len, gtm_del_by_pid);
}
static ssize_t del_all_write(struct file *file, const char __user *buf,
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';
-
- ret = gtm_set_linker_path(path);
-
-linker_path_write_out:
- kfree(path);
-
- return ret == 0 ? len : ret;
+ return get_string_and_call(buf, len, gtm_set_linker_path);
}
static ssize_t fixup_off_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
- ssize_t ret;
- char *off;
- unsigned long offset;
-
- off = kmalloc(len, GFP_KERNEL);
- if (off == NULL) {
- ret = -ENOMEM;
- goto fixup_off_write_out;
- }
-
- if (copy_from_user(off, buf, len)) {
- ret = -EINVAL;
- goto fixup_off_write_out;
- }
-
- off[len - 1] = '\0';
-
- ret = kstrtoul(off, 16, &offset);
- if (ret != 0)
- goto fixup_off_write_out;
-
- ret = gtm_set_fixup_off(offset);
-
-fixup_off_write_out:
- kfree(off);
-
- return ret == 0 ? len : ret;
+ return get_ul_and_call(buf, len, gtm_set_fixup_off);
}
static ssize_t reloc_off_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
- ssize_t ret;
- char *off;
- unsigned long offset;
-
- off = kmalloc(len, GFP_KERNEL);
- if (off == NULL) {
- ret = -ENOMEM;
- goto reloc_off_write_out;
- }
-
- if (copy_from_user(off, buf, len)) {
- ret = -EINVAL;
- goto reloc_off_write_out;
- }
-
- off[len - 1] = '\0';
-
- ret = kstrtoul(off, 16, &offset);
- if (ret != 0)
- goto reloc_off_write_out;
-
- ret = gtm_set_reloc_off(offset);
-
-reloc_off_write_out:
- kfree(off);
-
- return ret == 0 ? len : ret;
+ return get_ul_and_call(buf, len, gtm_set_reloc_off);
}
static const struct file_operations linker_path_fops = {
static ssize_t pthread_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 pthread_path_write_out;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto pthread_path_write_out;
- }
-
- path[len - 1] = '\0';
-
- ret = gtm_set_pthread_path(path);
-
-pthread_path_write_out:
- kfree(path);
-
- return ret == 0 ? len : ret;
+ return get_string_and_call(buf, len, gtm_set_pthread_path);
}
static ssize_t init_off_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
- ssize_t ret;
- char *off;
- unsigned long offset;
-
- off = kmalloc(len, GFP_KERNEL);
- if (off == NULL) {
- ret = -ENOMEM;
- goto init_off_write_out;
- }
-
- if (copy_from_user(off, buf, len)) {
- ret = -EINVAL;
- goto init_off_write_out;
- }
-
- off[len - 1] = '\0';
-
- ret = kstrtoul(off, 16, &offset);
- if (ret != 0) {
- ret = -EINVAL;
- goto init_off_write_out;
- }
-
- ret = gtm_set_init_off(offset);
-
-init_off_write_out:
- kfree(off);
-
- return ret == 0 ? len : ret;
+ return get_ul_and_call(buf, len, gtm_set_init_off);
}
static const struct file_operations pthread_path_fops = {
typedef unsigned long (*rh_t)(struct uretprobe_instance *, struct pt_regs *,
struct hd_t *);
+/* Typedef for compare function that removes data from list */
+typedef bool (*cf_t)(struct l_probe_el*, void *);
+
static LIST_HEAD(_reg_probes);
static LIST_HEAD(_unreg_probes);
static DEFINE_MUTEX(_linker_probes_lock);
*(bool *)swap_ktd(>_ktd, current) = is_in_handler;
}
+static inline bool _check_by_dentry(struct l_probe_el *l_probe, void *data)
+{
+ struct dentry *dentry = (struct dentry *)data;
+
+ if (l_probe->task_id == GT_SET_BY_DENTRY &&
+ l_probe->dentry == dentry)
+ return true;
+
+ return false;
+}
+
+static inline bool _check_by_pid(struct l_probe_el *l_probe, void *data)
+{
+ pid_t tgid = *(pid_t *)data;
+
+ if (l_probe->task_id == GT_SET_BY_PID &&
+ l_probe->tgid == tgid)
+ return true;
+
+ return false;
+}
+
+static inline bool _del_all(struct l_probe_el *l_probe, void *data)
+{
+ return true;
+}
+
/* ===========================================================================
* = LINKER HANDLERS =
* ===========================================================================
return (dest + 1);
}
+static int _add_to_list(struct l_probe_el *l_probe)
+{
+ int ret = 0;
+
+ _lock_probes_list();
+ if (_is_enable()) {
+ ret = _register_probe_el_no_lock(l_probe);
+ if (ret == 0)
+ list_add_tail(&l_probe->list, &_reg_probes);
+ } else {
+ list_add_tail(&l_probe->list, &_unreg_probes);
+ }
+
+ _unlock_probes_list();
+
+ return ret;
+}
+
+static int _remove_from_list(cf_t cb, void *data)
+{
+ struct l_probe_el *l_probe, *n;
+ int ret = 0;
+
+ _lock_probes_list();
+
+ list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
+ if (cb(l_probe, data)) {
+ ret = _unregister_probe_el_no_lock(l_probe);
+ if (ret == 0) {
+ list_del(&l_probe->list);
+ _destroy_linker_probe_el_no_lock(l_probe);
+ }
+ goto remove_from_list_unlock;
+ }
+ }
+
+ list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
+ if (cb(l_probe, data)) {
+ list_del(&l_probe->list);
+ _destroy_linker_probe_el_no_lock(l_probe);
+ goto remove_from_list_unlock;
+ }
+ }
+
+remove_from_list_unlock:
+ _unlock_probes_list();
+
+ return ret;
+}
+
l_probe->task_id = GT_SET_BY_DENTRY;
l_probe->dentry = dentry;
- _lock_probes_list();
- if (_is_enable()) {
- ret = _register_probe_el_no_lock(l_probe);
- if (ret == 0)
- list_add_tail(&l_probe->list, &_reg_probes);
- else
- goto add_by_path_unlock;
- } else {
- list_add_tail(&l_probe->list, &_unreg_probes);
- }
- _unlock_probes_list();
+ ret = _add_to_list(l_probe);
+ if (ret != 0)
+ goto add_by_path_free;
return 0;
-add_by_path_unlock:
- _unlock_probes_list();
+add_by_path_free:
kfree(l_probe);
add_by_path_put_pfg:
l_probe->task_id = GT_SET_BY_PID;
l_probe->tgid = pid;
- _lock_probes_list();
- if (_is_enable()) {
- ret = _register_probe_el_no_lock(l_probe);
- if (ret == 0)
- list_add_tail(&l_probe->list, &_reg_probes);
- else
- goto add_by_pid_unlock;
- } else {
- list_add_tail(&l_probe->list, &_unreg_probes);
- }
- _unlock_probes_list();
+ ret = _add_to_list(l_probe);
+ if (ret != 0)
+ goto add_by_pid_free;
return 0;
-add_by_pid_unlock:
- _unlock_probes_list();
+add_by_pid_free:
kfree(l_probe);
add_by_pid_put_pfg:
int gtm_del_by_path(char *path)
{
- struct l_probe_el *l_probe, *n;
struct dentry *dentry;
int ret = 0;
if (dentry == NULL)
return -EINVAL;
- _lock_probes_list();
-
- list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
- if (l_probe->task_id == GT_SET_BY_DENTRY &&
- l_probe->dentry == dentry) {
- ret = _unregister_probe_el_no_lock(l_probe);
- if (ret != 0)
- goto del_by_path_unlock;
- list_del(&l_probe->list);
- _destroy_linker_probe_el_no_lock(l_probe);
- goto del_by_path_unlock;
- }
- }
-
- list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
- if (l_probe->task_id == GT_SET_BY_DENTRY &&
- l_probe->dentry == dentry) {
- list_del(&l_probe->list);
- _destroy_linker_probe_el_no_lock(l_probe);
- goto del_by_path_unlock;
- }
- }
-
-del_by_path_unlock:
- _unlock_probes_list();
+ ret = _remove_from_list(_check_by_dentry, dentry);
return ret;
}
int gtm_del_by_pid(pid_t pid)
{
- struct l_probe_el *l_probe, *n;
int ret = 0;
- _lock_probes_list();
-
- list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
- if (l_probe->task_id == GT_SET_BY_PID &&
- l_probe->tgid == pid) {
- ret = _unregister_probe_el_no_lock(l_probe);
- if (ret != 0)
- goto del_by_pid_unlock;
- list_del(&l_probe->list);
- _destroy_linker_probe_el_no_lock(l_probe);
- goto del_by_pid_unlock;
- }
- }
-
- list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
- if (l_probe->task_id == GT_SET_BY_PID &&
- l_probe->tgid == pid) {
- list_del(&l_probe->list);
- _destroy_linker_probe_el_no_lock(l_probe);
- goto del_by_pid_unlock;
- }
- }
-
-del_by_pid_unlock:
- _unlock_probes_list();
+ ret = _remove_from_list(_check_by_pid, &pid);
return ret;
}
int gtm_del_all(void)
{
- struct l_probe_el *l_probe, *n;
int ret = 0;
- _lock_probes_list();
-
- list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
- ret = _unregister_probe_el_no_lock(l_probe);
- if (ret != 0)
- goto del_all_fail;
- list_del(&l_probe->list);
- _destroy_linker_probe_el_no_lock(l_probe);
- }
-
- list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
- list_del(&l_probe->list);
- _destroy_linker_probe_el_no_lock(l_probe);
- }
-
-del_all_fail:
- _unlock_probes_list();
+ ret = _remove_from_list(_del_all, NULL);
return ret;
}