HANDLER_RUNNING = 0x1
};
-static struct dentry *handler_dentry = NULL;
-
+struct user_ptrs {
+ char *caller;
+ char *orig;
+ char *call_type;
+};
static inline struct pd_t *__get_process_data(struct uretprobe *rp)
{
}
static inline int __msg_sanitization(char *user_msg, size_t len,
- char *call_type_p, char *caller_p)
+ struct user_ptrs *ptrs)
{
- if ((call_type_p < user_msg) || (call_type_p > user_msg + len) ||
- (caller_p < user_msg) || (caller_p > user_msg + len))
+ if (ptrs->caller &&
+ (ptrs->caller < user_msg || ptrs->caller > user_msg + len))
+ return -EINVAL;
+
+ if (ptrs->orig &&
+ (ptrs->orig < user_msg || ptrs->orig > user_msg + len))
+ return -EINVAL;
+
+ if (ptrs->call_type &&
+ (ptrs->call_type < user_msg || ptrs->call_type > user_msg + len))
return -EINVAL;
return 0;
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;
+ struct pd_t *pd;
+ struct pt_data_t ptd;
base = lpd_get_handlers_base(hd);
if (base == 0)
/* 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_path.dentry != NULL) {
-
- struct dentry *dentry = cvma->vm_file->f_path.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);
- }
- }
+ ptd.caller = get_regs_ret_func(regs);
+ cvma = __get_vma_by_addr(current, ptd.caller);
+ ptd.call_type = pc_call_type(ip, (void *)ptd.caller);
+ ptd.disable_addr = __is_probe_non_block(ip) ? ip->orig_addr : 0;
+ ptd.orig = ip->orig_addr;
+ pd = lpd_get_parent_pd(hd);
+
+ /* 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 &&
+ !pc_check_dentry_is_ignored(cvma->vm_file->f_path.dentry) &&
+ __check_flag_and_call_type(ip, ptd.call_type) &&
+ !__is_handlers_call(cvma, pd)) {
+
+ ptd.drop = __should_drop(ip, ptd.call_type);
+ if (pt_set_data(current, &ptd) != 0)
+ printk(PRELOAD_PREFIX "Error! Failed to store data for %d/%d\n",
+ current->tgid, current->pid);
+ /* args are not changed */
+ loader_module_prepare_ujump(ri, regs, vaddr);
+ if (ptd.disable_addr == 0)
+ pt_set_flags(current, HANDLER_RUNNING);
}
return vaddr;
-static void __write_data_to_msg(char *msg, size_t len,
- unsigned long call_type_off,
- unsigned long caller_off,
- unsigned long caller_addr)
+static void __write_data_on_demand(char *user, char *msg, size_t len,
+ struct user_ptrs *ptrs,
+ unsigned long caller_addr)
{
+ unsigned long caller_ptr = 0, orig_ptr = 0, ct_ptr = 0;
+ unsigned long caller = 0, orig = 0;
unsigned char call_type = 0;
- unsigned long caller = 0;
int ret;
- if (caller_addr != 0) {
+ /* Evaluate addresses whereto write data as:
+ * pointer from user - user buffer beggining + kernel buffer beginning
+ * If incoming pointer is NULL - do not write
+ */
+
+ if (ptrs->orig) {
+ orig_ptr = (unsigned long)(ptrs->orig - user + msg);
+
+ ret = pt_get_orig(current, &orig);
+ if (ret) {
+ orig = 0xbadbeef;
+ printk(PRELOAD_PREFIX "No orig for %d/%d\n",
+ current->tgid, current->pid);
+ }
+
+ /* Types should be the same as in preload lib!!! */
+ *(uint64_t *)orig_ptr = (uint64_t)orig;
+ }
+
+ if (caller_addr && ptrs->caller && ptrs->call_type) {
+ caller_ptr = (unsigned long)(ptrs->caller - user + msg);
+ ct_ptr = (unsigned long)(ptrs->call_type - user + msg);
+
caller = caller_addr;
call_type =
pc_call_type_always_inst((void *)caller);
- } else {
+
+ /* Types should be the same as in preload lib!!! */
+ *(uint64_t *)caller_ptr = (uint64_t)caller;
+ *(uint32_t *)ct_ptr = (uint32_t)call_type;
+
+ return;
+ }
+
+ if (ptrs->caller) {
+ caller_ptr = (unsigned long)(ptrs->caller - user + msg);
+
ret = pt_get_caller(current, &caller);
- if (ret != 0) {
+ if (ret) {
caller = 0xbadbeef;
- printk(PRELOAD_PREFIX "Error! Cannot get caller address"
- " for %d/%d\n", current->tgid, current->pid);
+ printk(PRELOAD_PREFIX "No caller for %d/%d\n",
+ current->tgid, current->pid);
}
+ /* Types should be the same as in preload lib!!! */
+ *(uint64_t *)caller_ptr = (uint64_t)caller;
+ }
+
+ if (ptrs->call_type) {
+ ct_ptr = (unsigned long)(ptrs->call_type - user + msg);
+
ret = pt_get_call_type(current, &call_type);
- if (ret != 0) {
+ if (ret) {
call_type = 0xff;
- printk(PRELOAD_PREFIX "Error! Cannot get call type for "
- "%d/%d\n", current->tgid, current->pid);
+ printk(PRELOAD_PREFIX "No 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;
+ /* Types should be the same as in preload lib!!! */
+ *(uint32_t *)ct_ptr = (uint32_t)call_type;
+ }
}
static int write_msg_handler(struct uprobe *p, struct pt_regs *regs)
{
- char *user_buf;
- char *buf;
- char *caller_p;
- char *call_type_p;
+ struct user_ptrs ptrs;
+ char *user_buf, *buf;
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);
+ ptrs.call_type = (char *)swap_get_uarg(regs, 2);
+ ptrs.caller = (char *)swap_get_uarg(regs, 3);
caller_addr = swap_get_uarg(regs, 4);
+ ptrs.orig = (char *)swap_get_uarg(regs, 5);
- if (call_type_p != NULL || caller_p != NULL) {
- ret = __msg_sanitization(user_buf, len, call_type_p, caller_p);
+ if (ptrs.caller || ptrs.call_type || ptrs.orig) {
+ ret = __msg_sanitization(user_buf, len, &ptrs);
if (ret != 0) {
printk(PRELOAD_PREFIX "Invalid message pointers!\n");
return 0;
goto write_msg_fail;
}
-
- if (call_type_p != NULL || caller_p != NULL) {
- /* 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);
- }
+ __write_data_on_demand(user_buf, buf, len, &ptrs, caller_addr);
ret = swap_msg_raw(buf, len);
if (ret != len)
struct list_head disabled_addrs;
unsigned long caller;
+ unsigned long orig;
unsigned char call_type;
bool drop; /* TODO Workaround, remove when will be possible to install
* several us probes at the same addr. */
static inline void __init_slot(struct thread_slot *slot)
{
slot->caller = 0;
+ slot->orig = 0;
slot->call_type = 0;
slot->drop = false;
INIT_LIST_HEAD(&slot->disabled_addrs);
static inline void __set_slot(struct thread_slot *slot,
struct task_struct *task, unsigned long caller,
- unsigned char call_type, bool drop)
+ unsigned long orig, unsigned char call_type,
+ bool drop)
{
slot->caller = caller;
+ slot->orig = orig;
slot->call_type = call_type;
slot->drop = drop;
}
-int pt_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, struct pt_data_t *data)
{
struct preload_td *td = get_preload_td(task);
struct thread_slot *slot;
+ unsigned long caller, disable_addr, orig;
+ unsigned char call_type;
+ bool drop;
int ret = 0;
+ caller = data->caller;
+ disable_addr = data->disable_addr;
+ orig = data->orig;
+ call_type = data->call_type;
+ drop = data->drop;
+
slot = __grow_slot();
if (slot == NULL) {
ret = -ENOMEM;
goto set_data_done;
}
- __set_slot(slot, task, caller, call_type, drop);
+ __set_slot(slot, task, caller, orig, call_type, drop);
list_add_tail(&slot->list, &td->slots);
set_data_done:
int pt_get_caller(struct task_struct *task, unsigned long *caller)
{
struct thread_slot *slot;
- int ret = 0;
slot = __get_task_slot(task);
if (slot != NULL) {
*caller = slot->caller;
- goto get_caller_done;
+ return 0;
}
- /* If we're here - slot was not found */
- ret = -EINVAL;
+ return -EINVAL;
+}
-get_caller_done:
- return ret;
+int pt_get_orig(struct task_struct *task, unsigned long *orig)
+{
+ struct thread_slot *slot;
+
+ slot = __get_task_slot(task);
+ if (slot != NULL) {
+ *orig = slot->caller;
+ return 0;
+ }
+
+ return -EINVAL;
}
int pt_get_call_type(struct task_struct *task,
unsigned char *call_type)
{
struct thread_slot *slot;
- int ret = 0;
slot = __get_task_slot(task);
if (slot != NULL) {
*call_type = slot->call_type;
- goto get_call_type_done;
+ return 0;
}
- /* If we're here - slot was not found */
- ret = -EINVAL;
-
-get_call_type_done:
- return ret;
+ return -EINVAL;
}
int pt_get_drop(struct task_struct *task)
{
struct thread_slot *slot;
- int ret = 0;
slot = __get_task_slot(task);
- if (slot != NULL) {
- ret = (int) slot->drop;
- goto get_drop_done;
- }
-
- /* If we're here - slot was not found */
- ret = -EINVAL;
+ if (slot != NULL)
+ return (int)slot->drop;
-get_drop_done:
- return ret;
+ return -EINVAL;
}
bool pt_check_disabled_probe(struct task_struct *task, unsigned long addr)
if (slot != NULL) {
__reinit_slot(slot);
__clean_slot(slot); /* remove from list */
- goto put_data_done;
}
-put_data_done:
return ret;
}