#include <linux/kernel.h>
#include <linux/string.h> // strrchr
-#undef __DEBUG
+// #undef __DEBUG
#ifdef __DEBUG
#define DPRINTF(format, args...) do { \
break;
}
+ case EC_IOCTL_SET_PID:
+ {
+ unsigned int _pid;
+
+ result = copy_from_user(&_pid, (void *)arg, sizeof(unsigned int));
+ if (result) {
+ EPRINTF("Cannot copy pid!");
+ result = -1;
+ break;
+ }
+
+ inst_pid = _pid;
+
+ DPRINTF("EC_IOCTL_SET_PID pid:%d", inst_pid);
+
+ break;
+ }
case EC_IOCTL_SET_PROFILEBUNDLE:
{
size_t size;
EC_IOCTL_GET_PREDEF_UPROBES,
EC_IOCTL_GET_PREDEF_UPROBES_SIZE,
+ EC_IOCTL_SET_PID,
+
} EC_IOCTL_CMD;
typedef struct
inst_us_proc_t us_proc_info;
char *deps;
char *bundle;
+unsigned int inst_pid = 0;
struct hlist_head kernel_probes;
int event_mask = 0L;
struct cond cond_list;
return 0;
}
+int SetPid(unsigned int pid)
+{
+ if (GetECState() != EC_STATE_IDLE)
+ {
+ EPRINTF("PID changes are allowed in IDLE state only (%d)!", GetECState());
+ return -1;
+ }
+
+ inst_pid = pid;
+ DPRINTF("SetPid pid:%d\n", pid);
+ return 0;
+}
+
void ResetSingleBuffer(void) {
}
}
p += sizeof(u_int32_t);
+ /* Pid */
+ if (SetPid(*(u_int32_t *)p) == -1) {
+ EPRINTF("Cannot set pid!\n");
+ return -1;
+ }
+ p += sizeof(u_int32_t);
+
/* Kernel probes */
nr_kern_probes = *(u_int32_t *)p;
p += sizeof(u_int32_t);
path_release(&nd);
#else
d_lib->m_f_dentry = nd.path.dentry;
+ d_lib->m_vfs_mount = nd.path.mnt;
path_put(&nd.path);
#endif
#if !defined(__STORAGE_H__)
#define __STORAGE_H__
+#include <linux/mount.h>
#include "picl.h"
#include "ec_ioctl.h"
#include "ec_probe.h"
extern int SetBufferSize(unsigned int nSize);
extern int ResetBuffer(void);
+extern int SetPid(unsigned int pid);
+
//extern spinlock_t buffer_spinlock;
///////////////////////////////////////////////////////////////////////////////////////////////////
// event mask
extern int event_mask;
+// process pid to instrument
+extern unsigned int inst_pid;
+
typedef struct
{
char *name;
} us_proc_vtp_data_t;
typedef struct dentry *STRUCT_DENTRY_PTR;
+typedef struct vfsmount *STRUCT_VFSMOUNT_PTR;
typedef struct
{
char *path;
STRUCT_DENTRY_PTR m_f_dentry;
+ STRUCT_VFSMOUNT_PTR m_vfs_mount;
unsigned ips_count;
us_proc_ip_t *p_ips;
unsigned vtps_count;
rcu_read_lock ();
for_each_process (task) {
+
+ if ( 0 != inst_pid && ( inst_pid != task->pid ) )
+ continue;
+
mm = get_task_mm (task);
if (!mm)
continue;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
if (vma->vm_file->f_dentry == nd.dentry) {
#else
- if (vma->vm_file->f_dentry == nd.path.dentry) {
+ if (vma->vm_file->f_dentry == nd.path.dentry ) {
#endif
if (!*p_task) {
*p_task = task;
unsigned int old_ips_count, old_vtps_count;
struct mm_struct *mm;
+ char path_buffer[256];
+
mm = atomic ? task->active_mm : get_task_mm (task);
if (!mm) {
return task_inst_info->unres_ips_count + task_inst_info->unres_vtps_count;
}
+// DPRINTF("installing probes...");
+
old_ips_count = task_inst_info->unres_ips_count;
old_vtps_count = task_inst_info->unres_vtps_count;
+
if(!atomic)
down_read (&mm->mmap_sem);
+
+// DPRINTF("locked for read");
+
vma = mm->mmap;
while (vma) {
// skip non-text section
* After process was forked, some time it inherits parent process environment.
* We need to renew instrumentation when we detect that process gets own environment.
*/
- if (vma->vm_flags & VM_EXECUTABLE) {
- if (!task_inst_info->m_f_dentry) {
- task_inst_info->m_f_dentry = vma->vm_file->f_dentry;
- printk("initiate dentry tgid = %d\n", task->tgid, task->comm);
- } else if (task_inst_info->m_f_dentry != vma->vm_file->f_dentry) {
- printk("we have detected that detry was changed tgid = %d\n", task->tgid, task->comm);
- for (i = 0; i < task_inst_info->libs_count; i++) {
- task_inst_info->p_libs[i].loaded = 0;
- for (k = 0; k < task_inst_info->p_libs[i].ips_count; k++) {
- task_inst_info->p_libs[i].p_ips[k].installed = 0;
- task_inst_info->unres_ips_count++;
- }
- for (k = 0; k < task_inst_info->p_libs[i].vtps_count; k++) {
- task_inst_info->p_libs[i].p_vtps[k].installed = 0;
- task_inst_info->unres_vtps_count++;
- }
+// DPRINTF("vma_start:%x vma_end:%x", vma->vm_start, vma->vm_end );
- task_inst_info->m_f_dentry = vma->vm_file->f_dentry;
- }
+ if (vma->vm_flags & VM_EXECUTABLE)
+ {
+
+// DPRINTF("VM_EXECUTABLE");
+
+ if (!task_inst_info->m_f_dentry)
+ {
+ task_inst_info->m_f_dentry = vma->vm_file->f_dentry;
+ printk("initiate dentry tgid = %d\n", task->tgid, task->comm);
+ }
+ else if (task_inst_info->m_f_dentry != vma->vm_file->f_dentry)
+ {
+ printk("we have detected that detry was changed tgid = %d\n", task->tgid, task->comm);
+ for (i = 0; i < task_inst_info->libs_count; i++)
+ {
+ task_inst_info->p_libs[i].loaded = 0;
+ for (k = 0; k < task_inst_info->p_libs[i].ips_count; k++)
+ {
+ task_inst_info->p_libs[i].p_ips[k].installed = 0;
+ task_inst_info->unres_ips_count++;
+ }
+
+ for (k = 0; k < task_inst_info->p_libs[i].vtps_count; k++)
+ {
+ task_inst_info->p_libs[i].p_vtps[k].installed = 0;
+ task_inst_info->unres_vtps_count++;
+ }
+
+ task_inst_info->m_f_dentry = vma->vm_file->f_dentry;
+ }
}
}
+
+// DPRINTF("Instrumenting libs. libcount:%d", task_inst_info->libs_count );
- for (i = 0; i < task_inst_info->libs_count; i++) {
+ for (i = 0; i < task_inst_info->libs_count; i++)
+ {
+// struct path tmp_path;
+//
+// tmp_path.dentry = task_inst_info->p_libs[i].m_f_dentry;
+// tmp_path.mnt = task_inst_info->p_libs[i].m_vfs_mount;
+//
+// char* p_path = d_path ( &tmp_path, path_buffer, 255 );
+//
+// DPRINTF("f_dentry:%x m_f_dentry:%x path:%s", vma->vm_file->f_dentry, task_inst_info->p_libs[i].m_f_dentry, p_path );
+
//TODO: test - try to instrument non-existing libs
- if (vma->vm_file->f_dentry == task_inst_info->p_libs[i].m_f_dentry) {
- if(!(vma->vm_flags & VM_EXECUTABLE) && !task_inst_info->p_libs[i].loaded) {
+ if (vma->vm_file->f_dentry == task_inst_info->p_libs[i].m_f_dentry)
+ {
+// DPRINTF("vm_flags:%x loaded:%x ips_count:%d vtps_count:%d", vma->vm_flags, task_inst_info->p_libs[i].loaded,
+// task_inst_info->p_libs[i].ips_count, task_inst_info->p_libs[i].vtps_count );
+
+ if(!(vma->vm_flags & VM_EXECUTABLE) && !task_inst_info->p_libs[i].loaded)
+ {
+// DPRINTF("!VM_EXECUTABLE && !loaded");
char *p;
DPRINTF ("post dyn lib event %s/%s", current->comm, task_inst_info->p_libs[i].path);
// if we installed something, post library info for those IPs
task->tgid, p, vma->vm_start, vma->vm_end-vma->vm_start);
}
- for (k = 0; k < task_inst_info->p_libs[i].ips_count; k++) {
+ for (k = 0; k < task_inst_info->p_libs[i].ips_count; k++)
+ {
+// DPRINTF("ips_count current:%d", k);
if (!task_inst_info->p_libs[i].p_ips[k].installed)
{
+// DPRINTF("!installed");
addr = task_inst_info->p_libs[i].p_ips[k].offset;
- if (!(vma->vm_flags & VM_EXECUTABLE)) {
+ if (!(vma->vm_flags & VM_EXECUTABLE))
+ {
/* In the case of prelinking addr is already an
* absolute address so we do not need to add
* library base address to it. We use a rule of
if (addr < vma->vm_start)
addr += vma->vm_start;
}
- if (page_present (mm, addr)) {
+ if (page_present (mm, addr))
+ {
DPRINTF ("pid %d, %s sym is loaded at %lx/%lx.", task->pid, task_inst_info->p_libs[i].path, task_inst_info->p_libs[i].p_ips[k].offset, addr);
task_inst_info->p_libs[i].p_ips[k].jprobe.kp.addr = (kprobe_opcode_t *) addr;
task_inst_info->p_libs[i].p_ips[k].retprobe.kp.addr = (kprobe_opcode_t *) addr;
task_inst_info->unres_ips_count--;
err = register_usprobe (task, mm, &task_inst_info->p_libs[i].p_ips[k], atomic, 0);
- if (err != 0) {
+ if (err != 0)
+ {
DPRINTF ("failed to install IP at %lx/%p. Error %d!", task_inst_info->p_libs[i].p_ips[k].offset,
task_inst_info->p_libs[i].p_ips[k].jprobe.kp.addr, err);
}
}
}
}
- for (k = 0; k < task_inst_info->p_libs[i].vtps_count; k++) {
+ for (k = 0; k < task_inst_info->p_libs[i].vtps_count; k++)
+ {
+// DPRINTF("vtps_count current:%d", k);
if (!task_inst_info->p_libs[i].p_vtps[k].installed)
{
+// DPRINTF("!installed");
addr = task_inst_info->p_libs[i].p_vtps[k].addr;
if (!(vma->vm_flags & VM_EXECUTABLE))
addr += vma->vm_start;
- if (page_present (mm, addr)) {
+ if (page_present (mm, addr))
+ {
+ DPRINTF ("pid %d, %s sym is loaded at %lx/%lx.", task->pid, task_inst_info->p_libs[i].path, task_inst_info->p_libs[i].p_ips[k].offset, addr);
task_inst_info->p_libs[i].p_vtps[k].jprobe.kp.tgid = task_inst_info->tgid;
task_inst_info->p_libs[i].p_vtps[k].jprobe.kp.addr = (kprobe_opcode_t *) addr;
task_inst_info->p_libs[i].p_vtps[k].jprobe.entry = (kprobe_opcode_t *) us_vtp_event_handler;
task_inst_info->unres_vtps_count--;
err = register_ujprobe (task, mm, &task_inst_info->p_libs[i].p_vtps[k].jprobe, atomic);
- if (err != 0) {
+ if (err != 0)
+ {
EPRINTF ("failed to install VTP at %p. Error %d!",
task_inst_info->p_libs[i].p_vtps[k].jprobe.kp.addr, err);
}
if (!us_proc_info.path)
return 0;
+ DPRINTF("User space instr");
+
+
for (i = 0; i < us_proc_info.libs_count; i++)
us_proc_info.p_libs[i].loaded = 0;
/* check whether process is already running
task_inst_info = copy_task_inst_info (task, &us_proc_info);
put_task_inst_node(task, task_inst_info);
}
+ DPRINTF("trying process");
install_mapped_ips (task, task_inst_info, 1);
//put_task_struct (task);
task_inst_info = NULL;
else
{
ret = find_task_by_path (us_proc_info.path, &task, NULL);
- if (task)
+ if ( task )
{
+ DPRINTF("task found. installing probes");
us_proc_info.tgid = task->pid;
install_mapped_ips (task, &us_proc_info, 0);
put_task_struct (task);
ARM_INSN_MATCH (BX, ainsn->insn[0]) ||
ARM_INSN_MATCH (BXJ, ainsn->insn[0]))
{
+ printk ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn[0]);
DBPRINTF ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn[0]);
ret = -EFAULT;
}
(ARM_INSN_REG_RD (ainsn->insn[0]) == 15))
{
DBPRINTF ("Bad arch_check_insn_arm: %lx\n", ainsn->insn[0]);
+ printk ("Bad arch_check_insn_arm: %lx\n", ainsn->insn[0]);
ret = -EFAULT;
}
#endif // CONFIG_CPU_V7
// store/load with pc update
((ARM_INSN_REG_RN (ainsn->insn[0]) == 15) && (ainsn->insn[0] & 0x200000))))
{
+ printk ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn[0]);
DBPRINTF ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn[0]);
ret = -EFAULT;
}
(THUMB2_INSN_MATCH (LDRWL, ainsn->insn[0]) && THUMB2_INSN_REG_RT(ainsn->insn[0]) == 15) ||
(THUMB2_INSN_MATCH (DP, ainsn->insn[0]) && THUMB2_INSN_REG_RD(ainsn->insn[0]) == 15))
{
+ printk ("Bad insn arch_check_insn_thumb: %lx\n", ainsn->insn[0]);
DBPRINTF ("Bad insn arch_check_insn_thumb: %lx\n", ainsn->insn[0]);
ret = -EFAULT;
}
{
int ret = 0;
+// printk ( ">>>>>>>>>>>>>>>arch_prepare_uprobe task:%s %x\n", task->comm, p->addr );
+
if ((unsigned long) p->addr & 0x01)
{
DBPRINTF ("Attempt to register kprobe at an unaligned address");
int my_pr = 0;
int i = 0;
+ preempt_disable ();
+
if (user_mode(regs))
{
if (!thumb_mode ( regs )) addr = (kprobe_opcode_t *) (regs->uregs[15] - 4);
else addr = (kprobe_opcode_t *) (regs->uregs[15] - 2);
+ //printk ("%s %x\n", __FUNCTION__, addr );
+
for(i = 0; i < my_probe; i++)
{
if (my_p[i]->addr == addr)
{
my_handler_lock = 1;
- if (thumb_mode(regs))
+ if (thumb_mode(regs) /*&& addr != 0xad327238 */)
{
if ((ret = arch_copy_trampoline_thumb_uprobe(my_p[my_pr], my_task[my_pr], my_atomic[my_pr])) != 0)
{
printk(" >>>>> arch_copy_trampoline_thumb_uprobe error\n");
+ preempt_enable_no_resched ();
return ret;
}
}else{
if ((ret = arch_copy_trampoline_arm_uprobe(my_p[my_pr], my_task[my_pr], my_atomic[my_pr])) != 0)
{
printk(" >>>>> arch_copy_trampoline_arm_uprobe error\n");
+ preempt_enable_no_resched ();
return ret;
}
}
// DBPRINTF ("KPROBE: regs->uregs[15] = 0x%lx addr = 0x%p\n", regs->uregs[15], addr);
//DBPRINTF("regs->uregs[14] = 0x%lx\n", regs->uregs[14]);
- preempt_disable ();
-
kcb = get_kprobe_ctlblk ();
if (user_mode (regs))
mm = atomic ? task->active_mm : get_task_mm (task);
if (mm){
if(!atomic)
- down_write (&mm->mmap_sem);
+ {
+ if ( !down_write_trylock (&mm->mmap_sem) )
+ {
+ rcu_read_lock ();
+
+ up_read (&mm->mmap_sem);
+ down_write (&mm->mmap_sem);
+
+ rcu_read_unlock();
+ }
+ }
// FIXME: its seems to be bad decision to replace 'current' pointer temporarily
current_thread_info()->task = task;
ret = (unsigned long)do_mmap_pgoff(0, 0, len, prot, flags, 0);
current_thread_info()->task = otask;
- if(!atomic){
- up_write (&mm->mmap_sem);
+ if(!atomic)
+ {
+ downgrade_write (&mm->mmap_sem);
mmput(mm);
}
}
else
printk ("proc %d has no mm", task->pid);
+
return (unsigned long)ret;
}
struct hlist_head *page_list = task ? &uprobe_insn_pages : &kprobe_insn_pages;
unsigned slots_per_page = INSNS_PER_PAGE, slot_size = MAX_INSN_SIZE;
+ printk (">>>>>>>>>>>>>>>>>>>>>>>>>>>> %s %d\n", __FUNCTION__, __LINE__);
+
if(task) {
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
slots_per_page = INSNS_PER_PAGE/UPROBES_TRAMP_LEN;
slot_size = UPROBES_TRAMP_LEN;
}
else {
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
slots_per_page = INSNS_PER_PAGE/KPROBES_TRAMP_LEN;
slot_size = KPROBES_TRAMP_LEN;
}
retry:
hlist_for_each_entry (kip, pos, page_list, hlist)
{
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
if (kip->nused < slots_per_page)
{
int i;
if(!task || (kip->tgid == task->tgid)){
kip->slot_used[i] = SLOT_USED;
kip->nused++;
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
return kip->insns + (i * slot_size);
}
}
/* If there are any garbage slots, collect it and try again. */
if(task) {
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
if (uprobe_garbage_slots && collect_garbage_slots(page_list, task) == 0)
goto retry;
}
else {
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
if (kprobe_garbage_slots && collect_garbage_slots(page_list, task) == 0)
goto retry;
}
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
/* All out of space. Need to allocate a new page. Use slot 0. */
kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
if (!kip)
return NULL;
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
kip->slot_used = kmalloc(sizeof(char)*slots_per_page, GFP_KERNEL);
if (!kip->slot_used){
kfree(kip);
}
if(task) {
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
kip->insns = (kprobe_opcode_t *)alloc_user_pages(task, PAGE_SIZE,
PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, atomic);
}
else {
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
kip->insns = kmalloc(PAGE_SIZE, GFP_KERNEL);
}
if (!kip->insns)
{
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
kfree (kip->slot_used);
kfree (kip);
return NULL;
}
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
INIT_HLIST_NODE (&kip->hlist);
hlist_add_head (&kip->hlist, page_list);
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
memset(kip->slot_used, SLOT_CLEAN, slots_per_page);
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
kip->slot_used[0] = SLOT_USED;
kip->nused = 1;
kip->ngarbage = 0;
kip->tgid = task ? task->tgid : 0;
+ printk ("=========================== %s %d\n", __FUNCTION__, __LINE__);
return kip->insns;
}
#endif
}
+
int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
{
struct mm_struct *mm;
struct vm_area_struct *vma;
void *old_buf = buf;
+ unsigned long addr1 = addr;
+ unsigned int* inst_buf = (unsigned int*)buf;
+
mm = get_task_mm(tsk);
if (!mm)
return 0;
- //down_read(&mm->mmap_sem);
+ down_read(&mm->mmap_sem);
/* ignore errors, just check how much was successfully transferred */
while (len) {
int bytes, ret, offset;
ret = get_user_pages_uprobe(tsk, mm, addr, 1,
write, 1, &page, &vma);
+
if (ret <= 0) {
/*
* Check if this is a VM_IO | VM_PFNMAP VMA, which
buf += bytes;
addr += bytes;
}
- //up_read(&mm->mmap_sem);
+ up_read(&mm->mmap_sem);
mmput(mm);
+
+ if(addr1 == 0xad327238)
+ {
+ printk(">>>>> %s\n", tsk->comm);
+ printk(">>>>> %x\n", inst_buf[0]);
+ }
+
+
return buf - old_buf;
}
int ret = 0;
struct kprobe *old_p;
+// printk (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>> %s %d\n", __FUNCTION__, __LINE__);
+
if (!p->addr)
return -EINVAL;
DBPRINTF ("goto out\n", ret);
goto out;
}
+
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
if ((ret = arch_prepare_uprobe (p, task, atomic)) != 0)
{
- DBPRINTF ("goto out\n", ret);
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
+ DBPRINTF ("goto out\n", ret);
goto out;
}
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
DBPRINTF ("before out ret = 0x%x\n", ret);
INIT_HLIST_NODE (&p->hlist);
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
hlist_add_head_rcu (&p->hlist, &kprobe_table[hash_ptr (p->addr, KPROBE_HASH_BITS)]);
INIT_HLIST_NODE (&p->is_hlist);
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
hlist_add_head_rcu (&p->is_hlist, &uprobe_insn_slot_table[hash_ptr (p->ainsn.insn, KPROBE_HASH_BITS)]);
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
arch_arm_uprobe (p, task);
+// printk ("================================ %s %d\n", __FUNCTION__, __LINE__);
+
out:
DBPRINTF ("out ret = 0x%x\n", ret);
+// printk ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<< %s %d\n", __FUNCTION__, __LINE__);
return ret;
}