-#include <dbi_kprobes.h>
-#include <dbi_kprobes_deps.h>
-#include <ksyms.h>
-#include "us_proc_inst.h"
+/*
+ * SWAP uprobe manager
+ * modules/us_manager/helper.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2013
+ *
+ * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include <kprobe/dbi_kprobes.h>
+#include <kprobe/dbi_kprobes_deps.h>
+#include <ksyms/ksyms.h>
+#include <writer/kernel_operations.h>
+#include <writer/swap_writer_module.h>
#include "us_slot_manager.h"
-#include "storage.h"
#include "sspt/sspt.h"
#include "helper.h"
unsigned long addr;
};
-static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
+static int entry_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
{
struct pf_data *data = (struct pf_data *)ri->data;
-#if defined(CONFIG_X86)
- data->addr = read_cr2();
-#elif defined(CONFIG_ARM)
- data->addr = regs->ARM_r0;
-#else
-#error this architecture is not supported
-#endif
+ data->addr = swap_get_karg(regs, 2);
return 0;
}
/* Detects when IPs are really loaded into phy mem and installs probes. */
-static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
+static int ret_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
{
- struct task_struct *task;
- struct sspt_proc *proc;
-
- install_page(((struct pf_data *)ri->data)->addr);
- return 0;
+ struct task_struct *task = current;
+ unsigned long page_addr;
- /*
- * Because process threads have same address space
- * we instrument only group_leader of all this threads
- */
- task = current->group_leader;
if (is_kthread(task))
return 0;
- proc = sspt_proc_get_by_task(task);
- if (proc)
- goto install_proc;
-
- task = check_task(task);
- if (task) {
- proc = sspt_proc_get_new(task);
- goto install_proc;
- }
-
- return 0;
-
-install_proc:
- if (proc->first_install) {
- unsigned long page;
- page = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
- sspt_proc_install_page(proc, page);
- } else {
- sspt_proc_install(proc);
- }
+ /* TODO: check return value */
+ page_addr = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
+ call_page_fault(task, page_addr);
return 0;
}
-static struct kretprobe pf_kretprobe = {
- .entry_handler = entry_handler_pf,
- .handler = ret_handler_pf,
+static struct kretprobe mf_kretprobe = {
+ .entry_handler = entry_handler_mf,
+ .handler = ret_handler_mf,
.data_size = sizeof(struct pf_data)
};
if(task->mm != current->mm) { /* check flags CLONE_VM */
rm_uprobes_child(task);
-
- if (check_task(current)) {
- struct sspt_proc *proc;
-
- proc = sspt_proc_get_new(task);
- sspt_proc_install(proc);
- }
}
out:
return 0;
/* Detects when target process removes IPs. */
static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
- struct sspt_proc *proc = NULL;
- struct task_struct *task;
-
-#if defined(CONFIG_X86)
- task = (struct task_struct *)regs->EREG(ax);
-#elif defined(CONFIG_ARM)
- task = (struct task_struct *)regs->ARM_r0;
-#else
-#error this architecture is not supported
-#endif
+ struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
if (is_kthread(task))
goto out;
goto out;
}
- proc = sspt_proc_get_by_task(task);
- if (proc) {
- int ret = sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
- if (ret != 0) {
- printk("failed to uninstall IPs (%d)!\n", ret);
- }
-
- dbi_unregister_all_uprobes(task);
- }
-
+ call_mm_release(task);
out:
return 0;
}
* do_munmap() *
******************************************************************************
*/
+struct unmap_data {
+ unsigned long start;
+ size_t len;
+};
-static int remove_unmap_probes(struct task_struct *task, struct sspt_proc *proc, unsigned long start, size_t len)
+static void remove_unmap_probes(struct sspt_proc *proc, struct unmap_data *umd)
{
- struct mm_struct *mm = task->mm;
- struct vm_area_struct *vma;
-
- if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE - start) {
- return -EINVAL;
- }
+ struct task_struct *task = proc->task;
+ unsigned long start = umd->start;
+ size_t len = PAGE_ALIGN(umd->len);
+ LIST_HEAD(head);
- if ((len = PAGE_ALIGN(len)) == 0) {
- return -EINVAL;
- }
-
- vma = find_vma(mm, start);
- if (vma && check_vma(vma)) {
- struct sspt_file *file;
+ if (sspt_proc_get_files_by_region(proc, &head, start, len)) {
+ struct sspt_file *file, *n;
unsigned long end = start + len;
- struct dentry *dentry = vma->vm_file->f_dentry;
- file = sspt_proc_find_file(proc, dentry);
- if (file) {
- if (vma->vm_start == start || vma->vm_end == end) {
- sspt_file_uninstall(file, task, US_UNREGS_PROBE);
- file->loaded = 0;
+ list_for_each_entry_safe(file, n, &head, list) {
+ if (file->vm_start >= end)
+ continue;
+
+ if (file->vm_start >= start) {
+ sspt_file_uninstall(file, task, US_UNINSTALL);
} else {
- unsigned long page_addr;
- struct sspt_page *page;
-
- for (page_addr = vma->vm_start; page_addr < vma->vm_end; page_addr += PAGE_SIZE) {
- page = sspt_find_page_mapped(file, page_addr);
- if (page) {
- sspt_unregister_page(page, US_UNREGS_PROBE, task);
- }
- }
-
- if (sspt_file_check_install_pages(file)) {
- file->loaded = 0;
- }
+ /* TODO: uninstall pages: start..file->vm_end */
}
}
+
+ sspt_proc_insert_files(proc, &head);
+
+ proc_unmap_msg(start, end);
}
+}
+
+
+static int entry_handler_unmap(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ struct unmap_data *data = (struct unmap_data *)ri->data;
+
+ data->start = swap_get_karg(regs, 1);
+ data->len = (size_t)swap_get_karg(regs, 2);
return 0;
}
-/* Detects when target removes IPs. */
-static int unmap_pre_handler(struct kprobe *p, struct pt_regs *regs)
+static int ret_handler_unmap(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
{
- /* for ARM */
- struct mm_struct *mm;
- unsigned long start;
- size_t len;
+ struct task_struct *task;
+ struct sspt_proc *proc;
-#if defined(CONFIG_X86)
- mm = (struct mm_struct *)regs->EREG(ax);
- start = regs->EREG(dx);
- len = (size_t)regs->EREG(cx);
-#elif defined(CONFIG_ARM)
- mm = (struct mm_struct *)regs->ARM_r0;
- start = regs->ARM_r1;
- len = (size_t)regs->ARM_r2;
-#else
-#error this architecture is not supported
-#endif
-
- struct sspt_proc *proc = NULL;
- struct task_struct *task = current;
+ task = current->group_leader;
+ if (is_kthread(task) ||
+ get_regs_ret_val(regs))
+ return 0;
+
+ proc = sspt_proc_get_by_task(task);
+ if (proc)
+ remove_unmap_probes(proc, (struct unmap_data *)ri->data);
+
+ return 0;
+}
+static struct kretprobe unmap_kretprobe = {
+ .entry_handler = entry_handler_unmap,
+ .handler = ret_handler_unmap,
+ .data_size = sizeof(struct unmap_data)
+};
+
+
+
+/*
+ ******************************************************************************
+ * do_mmap_pgoff() *
+ ******************************************************************************
+ */
+static int ret_handler_mmap(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ struct sspt_proc *proc;
+ struct task_struct *task;
+ unsigned long start_addr;
+ struct vm_area_struct *vma;
+
+ task = current->group_leader;
if (is_kthread(task))
- goto out;
+ return 0;
+
+ start_addr = (unsigned long)get_regs_ret_val(regs);
+ if (IS_ERR_VALUE(start_addr))
+ return 0;
proc = sspt_proc_get_by_task(task);
- if (proc) {
- if (remove_unmap_probes(task, proc, start, len)) {
- printk("ERROR do_munmap: start=%lx, len=%x\n", start, len);
- }
- }
+ if (proc == NULL)
+ return 0;
+
+ vma = find_vma_intersection(task->mm, start_addr, start_addr + 1);
+ if (vma && check_vma(vma))
+ pcoc_map_msg(vma);
-out:
return 0;
}
-static struct kprobe unmap_kprobe = {
- .pre_handler = unmap_pre_handler
+static struct kretprobe mmap_kretprobe = {
+ .handler = ret_handler_mmap
};
int ret = 0;
/* install kprobe on 'do_munmap' to detect when for remove user space probes */
- ret = dbi_register_kprobe(&unmap_kprobe);
+ ret = dbi_register_kretprobe(&unmap_kretprobe);
if (ret) {
printk("dbi_register_kprobe(do_munmap) result=%d!\n", ret);
return ret;
goto unregister_mr;
}
- /* install kretprobe on 'do_page_fault' to detect when they will be loaded */
- ret = dbi_register_kretprobe(&pf_kretprobe);
+ /* install kretprobe on 'do_mmap_pgoff' to detect when mapping file */
+ ret = dbi_register_kretprobe(&mmap_kretprobe);
if (ret) {
- printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
+ printk("dbi_register_kretprobe(do_mmap_pgoff) result=%d!\n", ret);
goto unregister_cp;
}
+ /* install kretprobe on 'handle_mm_fault' to detect when they will be loaded */
+ ret = dbi_register_kretprobe(&mf_kretprobe);
+ if (ret) {
+ printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
+ goto unregister_mmap;
+ }
+
return ret;
+
+unregister_mmap:
+ dbi_unregister_kretprobe(&mmap_kretprobe);
+
unregister_cp:
dbi_unregister_kretprobe(&cp_kretprobe);
unregister_mr:
- dbi_unregister_kprobe(&mr_kprobe, NULL);
+ dbi_unregister_kprobe(&mr_kprobe);
unregister_unmap:
- dbi_unregister_kprobe(&unmap_kprobe, NULL);
+ dbi_unregister_kretprobe(&unmap_kretprobe);
return ret;
}
void unregister_helper(void)
{
- /* uninstall kretprobe with 'do_page_fault' */
- dbi_unregister_kretprobe(&pf_kretprobe);
+ /* uninstall kretprobe with 'handle_mm_fault' */
+ dbi_unregister_kretprobe(&mf_kretprobe);
+
+ /* uninstall kretprobe with 'do_mmap_pgoff' */
+ dbi_unregister_kretprobe(&mmap_kretprobe);
/* uninstall kretprobe with 'copy_process' */
dbi_unregister_kretprobe(&cp_kretprobe);
/* uninstall kprobe with 'mm_release' */
- dbi_unregister_kprobe(&mr_kprobe, NULL);
+ dbi_unregister_kprobe(&mr_kprobe);
- /* uninstall kprobe with 'do_munmap' */
- dbi_unregister_kprobe(&unmap_kprobe, NULL);
+ /* uninstall kretprobe with 'do_munmap' */
+ dbi_unregister_kretprobe(&unmap_kretprobe);
}
int init_helper(void)
{
unsigned long addr;
- addr = swap_ksyms("do_page_fault");
+ addr = swap_ksyms("handle_mm_fault");
if (addr == 0) {
- printk("Cannot find address for page fault function!\n");
+ printk("Cannot find address for handle_mm_fault function!\n");
return -EINVAL;
}
- pf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
+ mf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
addr = swap_ksyms("copy_process");
if (addr == 0) {
printk("Cannot find address for do_munmap function!\n");
return -EINVAL;
}
- unmap_kprobe.addr = (kprobe_opcode_t *)addr;
+ unmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
+
+ addr = swap_ksyms("do_mmap_pgoff");
+ if (addr == 0) {
+ printk("Cannot find address for do_mmap_pgoff function!\n");
+ return -EINVAL;
+ }
+ mmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
return 0;
}