From 371abe16ea1b1a70a92e393b3035821e9c7d6d6a Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 02:13:53 +0200 Subject: [PATCH 01/25] initial changes --- load.sh | 4 +- src/debug.h | 2 + src/files.c | 3 +- src/ftrace_helper.h | 215 ++++++++++++++++++++++++++++++++++++++++++ src/hook.c | 19 +++- src/lookup_symbols.py | 2 + src/memory.c | 163 +++++++++++++++++++++++++------- src/module.c | 39 +++++++- src/snapshot.c | 16 ++-- src/snapshot.h | 21 ++++- src/task_data.c | 27 +++++- test/test2.c | 61 ++++++++++++ 12 files changed, 513 insertions(+), 59 deletions(-) create mode 100644 src/ftrace_helper.h create mode 100644 test/test2.c diff --git a/load.sh b/load.sh index 10787ba..13a8ed5 100755 --- a/load.sh +++ b/load.sh @@ -1,5 +1,7 @@ #!/bin/sh +set -e -o pipefail + if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then echo "Warning: you need to be root to run this!" # we do not exit as other mechanisms exist that allows to do this than @@ -8,6 +10,6 @@ fi cd src/ -rmmod afl_snapshot +rmmod afl_snapshot || echo "Not loaded anyways..." make insmod afl_snapshot.ko && echo Successfully loaded the snapshot module diff --git a/src/debug.h b/src/debug.h index 2e3de44..0a534aa 100644 --- a/src/debug.h +++ b/src/debug.h @@ -54,5 +54,7 @@ #endif +#define PREEMPT_DEBUG(tag) SAYF("[%s():%s:%d] " tag " preempt_count() == %d\n", __FUNCTION__, __FILE__, __LINE__, preempt_count()) + #endif diff --git a/src/files.c b/src/files.c index bf80cb1..84d5bf2 100644 --- a/src/files.c +++ b/src/files.c @@ -57,7 +57,8 @@ void recover_files_snapshot(struct task_data *data) { DBG_PRINT("find new fds %d file* 0x%08lx\n", i, (unsigned long)file); // fdt->fd[i] = NULL; // filp_close(file, files); - __close_fd(files, i); + WARNF("closing doesn't work :(\n"); + // __close_fd(files, i); } diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h new file mode 100644 index 0000000..5b5f5de --- /dev/null +++ b/src/ftrace_helper.h @@ -0,0 +1,215 @@ +/* + * Helper library for ftrace hooking kernel functions + * Author: Harvey Phillips (xcellerator@gmx.com) + * License: GPL + * */ + +#include +#include +#include +#include +#include +#include "debug.h" + +#if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) +#define PTREGS_SYSCALL_STUBS 1 +#endif + +/* + * On Linux kernels 5.7+, kallsyms_lookup_name() is no longer exported, + * so we have to use kprobes to get the address. + * Full credit to @f0lg0 for the idea. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0) +#define KPROBE_LOOKUP 1 +#include +static struct kprobe kp = { + .symbol_name = "kallsyms_lookup_name" +}; +#endif + +/* x64 has to be special and require a different naming convention */ +#ifdef PTREGS_SYSCALL_STUBS +#define SYSCALL_NAME(name) ("__x64_" name) +#else +#define SYSCALL_NAME(name) (name) +#endif + +#define HOOK(_name, _hook, _orig) \ +{ \ + .name = (_name), \ + .function = (_hook), \ + .original = (_orig), \ +} + +#define SYSCALL_HOOK(_name, _hook, _orig) \ +{ \ + .name = SYSCALL_NAME(_name), \ + .function = (_hook), \ + .original = (_orig), \ +} + + +/* We need to prevent recursive loops when hooking, otherwise the kernel will + * panic and hang. The options are to either detect recursion by looking at + * the function return address, or by jumping over the ftrace call. We use the + * first option, by setting USE_FENTRY_OFFSET = 0, but could use the other by + * setting it to 1. (Oridinarily ftrace provides it's own protections against + * recursion, but it relies on saving return registers in $rip. We will likely + * need the use of the $rip register in our hook, so we have to disable this + * protection and implement our own). + * */ +#define USE_FENTRY_OFFSET 0 +#if !USE_FENTRY_OFFSET +#pragma GCC optimize("-fno-optimize-sibling-calls") +#endif + +/* We pack all the information we need (name, hooking function, original function) + * into this struct. This makes is easier for setting up the hook and just passing + * the entire struct off to fh_install_hook() later on. + * */ +struct ftrace_hook { + const char *name; + void *function; + void *original; + + unsigned long address; + struct ftrace_ops ops; +}; + +/* Ftrace needs to know the address of the original function that we + * are going to hook. As before, we just use kallsyms_lookup_name() + * to find the address in kernel memory. + * */ +static int fh_resolve_hook_address(struct ftrace_hook *hook) +{ +#ifdef KPROBE_LOOKUP + typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); + kallsyms_lookup_name_t kallsyms_lookup_name; + register_kprobe(&kp); + kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr; + unregister_kprobe(&kp); +#endif + hook->address = kallsyms_lookup_name(hook->name); + + if (!hook->address) + { + printk(KERN_DEBUG "rootkit: unresolved symbol: %s\n", hook->name); + return -ENOENT; + } + +#if USE_FENTRY_OFFSET + *((unsigned long*) hook->original) = hook->address + MCOUNT_INSN_SIZE; +#else + *((unsigned long*) hook->original) = hook->address; +#endif + + return 0; +} + +/* See comment below within fh_install_hook() */ +static void notrace fh_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct ftrace_regs *regs) +{ + struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); + +#if USE_FENTRY_OFFSET + regs->ip = (unsigned long) hook->function; +#else + if(!within_module(parent_ip, THIS_MODULE)) + regs->regs.ip = (unsigned long) hook->function; +#endif +} + +/* Assuming we've already set hook->name, hook->function and hook->original, we + * can go ahead and install the hook with ftrace. This is done by setting the + * ops field of hook (see the comment below for more details), and then using + * the built-in ftrace_set_filter_ip() and register_ftrace_function() functions + * provided by ftrace.h + * */ +int fh_install_hook(struct ftrace_hook *hook) +{ + int err; + err = fh_resolve_hook_address(hook); + if(err) + return err; + SAYF("Successfully resolved address 0x%lx for function %s\n", hook->address, hook->name); + + /* For many of function hooks (especially non-trivial ones), the $rip + * register gets modified, so we have to alert ftrace to this fact. This + * is the reason for the SAVE_REGS and IP_MODIFY flags. However, we also + * need to OR the RECURSION_SAFE flag (effectively turning if OFF) because + * the built-in anti-recursion guard provided by ftrace is useless if + * we're modifying $rip. This is why we have to implement our own checks + * (see USE_FENTRY_OFFSET). */ + hook->ops.func = fh_ftrace_thunk; + hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS + | FTRACE_OPS_FL_IPMODIFY; + + err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); + if(err) + { + printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err); + return err; + } + + err = register_ftrace_function(&hook->ops); + if(err) + { + printk(KERN_DEBUG "rootkit: register_ftrace_function() failed: %d\n", err); + return err; + } + + return 0; +} + +/* Disabling our function hook is just a simple matter of calling the built-in + * unregister_ftrace_function() and ftrace_set_filter_ip() functions (note the + * opposite order to that in fh_install_hook()). + * */ +void fh_remove_hook(struct ftrace_hook *hook) +{ + int err; + err = unregister_ftrace_function(&hook->ops); + if(err) + { + printk(KERN_DEBUG "rootkit: unregister_ftrace_function() failed: %d\n", err); + } + + err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0); + if(err) + { + printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err); + } +} + +/* To make it easier to hook multiple functions in one module, this provides + * a simple loop over an array of ftrace_hook struct + * */ +int fh_install_hooks(struct ftrace_hook *hooks, size_t count) +{ + int err; + size_t i; + + for (i = 0 ; i < count ; i++) + { + err = fh_install_hook(&hooks[i]); + if(err) + goto error; + } + return 0; + +error: + while (i != 0) + { + fh_remove_hook(&hooks[--i]); + } + return err; +} + +void fh_remove_hooks(struct ftrace_hook *hooks, size_t count) +{ + size_t i; + + for (i = 0 ; i < count ; i++) + fh_remove_hook(&hooks[i]); +} \ No newline at end of file diff --git a/src/hook.c b/src/hook.c index 9b39f79..21a48a6 100644 --- a/src/hook.c +++ b/src/hook.c @@ -1,13 +1,16 @@ #include #include +#include #include #include +#include "debug.h" // TODO(andrea) switch from Kprobes to Ftrace struct hook { struct kprobe kp; + struct ftrace_ops fops; struct list_head l; }; @@ -15,13 +18,17 @@ struct hook { LIST_HEAD(hooks); int try_hook(const char *func_name, void *handler) { - + SAYF("Hooking function %s\n", func_name); struct hook *hook = kmalloc(sizeof(struct hook), GFP_KERNEL | __GFP_ZERO); INIT_LIST_HEAD(&hook->l); hook->kp.symbol_name = func_name; hook->kp.pre_handler = handler; - - int ret = register_kprobe(&hook->kp); + hook->fops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY | FTRACE_OPS_FL_RECURSION; + hook->fops.func = handler; + ftrace_set_filter(&hook->fops, func_name, strlen(func_name), 0); + int ret = register_ftrace_function(&hook->fops); + SAYF("Hooked function: %d\n", ret); + // int ret = register_kprobe(&hook->kp); if (!ret) { list_add(&hook->l, &hooks); } return true; @@ -35,7 +42,8 @@ void unhook(const char *func_name) { if (!strcmp(hook->kp.symbol_name, func_name)) { - unregister_kprobe(&hook->kp); + // unregister_kprobe(&hook->kp); + unregister_ftrace_function(&hook->fops); } @@ -48,7 +56,8 @@ void unhook_all(void) { struct hook *hook = NULL; list_for_each_entry(hook, &hooks, l) { - unregister_kprobe(&hook->kp); + // unregister_kprobe(&hook->kp); + unregister_ftrace_function(&hook->fops); } diff --git a/src/lookup_symbols.py b/src/lookup_symbols.py index f7e8da9..14c41a4 100644 --- a/src/lookup_symbols.py +++ b/src/lookup_symbols.py @@ -13,6 +13,8 @@ system_map = map(lambda x: x.split(), fd.read().split('\n')) +# print("system_map:", list(system_map)) + register_chrdev_region = None sys_call_table = None sys_read = None diff --git a/src/memory.c b/src/memory.c index 24b381d..e608b85 100644 --- a/src/memory.c +++ b/src/memory.c @@ -6,6 +6,15 @@ static DEFINE_PER_CPU(struct task_struct *, last_task) = NULL; static DEFINE_PER_CPU(struct task_data *, last_data) = NULL; +// #define put_cpu_var_d(val) PREEMPT_DEBUG("before put " #val); put_cpu_var(val); PREEMPT_DEBUG("after put " #val); +#define put_cpu_var_d(val) put_cpu_var(val) + +#define preempt_debug_start int start_count = preempt_count(); +#define preempt_debug_end do { \ + int end_count = preempt_count(); \ + if (end_count != start_count) WARNF("[%s():%s:%d] preempt_count wrong, start = %d != %d = end\n", __FUNCTION__, __FILE__, __LINE__, start_count, end_count);\ +} while (0); + pmd_t *get_page_pmd(unsigned long addr) { pgd_t *pgd; @@ -201,6 +210,8 @@ struct snapshot_page *get_snapshot_page(struct task_data *data, struct snapshot_page *sp; + // SAYF("get_snapshot_page(%px, %px)\n", data->ss.) + hash_for_each_possible(data->ss.ss_page, sp, next, page_base) { if (sp->page_base == page_base) return sp; @@ -223,6 +234,7 @@ struct snapshot_page *add_snapshot_page(struct task_data *data, sp->page_base = page_base; sp->page_data = NULL; + // sp->next = NULL; hash_add(data->ss.ss_page, &sp->next, sp->page_base); } @@ -304,26 +316,32 @@ void take_memory_snapshot(struct task_data *data) { struct vm_area_struct *pvma = current->mm->mmap; unsigned long addr; + // preempt_debug_start + get_cpu_var(last_task) = NULL; - put_cpu_var(last_task); get_cpu_var(last_data) = NULL; - put_cpu_var(last_data); + put_cpu_var_d(last_task); + put_cpu_var_d(last_data); - struct vmrange_node *n = data->allowlist; - while (n) { + // preempt_debug_end - DBG_PRINT("Allowlist: 0x%08lx - 0x%08lx\n", n->start, n->end); - n = n->next; + // struct vmrange_node *n = data->allowlist; + // while (n) { - } + // DBG_PRINT("Allowlist: 0x%08lx - 0x%08lx\n", n->start, n->end); + // n = n->next; - n = data->blocklist; - while (n) { + // } - DBG_PRINT("Blocklist: 0x%08lx - 0x%08lx\n", n->start, n->end); - n = n->next; + // n = data->blocklist; + // while (n) { - } + // DBG_PRINT("Blocklist: 0x%08lx - 0x%08lx\n", n->start, n->end); + // n = n->next; + + // } + + // size_t count = 0; do { @@ -356,9 +374,12 @@ void take_memory_snapshot(struct task_data *data) { } pvma = pvma->vm_next; + // count++; } while (pvma != NULL); - + // if (count > 10) { + // SAYF("ya seem loaded: %d\n", count); + // } } void munmap_new_vmas(struct task_data *data) { @@ -451,6 +472,8 @@ void munmap_new_vmas(struct task_data *data) { } +#include + void do_recover_page(struct snapshot_page *sp) { DBG_PRINT( @@ -458,9 +481,9 @@ void do_recover_page(struct snapshot_page *sp) { "0x%08lx\n", (unsigned long)sp->page_data, (unsigned long)sp->page_base, sp->page_prot); - if (copy_to_user((void __user *)sp->page_base, sp->page_data, PAGE_SIZE) != 0) DBG_PRINT("incomplete copy_to_user\n"); + // copy_page(sp->page_base, sp->page_data); sp->dirty = false; } @@ -485,8 +508,10 @@ void recover_memory_snapshot(struct task_data *data) { if (data->config & AFL_SNAPSHOT_MMAP) munmap_new_vmas(data); - hash_for_each(data->ss.ss_page, i, sp, next) { - + // hash_for_each(data->ss.ss_page, i, sp, next) { + struct list_head* ptr; + for (ptr = data->ss.dirty_pages.next; ptr != &data->ss.dirty_pages; ptr = ptr->next){ + sp = list_entry(ptr, struct snapshot_page, dirty_list); if (sp->dirty && sp->has_been_copied) { // it has been captured by page fault @@ -510,7 +535,7 @@ void recover_memory_snapshot(struct task_data *data) { } - } else if (is_snapshot_page_private(sp)) { + // } else if (is_snapshot_page_private(sp)) { // private page that has not been captured // still write protected @@ -526,6 +551,10 @@ void recover_memory_snapshot(struct task_data *data) { } + // haha this is really dumb + // surely this will not come back to bite me later, right?? + INIT_LIST_HEAD(&data->ss.dirty_pages); + } void clean_snapshot_vmas(struct task_data *data) { @@ -551,24 +580,51 @@ void clean_memory_snapshot(struct task_data *data) { struct snapshot_page *sp; int i; - if (get_cpu_var(last_task) == current) { + // SAYF("clean_memory_snapshot initial (PID: %d)\n", current->pid); + // dump_stack(); + + preempt_debug_start + + struct task_struct* ltask = get_cpu_var(last_task); + if (ltask == current) { get_cpu_var(last_task) = NULL; get_cpu_var(last_data) = NULL; - + put_cpu_var_d(last_task); + put_cpu_var_d(last_data); } + put_cpu_var_d(last_task); - put_cpu_var(last_task); - put_cpu_var(last_data); + preempt_debug_end if (data->config & AFL_SNAPSHOT_MMAP) clean_snapshot_vmas(data); + // SAYF("clean_memory_snapshot after snapshot vmas\n"); + + struct snapshot_page *prev_sp = NULL; // we need to always be a single item behind, otherwise I think we have a use after free! + hash_for_each(data->ss.ss_page, i, sp, next) { + if (prev_sp != NULL) { + hash_del(&prev_sp->next); + kfree(prev_sp); + prev_sp = NULL; + } + + // if (sp == NULL) SAYF("dafuq, sp == NULL for %d\n", i); + + // SAYF("BKT %i, sp %px, page_base %px, page_data %px\n", i, sp, sp->page_base, sp->page_data); if (sp->page_data != NULL) kfree(sp->page_data); - kfree(sp); + // SAYF("maybe freed sp->page_data\n"); + prev_sp = sp; + // if (sp != NULL) kfree(sp); + } + if (prev_sp != NULL) { + hash_del(&prev_sp->next); + kfree(prev_sp); + prev_sp = NULL; } } @@ -579,7 +635,8 @@ static long return_0_stub_func(void) { } -int wp_page_hook(struct kprobe *p, struct pt_regs *regs) { +int wp_page_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *regs) { struct vm_fault * vmf; struct mm_struct * mm; @@ -589,26 +646,49 @@ int wp_page_hook(struct kprobe *p, struct pt_regs *regs) { pte_t entry; char * vfrom; - vmf = (struct vm_fault *)regs->di; + + + vmf = (struct vm_fault *)regs->regs.di; + // SAYF("HAD FAULT: %px\n", vmf->address); + // return 0; mm = vmf->vma->vm_mm; ss_page = NULL; + // SAYF("OWNER: %s (pid %d)\n", mm->owner->comm, mm->owner->pid); + // #ifdef CONFIG_PREEMPT_COUNT + // SAYF("Counting number preempts!\n"); + // #endif + // return 0; + // preempt_debug_start - if (get_cpu_var(last_task) == mm->owner) { + struct task_struct* ltask = get_cpu_var(last_task); + if (ltask == mm->owner) { // fast path data = get_cpu_var(last_data); - + put_cpu_var_d(last_task); + put_cpu_var_d(last_data); } else { // query the radix tree data = get_task_data(mm->owner); get_cpu_var(last_task) = mm->owner; get_cpu_var(last_data) = data; + put_cpu_var_d(last_task); + put_cpu_var_d(last_task); + put_cpu_var_d(last_data); } - put_cpu_var(last_task); - put_cpu_var(last_data); // not needed? + // preempt_debug_end + + // SAYF("Did find data: %px\n", data); + + // return 0; + + // put_cpu_var(last_task); + // put_cpu_var(last_data); // not needed? + + // return 0; if (data && have_snapshot(data)) { @@ -628,6 +708,7 @@ int wp_page_hook(struct kprobe *p, struct pt_regs *regs) { if (ss_page->dirty) return 0; ss_page->dirty = true; + list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); DBG_PRINT("wp_page_hook 0x%08lx", vmf->address); @@ -675,7 +756,7 @@ int wp_page_hook(struct kprobe *p, struct pt_regs *regs) { pte_unmap_unlock(vmf->pte, vmf->ptl); // skip original function - regs->ip = (long unsigned int)&return_0_stub_func; + regs->regs.ip = (long unsigned int)&return_0_stub_func; return 1; } @@ -686,7 +767,8 @@ int wp_page_hook(struct kprobe *p, struct pt_regs *regs) { // actually hooking page_add_new_anon_rmap, but we really only care about calls // from do_anonymous_page -int do_anonymous_hook(struct kprobe *p, struct pt_regs *regs) { +int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *regs) { struct vm_area_struct *vma; struct mm_struct * mm; @@ -694,27 +776,33 @@ int do_anonymous_hook(struct kprobe *p, struct pt_regs *regs) { struct snapshot_page * ss_page; unsigned long address; - vma = (struct vm_area_struct *)regs->si; - address = regs->dx; + vma = (struct vm_area_struct *)regs->regs.si; + address = regs->regs.dx; mm = vma->vm_mm; ss_page = NULL; - if (get_cpu_var(last_task) == mm->owner) { + preempt_debug_start + + struct task_struct* ltask = get_cpu_var(last_task); + if (ltask == mm->owner) { // fast path data = get_cpu_var(last_data); - + put_cpu_var_d(last_task); + put_cpu_var_d(last_data); } else { // query the radix tree data = get_task_data(mm->owner); get_cpu_var(last_task) = mm->owner; get_cpu_var(last_data) = data; + put_cpu_var_d(last_task); + put_cpu_var_d(last_task); + put_cpu_var_d(last_data); } - put_cpu_var(last_task); - put_cpu_var(last_data); // not needed? + preempt_debug_end if (data && have_snapshot(data)) { @@ -737,6 +825,9 @@ int do_anonymous_hook(struct kprobe *p, struct pt_regs *regs) { // HAVE PTE NOW ss_page->has_had_pte = true; + if (is_snapshot_page_none_pte(ss_page)) { + list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); + } return 0; diff --git a/src/module.c b/src/module.c index e3303b6..ad775d8 100644 --- a/src/module.c +++ b/src/module.c @@ -18,6 +18,7 @@ #include "snapshot.h" // main implementation #include "debug.h" #include "symbols.h" +#include "ftrace_helper.h" #include "afl_snapshot.h" @@ -129,7 +130,7 @@ static struct file_operations dev_fops = { }; -#ifdef ARCH_HAS_SYSCALL_WRAPPER +#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER typedef int (*syscall_handler_t)(struct pt_regs *); // The original syscall handler that we removed to override exit_group() @@ -144,6 +145,16 @@ syscall_handler_t orig_sct_exit_group = NULL; asmlinkage int sys_exit_group(struct pt_regs *regs) { + // SAYF("hooked sys_exit_group(%p)\n", regs); + // enum show_regs_mode print_kernel_regs; + + // show_regs_print_info(LOGLEVEL_INFO); + + // print_kernel_regs = user_mode(regs) ? SHOW_REGS_USER : SHOW_REGS_ALL; + // __show_regs(regs, print_kernel_regs, LOGLEVEL_INFO); + // int ret = exit_snapshot(); + // SAYF("exit_snapshot() = %d\n", ret); + // return orig_sct_exit_group(regs); if (exit_snapshot()) return orig_sct_exit_group(regs); return 0; @@ -156,13 +167,21 @@ typedef long (*syscall_handler_t)(int error_code); syscall_handler_t orig_sct_exit_group = NULL; asmlinkage long sys_exit_group(int error_code) { - + SAYF("hooked sys_exit_group(%d)\n", error_code); + int ret = exit_snapshot(); + SAYF("exit_snapshot() = %d\n", ret); + return orig_sct_exit_group(error_code); if (exit_snapshot()) return orig_sct_exit_group(error_code); return 0; } #endif + +static struct ftrace_hook syscall_hooks[] = { + SYSCALL_HOOK("sys_exit_group", sys_exit_group, &orig_sct_exit_group), +}; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) /* rename since Linux 5.8 */ #define probe_kernel_read copy_from_kernel_nofault #endif @@ -300,7 +319,14 @@ static int __init mod_init(void) { } - patch_syscall_table(); + // patch_syscall_table(); + // return 0; + int err; + err = fh_install_hooks(syscall_hooks, ARRAY_SIZE(syscall_hooks)); + if(err) + return err; + + // return 0; // func hooks if (!try_hook("do_wp_page", &wp_page_hook)) { @@ -322,6 +348,8 @@ static int __init mod_init(void) { } + // return 0; + if (!try_hook("do_exit", &exit_hook)) { FATAL("Unable to hook do_exit"); @@ -348,8 +376,11 @@ static void __exit mod_exit(void) { class_destroy(mod_class); unregister_chrdev(mod_major_num, DEVICE_NAME); + // return; + unhook_all(); - unpatch_syscall_table(); + // unpatch_syscall_table(); + fh_remove_hooks(syscall_hooks, ARRAY_SIZE(syscall_hooks)); } diff --git a/src/snapshot.c b/src/snapshot.c index faa32f3..05d7a8b 100644 --- a/src/snapshot.c +++ b/src/snapshot.c @@ -3,8 +3,9 @@ #include "task_data.h" #include "snapshot.h" -int exit_hook(struct kprobe *p, struct pt_regs *regs) { - +int exit_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *regs) { + // PREEMPT_DEBUG("before clean_snapshot"); clean_snapshot(); return 0; @@ -44,7 +45,7 @@ int take_snapshot(int config) { initialize_snapshot(data, config); take_memory_snapshot(data); - take_files_snapshot(data); + // take_files_snapshot(data); return 1; @@ -74,7 +75,7 @@ void restore_snapshot(struct task_data *data) { recover_threads_snapshot(data); recover_memory_snapshot(data); - recover_files_snapshot(data); + // recover_files_snapshot(data); recover_state(data); } @@ -87,8 +88,11 @@ void recover_snapshot(void) { } int exit_snapshot(void) { - + // SAYF("Entered exit_snapshot, current task: %p\n", current); + // SAYF("The process is \"%s\" (pid %i)\n", current->comm, current->pid); struct task_data *data = get_task_data(current); + // SAYF("Found task data: %p (%d)\n", data, data->config); + // return 1; if (data && (data->config & AFL_SNAPSHOT_EXIT) && have_snapshot(data)) { restore_snapshot(data); @@ -108,7 +112,7 @@ void clean_snapshot(void) { if (!data) { return; } clean_memory_snapshot(data); - clean_files_snapshot(data); + // clean_files_snapshot(data); clear_snapshot(data); remove_task_data(data); diff --git a/src/snapshot.h b/src/snapshot.h index afb03f2..32a269b 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -37,7 +37,9 @@ #include #include #include +#undef MODULE #include +#define MODULE 1 #include #include #include @@ -85,13 +87,17 @@ #include #include +#undef MODULE #include #include #include #include -#include + #include +#include +#define MODULE 1 #include +#include #include "afl_snapshot.h" @@ -124,6 +130,8 @@ struct snapshot_page { struct hlist_node next; + struct list_head dirty_list; + }; #define SNAPSHOT_PRIVATE 0x00000001 @@ -179,6 +187,8 @@ struct snapshot { DECLARE_HASHTABLE(ss_page, SNAPSHOT_HASHTABLE_SZ); + struct list_head dirty_pages; + }; #define SNAPSHOT_NONE 0x00000000 // outside snapshot @@ -205,9 +215,12 @@ void recover_threads_snapshot(struct task_data *data); int snapshot_initialize_k_funcs(void); -int wp_page_hook(struct kprobe *p, struct pt_regs *regs); -int do_anonymous_hook(struct kprobe *p, struct pt_regs *regs); -int exit_hook(struct kprobe *p, struct pt_regs *regs); +int wp_page_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *regs); +int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *regs); +int exit_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *regs); int take_snapshot(int config); void recover_snapshot(void); diff --git a/src/task_data.c b/src/task_data.c index 01c21c0..34119c1 100644 --- a/src/task_data.c +++ b/src/task_data.c @@ -1,5 +1,6 @@ #include "task_data.h" #include +#include "debug.h" LIST_HEAD(task_datas); static spinlock_t task_datas_lock; @@ -7,15 +8,32 @@ static spinlock_t task_datas_lock; static void task_data_free_callback(struct rcu_head *rcu) { struct task_data *data = container_of(rcu, struct task_data, rcu); - kfree(data); + // should probably free all the other stuff here too? + struct vmrange_node *n = data->blocklist; + while (n) { + data->blocklist = n->next; + kfree(n); + n = data->blocklist; + } + data->blocklist = NULL; + n = data->allowlist; + while (n) { + data->allowlist = n->next; + kfree(n); + n = data->allowlist; + } + data->allowlist = NULL; + kfree(data); } struct task_data *get_task_data(const struct task_struct *tsk) { - + // SAYF("entered get_task_data(%p)\n", tsk); struct task_data *data = NULL; + // return NULL; rcu_read_lock(); + // SAYF("rcu_read_lock ok\n"); list_for_each_entry_rcu(data, &task_datas, list) { if (data->tsk == tsk) { @@ -27,8 +45,12 @@ struct task_data *get_task_data(const struct task_struct *tsk) { } + // SAYF("list_foreach_done\n"); + rcu_read_unlock(); + // SAYF("rcu_read_unlock ok\n"); + return NULL; } @@ -43,6 +65,7 @@ struct task_data *ensure_task_data(const struct task_struct *tsk) { if (!data) return NULL; data->tsk = tsk; + INIT_LIST_HEAD(&data->ss.dirty_pages); spin_lock(&task_datas_lock); list_add_rcu(&data->list, &task_datas); diff --git a/test/test2.c b/test/test2.c new file mode 100644 index 0000000..e4edb15 --- /dev/null +++ b/test/test2.c @@ -0,0 +1,61 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libaflsnapshot.h" + +// gcc -I ../include -g ../lib/libaflsnapshot.o test2.c -o test2 + +int* shm_addr; +int* none_addr; + +int pippo = 1; + +void test2() { + + if (afl_snapshot_take(AFL_SNAPSHOT_NOSTACK) == 1) + fprintf(stderr, "first time!\n"); + +loop: + + *none_addr += 1; + *shm_addr += 1; + fprintf(stderr, ">> %d %p = %d %p = %d\n", pippo, none_addr, *none_addr, shm_addr, *shm_addr); + ++pippo; + + afl_snapshot_restore(); + goto loop; + +} + +int main() { + + afl_snapshot_init(); + + shm_addr = mmap(0, 0x10000, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED | MAP_ANONYMOUS, 0, 0); + + none_addr = mmap((void *)0, 0x1000, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + afl_snapshot_exclude_vmrange((unsigned long)none_addr, (unsigned long)(none_addr + (0x1000/4))); + afl_snapshot_include_vmrange((unsigned long)shm_addr, (unsigned long)(shm_addr + (0x10000/4))); + + *shm_addr = 0; + + test2(); + + return 0; + +} + + From aec5a50ab3be4096a9f042a8483a60101fd676e4 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 02:16:26 +0200 Subject: [PATCH 02/25] add perf improvements --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1fe921e..8913b77 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ however adding this snapshot module will still be a small improvement. |tiff|thumbnail|5058|3114|x1.6| |libxml|xmllint|7835|3450|x2.3| |afl++|test_persistent_new|106k|89k|x1.2| +|afl++|emmu_fuzz|10k-20k|40|x250-x500| ## Usage From d334f86bd0e4d4b3954b4e06f0d1310ac99680a4 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 02:27:01 +0200 Subject: [PATCH 03/25] cleanup --- src/memory.c | 124 +++++++++++++++--------------------------------- src/module.c | 92 +---------------------------------- src/snapshot.c | 5 -- src/task_data.c | 9 +--- 4 files changed, 40 insertions(+), 190 deletions(-) diff --git a/src/memory.c b/src/memory.c index e608b85..d110e71 100644 --- a/src/memory.c +++ b/src/memory.c @@ -6,15 +6,6 @@ static DEFINE_PER_CPU(struct task_struct *, last_task) = NULL; static DEFINE_PER_CPU(struct task_data *, last_data) = NULL; -// #define put_cpu_var_d(val) PREEMPT_DEBUG("before put " #val); put_cpu_var(val); PREEMPT_DEBUG("after put " #val); -#define put_cpu_var_d(val) put_cpu_var(val) - -#define preempt_debug_start int start_count = preempt_count(); -#define preempt_debug_end do { \ - int end_count = preempt_count(); \ - if (end_count != start_count) WARNF("[%s():%s:%d] preempt_count wrong, start = %d != %d = end\n", __FUNCTION__, __FILE__, __LINE__, start_count, end_count);\ -} while (0); - pmd_t *get_page_pmd(unsigned long addr) { pgd_t *pgd; @@ -210,8 +201,6 @@ struct snapshot_page *get_snapshot_page(struct task_data *data, struct snapshot_page *sp; - // SAYF("get_snapshot_page(%px, %px)\n", data->ss.) - hash_for_each_possible(data->ss.ss_page, sp, next, page_base) { if (sp->page_base == page_base) return sp; @@ -234,7 +223,6 @@ struct snapshot_page *add_snapshot_page(struct task_data *data, sp->page_base = page_base; sp->page_data = NULL; - // sp->next = NULL; hash_add(data->ss.ss_page, &sp->next, sp->page_base); } @@ -316,32 +304,30 @@ void take_memory_snapshot(struct task_data *data) { struct vm_area_struct *pvma = current->mm->mmap; unsigned long addr; - // preempt_debug_start - get_cpu_var(last_task) = NULL; get_cpu_var(last_data) = NULL; - put_cpu_var_d(last_task); - put_cpu_var_d(last_data); + put_cpu_var(last_task); + put_cpu_var(last_data); - // preempt_debug_end - - // struct vmrange_node *n = data->allowlist; - // while (n) { - - // DBG_PRINT("Allowlist: 0x%08lx - 0x%08lx\n", n->start, n->end); - // n = n->next; + // Only do loops if DBG_PRINT actually does something. + // Not sure if compiler would be smart enough to eliminate these anyways. + #if DEBUG + struct vmrange_node *n = data->allowlist; + while (n) { - // } + DBG_PRINT("Allowlist: 0x%08lx - 0x%08lx\n", n->start, n->end); + n = n->next; - // n = data->blocklist; - // while (n) { + } - // DBG_PRINT("Blocklist: 0x%08lx - 0x%08lx\n", n->start, n->end); - // n = n->next; + n = data->blocklist; + while (n) { - // } + DBG_PRINT("Blocklist: 0x%08lx - 0x%08lx\n", n->start, n->end); + n = n->next; - // size_t count = 0; + } + #endif do { @@ -374,12 +360,8 @@ void take_memory_snapshot(struct task_data *data) { } pvma = pvma->vm_next; - // count++; } while (pvma != NULL); - // if (count > 10) { - // SAYF("ya seem loaded: %d\n", count); - // } } void munmap_new_vmas(struct task_data *data) { @@ -472,8 +454,6 @@ void munmap_new_vmas(struct task_data *data) { } -#include - void do_recover_page(struct snapshot_page *sp) { DBG_PRINT( @@ -483,7 +463,6 @@ void do_recover_page(struct snapshot_page *sp) { sp->page_prot); if (copy_to_user((void __user *)sp->page_base, sp->page_data, PAGE_SIZE) != 0) DBG_PRINT("incomplete copy_to_user\n"); - // copy_page(sp->page_base, sp->page_data); sp->dirty = false; } @@ -507,7 +486,12 @@ void recover_memory_snapshot(struct task_data *data) { int i; if (data->config & AFL_SNAPSHOT_MMAP) munmap_new_vmas(data); - + // Instead of iterating over all pages in the snapshot and then restoring the dirty ones, + // we can save a lot of computing time by keeping a list of only dirty pages. + // Since we know exactly when pages match the conditions below, we can just insert them into the dirty list then. + // This had a massive boost on performance for me, >50%. (Might be more or less depending on a few factors). + // + // original loop below // hash_for_each(data->ss.ss_page, i, sp, next) { struct list_head* ptr; for (ptr = data->ss.dirty_pages.next; ptr != &data->ss.dirty_pages; ptr = ptr->next){ @@ -580,28 +564,20 @@ void clean_memory_snapshot(struct task_data *data) { struct snapshot_page *sp; int i; - // SAYF("clean_memory_snapshot initial (PID: %d)\n", current->pid); - // dump_stack(); - - preempt_debug_start - struct task_struct* ltask = get_cpu_var(last_task); if (ltask == current) { get_cpu_var(last_task) = NULL; get_cpu_var(last_data) = NULL; - put_cpu_var_d(last_task); - put_cpu_var_d(last_data); + put_cpu_var(last_task); + put_cpu_var(last_data); } - put_cpu_var_d(last_task); - - preempt_debug_end + put_cpu_var(last_task); if (data->config & AFL_SNAPSHOT_MMAP) clean_snapshot_vmas(data); - // SAYF("clean_memory_snapshot after snapshot vmas\n"); - - struct snapshot_page *prev_sp = NULL; // we need to always be a single item behind, otherwise I think we have a use after free! + // we need to always be a single item behind, otherwise we have a use after free! + struct snapshot_page *prev_sp = NULL; hash_for_each(data->ss.ss_page, i, sp, next) { if (prev_sp != NULL) { @@ -610,15 +586,8 @@ void clean_memory_snapshot(struct task_data *data) { prev_sp = NULL; } - // if (sp == NULL) SAYF("dafuq, sp == NULL for %d\n", i); - - // SAYF("BKT %i, sp %px, page_base %px, page_data %px\n", i, sp, sp->page_base, sp->page_data); - if (sp->page_data != NULL) kfree(sp->page_data); - - // SAYF("maybe freed sp->page_data\n"); prev_sp = sp; - // if (sp != NULL) kfree(sp); } if (prev_sp != NULL) { @@ -649,47 +618,28 @@ int wp_page_hook(unsigned long ip, unsigned long parent_ip, vmf = (struct vm_fault *)regs->regs.di; - // SAYF("HAD FAULT: %px\n", vmf->address); - // return 0; mm = vmf->vma->vm_mm; ss_page = NULL; - // SAYF("OWNER: %s (pid %d)\n", mm->owner->comm, mm->owner->pid); - // #ifdef CONFIG_PREEMPT_COUNT - // SAYF("Counting number preempts!\n"); - // #endif - // return 0; - // preempt_debug_start struct task_struct* ltask = get_cpu_var(last_task); if (ltask == mm->owner) { // fast path data = get_cpu_var(last_data); - put_cpu_var_d(last_task); - put_cpu_var_d(last_data); + put_cpu_var(last_task); + put_cpu_var(last_data); } else { // query the radix tree data = get_task_data(mm->owner); get_cpu_var(last_task) = mm->owner; get_cpu_var(last_data) = data; - put_cpu_var_d(last_task); - put_cpu_var_d(last_task); - put_cpu_var_d(last_data); + put_cpu_var(last_task); + put_cpu_var(last_task); + put_cpu_var(last_data); } - // preempt_debug_end - - // SAYF("Did find data: %px\n", data); - - // return 0; - - // put_cpu_var(last_task); - // put_cpu_var(last_data); // not needed? - - // return 0; - if (data && have_snapshot(data)) { ss_page = get_snapshot_page(data, vmf->address & PAGE_MASK); @@ -788,17 +738,17 @@ int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, // fast path data = get_cpu_var(last_data); - put_cpu_var_d(last_task); - put_cpu_var_d(last_data); + put_cpu_var(last_task); + put_cpu_var(last_data); } else { // query the radix tree data = get_task_data(mm->owner); get_cpu_var(last_task) = mm->owner; get_cpu_var(last_data) = data; - put_cpu_var_d(last_task); - put_cpu_var_d(last_task); - put_cpu_var_d(last_data); + put_cpu_var(last_task); + put_cpu_var(last_task); + put_cpu_var(last_data); } diff --git a/src/module.c b/src/module.c index ad775d8..f63f764 100644 --- a/src/module.c +++ b/src/module.c @@ -167,10 +167,7 @@ typedef long (*syscall_handler_t)(int error_code); syscall_handler_t orig_sct_exit_group = NULL; asmlinkage long sys_exit_group(int error_code) { - SAYF("hooked sys_exit_group(%d)\n", error_code); - int ret = exit_snapshot(); - SAYF("exit_snapshot() = %d\n", ret); - return orig_sct_exit_group(error_code); + if (exit_snapshot()) return orig_sct_exit_group(error_code); return 0; @@ -186,76 +183,7 @@ static struct ftrace_hook syscall_hooks[] = { #define probe_kernel_read copy_from_kernel_nofault #endif -static void **get_syscall_table(void) { - - void **syscall_table = NULL; - - syscall_table = (void**)SYMADDR_sys_call_table; - - if (syscall_table) { return syscall_table; } - - int i; - unsigned long long s0 = SYMADDR_sys_read; - unsigned long long s1 = SYMADDR_sys_read; - - unsigned long long *data = - (unsigned long long *)(SYMADDR__etext & ~0x7); - for (i = 0; (unsigned long long)(&data[i]) < ULLONG_MAX; i++) { - - unsigned long long d; - // use probe_kernel_read so we don't fault - if (probe_kernel_read(&d, &data[i], sizeof(d))) { continue; } - - if (d == s0 && data[i + 1] == s1) { - - syscall_table = (void **)(&data[i]); - break; - - } - - } - - return syscall_table; - -} - -static void _write_cr0(unsigned long val) { - - asm volatile("mov %0,%%cr0" : "+r"(val)); - -} - -static void enable_write_protection(void) { - - _write_cr0(read_cr0() | (1 << 16)); - -} - -static void disable_write_protection(void) { - - _write_cr0(read_cr0() & (~(1 << 16))); - -} - -static void **syscall_table_ptr; - -static void patch_syscall_table(void) { - - disable_write_protection(); - orig_sct_exit_group = syscall_table_ptr[__NR_exit_group]; - syscall_table_ptr[__NR_exit_group] = &sys_exit_group; - enable_write_protection(); - -} - -static void unpatch_syscall_table(void) { - - disable_write_protection(); - syscall_table_ptr[__NR_exit_group] = orig_sct_exit_group; - enable_write_protection(); - -} - +// TODO(galli-leo): we should be able to just use kallsyms_lookup_name now. int snapshot_initialize_k_funcs() { k_flush_tlb_mm_range = (void *)SYMADDR_flush_tlb_mm_range; @@ -310,24 +238,11 @@ static int __init mod_init(void) { SAYF("The major device number is %d", mod_major_num); - // syscall_table overwrites - syscall_table_ptr = get_syscall_table(); - if (!syscall_table_ptr) { - - FATAL("Unable to locate syscall_table"); - return -ENOENT; - - } - - // patch_syscall_table(); - // return 0; int err; err = fh_install_hooks(syscall_hooks, ARRAY_SIZE(syscall_hooks)); if(err) return err; - // return 0; - // func hooks if (!try_hook("do_wp_page", &wp_page_hook)) { @@ -376,10 +291,7 @@ static void __exit mod_exit(void) { class_destroy(mod_class); unregister_chrdev(mod_major_num, DEVICE_NAME); - // return; - unhook_all(); - // unpatch_syscall_table(); fh_remove_hooks(syscall_hooks, ARRAY_SIZE(syscall_hooks)); } diff --git a/src/snapshot.c b/src/snapshot.c index 05d7a8b..55405bd 100644 --- a/src/snapshot.c +++ b/src/snapshot.c @@ -5,7 +5,6 @@ int exit_hook(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *regs) { - // PREEMPT_DEBUG("before clean_snapshot"); clean_snapshot(); return 0; @@ -88,11 +87,7 @@ void recover_snapshot(void) { } int exit_snapshot(void) { - // SAYF("Entered exit_snapshot, current task: %p\n", current); - // SAYF("The process is \"%s\" (pid %i)\n", current->comm, current->pid); struct task_data *data = get_task_data(current); - // SAYF("Found task data: %p (%d)\n", data, data->config); - // return 1; if (data && (data->config & AFL_SNAPSHOT_EXIT) && have_snapshot(data)) { restore_snapshot(data); diff --git a/src/task_data.c b/src/task_data.c index 34119c1..08dd62c 100644 --- a/src/task_data.c +++ b/src/task_data.c @@ -8,7 +8,6 @@ static spinlock_t task_datas_lock; static void task_data_free_callback(struct rcu_head *rcu) { struct task_data *data = container_of(rcu, struct task_data, rcu); - // should probably free all the other stuff here too? struct vmrange_node *n = data->blocklist; while (n) { data->blocklist = n->next; @@ -28,12 +27,9 @@ static void task_data_free_callback(struct rcu_head *rcu) { } struct task_data *get_task_data(const struct task_struct *tsk) { - // SAYF("entered get_task_data(%p)\n", tsk); struct task_data *data = NULL; - // return NULL; rcu_read_lock(); - // SAYF("rcu_read_lock ok\n"); list_for_each_entry_rcu(data, &task_datas, list) { if (data->tsk == tsk) { @@ -45,12 +41,8 @@ struct task_data *get_task_data(const struct task_struct *tsk) { } - // SAYF("list_foreach_done\n"); - rcu_read_unlock(); - // SAYF("rcu_read_unlock ok\n"); - return NULL; } @@ -61,6 +53,7 @@ struct task_data *ensure_task_data(const struct task_struct *tsk) { if (data) return data; // XXX: this is academic code (tm) so if we run out of memory, too bad! + // TODO: Not sure if this is still the case? should be freed correctly. data = kmalloc(sizeof(struct task_data), GFP_KERNEL | __GFP_ZERO); if (!data) return NULL; From 64bc2881c3be63f4a6d328e2df30d61cea451265 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 02:27:33 +0200 Subject: [PATCH 04/25] update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8913b77..d32d4ad 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ however adding this snapshot module will still be a small improvement. |afl++|test_persistent_new|106k|89k|x1.2| |afl++|emmu_fuzz|10k-20k|40|x250-x500| +**TODO:** Rerun the others with improved version? + ## Usage Load it using `./load.sh`, unload it using `./unload.sh`. From a496c42d6741c93bf2013215a5467a52c99c2d14 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 02:43:37 +0200 Subject: [PATCH 05/25] missed one --- src/memory.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/memory.c b/src/memory.c index d110e71..9649052 100644 --- a/src/memory.c +++ b/src/memory.c @@ -731,8 +731,6 @@ int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, mm = vma->vm_mm; ss_page = NULL; - preempt_debug_start - struct task_struct* ltask = get_cpu_var(last_task); if (ltask == mm->owner) { @@ -752,8 +750,6 @@ int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, } - preempt_debug_end - if (data && have_snapshot(data)) { ss_page = get_snapshot_page(data, address & PAGE_MASK); From 51191b61284fc7e7ea9aff35ccfbc86ad73f3063 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 22:30:03 +0200 Subject: [PATCH 06/25] fix --- src/module.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/module.c b/src/module.c index f63f764..c5c6ff7 100644 --- a/src/module.c +++ b/src/module.c @@ -247,7 +247,7 @@ static int __init mod_init(void) { if (!try_hook("do_wp_page", &wp_page_hook)) { FATAL("Unable to hook do_wp_page"); - unpatch_syscall_table(); + // unpatch_syscall_table(); return -ENOENT; @@ -258,7 +258,7 @@ static int __init mod_init(void) { FATAL("Unable to hook page_add_new_anon_rmap"); unhook_all(); - unpatch_syscall_table(); + // unpatch_syscall_table(); return -ENOENT; } @@ -270,7 +270,7 @@ static int __init mod_init(void) { FATAL("Unable to hook do_exit"); unhook_all(); - unpatch_syscall_table(); + // unpatch_syscall_table(); return -ENOENT; } From e046a8d3cc4d601dfe88bb0011966849001e6936 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 22:37:42 +0200 Subject: [PATCH 07/25] remove need for python script --- src/Makefile | 3 +-- src/module.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Makefile b/src/Makefile index 739e698..65009b8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -46,10 +46,9 @@ endif LINUX_DIR ?= /lib/modules/$(shell uname -r)/build .PHONY: all +# env ARCH='$(ARCH)' LINUX_SYSTEM_MAP='$(LINUX_SYSTEM_MAP)' python3 lookup_symbols.py all: - env ARCH='$(ARCH)' LINUX_SYSTEM_MAP='$(LINUX_SYSTEM_MAP)' python3 lookup_symbols.py - $(MAKE) -C '$(LINUX_DIR)' M='$(M)' modules clean: diff --git a/src/module.c b/src/module.c index c5c6ff7..413ae3c 100644 --- a/src/module.c +++ b/src/module.c @@ -17,7 +17,7 @@ #include "hook.h" // function hooking #include "snapshot.h" // main implementation #include "debug.h" -#include "symbols.h" +// #include "symbols.h" #include "ftrace_helper.h" #include "afl_snapshot.h" @@ -186,8 +186,8 @@ static struct ftrace_hook syscall_hooks[] = { // TODO(galli-leo): we should be able to just use kallsyms_lookup_name now. int snapshot_initialize_k_funcs() { - k_flush_tlb_mm_range = (void *)SYMADDR_flush_tlb_mm_range; - k_zap_page_range = (void *)SYMADDR_zap_page_range; + k_flush_tlb_mm_range = (void *)kallsyms_lookup_name("flush_tlb_mm_range"); + k_zap_page_range = (void *)kallsyms_lookup_name("zap_page_range"); if (!k_flush_tlb_mm_range || !k_zap_page_range) { return -ENOENT; } From af0d1fb631ed85adc99ab5421161a8e94f6fe790 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 22:40:11 +0200 Subject: [PATCH 08/25] fix --- src/ftrace_helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h index 5b5f5de..9af3a50 100644 --- a/src/ftrace_helper.h +++ b/src/ftrace_helper.h @@ -26,6 +26,8 @@ static struct kprobe kp = { .symbol_name = "kallsyms_lookup_name" }; +typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); +kallsyms_lookup_name_t kallsyms_lookup_name; #endif /* x64 has to be special and require a different naming convention */ @@ -84,8 +86,6 @@ struct ftrace_hook { static int fh_resolve_hook_address(struct ftrace_hook *hook) { #ifdef KPROBE_LOOKUP - typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); - kallsyms_lookup_name_t kallsyms_lookup_name; register_kprobe(&kp); kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr; unregister_kprobe(&kp); From c1424ffe4b45a32302d7e25bb14534d6845c7b94 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 22:41:20 +0200 Subject: [PATCH 09/25] fix --- src/ftrace_helper.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h index 9af3a50..2e9c108 100644 --- a/src/ftrace_helper.h +++ b/src/ftrace_helper.h @@ -27,7 +27,8 @@ static struct kprobe kp = { .symbol_name = "kallsyms_lookup_name" }; typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); -kallsyms_lookup_name_t kallsyms_lookup_name; +kallsyms_lookup_name_t kallsyms_lookup_name_var; +#define kallsyms_lookup_name kallsyms_lookup_name_var; #endif /* x64 has to be special and require a different naming convention */ From 952897b64a40baa7e1f432b71bab64c8e250095c Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 22:42:33 +0200 Subject: [PATCH 10/25] fix --- src/ftrace_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h index 2e9c108..42266e7 100644 --- a/src/ftrace_helper.h +++ b/src/ftrace_helper.h @@ -28,7 +28,7 @@ static struct kprobe kp = { }; typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); kallsyms_lookup_name_t kallsyms_lookup_name_var; -#define kallsyms_lookup_name kallsyms_lookup_name_var; +#define kallsyms_lookup_name (*kallsyms_lookup_name_var); #endif /* x64 has to be special and require a different naming convention */ From c3e411a3432147fd5332f757efa5841de1eb5bc5 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 22:57:07 +0200 Subject: [PATCH 11/25] fix compiling on earlier kernels --- src/snapshot.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/snapshot.h b/src/snapshot.h index 32a269b..eb40d80 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -101,6 +101,11 @@ #include "afl_snapshot.h" +// TODO, at some point in time, ftrace_regs was introduced +// Figure out when. +struct ftrace_regs { + struct pt_regs regs; +}; struct task_data; // TODO lock VMA restore From 4fcf717f779d12bf2d49a5a640db0c04e9da744e Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Sat, 1 May 2021 00:46:30 +0200 Subject: [PATCH 12/25] fix --- test/test2 | Bin 0 -> 20648 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 test/test2 diff --git a/test/test2 b/test/test2 new file mode 100755 index 0000000000000000000000000000000000000000..04559b770bac68f9e690fb25a1101f1fe878c39f GIT binary patch literal 20648 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 literal 0 HcmV?d00001 From a139de56e39a742b96575c36799d4f7251035cae Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:03:12 +0200 Subject: [PATCH 13/25] real fix for older kernels --- src/snapshot.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/snapshot.h b/src/snapshot.h index eb40d80..2d4070c 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -101,11 +101,13 @@ #include "afl_snapshot.h" -// TODO, at some point in time, ftrace_regs was introduced -// Figure out when. +// In 5.11+, ftrace hooks take ftrace_regs as argument. +// Hacky way to fix this for older kernels. +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) struct ftrace_regs { struct pt_regs regs; }; +#endif struct task_data; // TODO lock VMA restore From 30ef95e26cdbea10962797ef5fe43a168827490a Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:04:03 +0200 Subject: [PATCH 14/25] forgot this --- src/snapshot.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/snapshot.h b/src/snapshot.h index 2d4070c..c41a990 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -98,6 +98,7 @@ #define MODULE 1 #include #include +#include #include "afl_snapshot.h" From 6f072e33f65417fa165987a057421ba65ab7fbeb Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:07:22 +0200 Subject: [PATCH 15/25] fix enum being defined --- src/ftrace_helper.h | 1 + src/snapshot.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h index 42266e7..b237d7f 100644 --- a/src/ftrace_helper.h +++ b/src/ftrace_helper.h @@ -144,6 +144,7 @@ int fh_install_hook(struct ftrace_hook *hook) * (see USE_FENTRY_OFFSET). */ hook->ops.func = fh_ftrace_thunk; hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS + | FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_IPMODIFY; err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); diff --git a/src/snapshot.h b/src/snapshot.h index c41a990..ef30d5e 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -108,6 +108,9 @@ struct ftrace_regs { struct pt_regs regs; }; +#define FTRACE_OPS_FL_RECURSION 0 +#else +#define FTRACE_OPS_FL_RECURSION_SAFE 0 #endif struct task_data; From 6b2ac1b5a7c3910d5e519a13a25509962f1a4027 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:08:40 +0200 Subject: [PATCH 16/25] accidently messed that up again. --- src/ftrace_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h index b237d7f..90d91a7 100644 --- a/src/ftrace_helper.h +++ b/src/ftrace_helper.h @@ -28,7 +28,7 @@ static struct kprobe kp = { }; typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); kallsyms_lookup_name_t kallsyms_lookup_name_var; -#define kallsyms_lookup_name (*kallsyms_lookup_name_var); +#define kallsyms_lookup_name kallsyms_lookup_name_var #endif /* x64 has to be special and require a different naming convention */ From 9852027db2eccfac563f9a40017170eacbcff75d Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:11:28 +0200 Subject: [PATCH 17/25] for now add them here as well. --- src/hook.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/hook.c b/src/hook.c index 21a48a6..3b2b23e 100644 --- a/src/hook.c +++ b/src/hook.c @@ -3,8 +3,15 @@ #include #include #include +#include #include "debug.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) +struct ftrace_regs { + struct pt_regs regs; +}; +#define FTRACE_OPS_FL_RECURSION 0 +#endif // TODO(andrea) switch from Kprobes to Ftrace struct hook { From 89797814d377572ff68f049eeeee246c50914333 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:21:37 +0200 Subject: [PATCH 18/25] actually fixed ftrace on older kernels --- src/ftrace_helper.h | 8 +++++--- src/ftrace_util.h | 18 ++++++++++++++++++ src/hook.c | 8 +------- src/memory.c | 16 +++++++++------- src/snapshot.h | 12 +----------- 5 files changed, 34 insertions(+), 28 deletions(-) create mode 100644 src/ftrace_util.h diff --git a/src/ftrace_helper.h b/src/ftrace_helper.h index 90d91a7..299f566 100644 --- a/src/ftrace_helper.h +++ b/src/ftrace_helper.h @@ -10,6 +10,7 @@ #include #include #include "debug.h" +#include "ftrace_util.h" #if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) #define PTREGS_SYSCALL_STUBS 1 @@ -109,15 +110,16 @@ static int fh_resolve_hook_address(struct ftrace_hook *hook) } /* See comment below within fh_install_hook() */ -static void notrace fh_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct ftrace_regs *regs) +static void notrace fh_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, ftrace_regs_ptr regs) { struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); + struct pt_regs* pregs = ftrace_get_regs(regs); #if USE_FENTRY_OFFSET - regs->ip = (unsigned long) hook->function; + pregs->ip = (unsigned long) hook->function; #else if(!within_module(parent_ip, THIS_MODULE)) - regs->regs.ip = (unsigned long) hook->function; + pregs->ip = (unsigned long) hook->function; #endif } diff --git a/src/ftrace_util.h b/src/ftrace_util.h new file mode 100644 index 0000000..5969812 --- /dev/null +++ b/src/ftrace_util.h @@ -0,0 +1,18 @@ +#ifndef __FTRACE_UTIL_H +#define __FTRACE_UTIL_H + +#include +#include + +// In 5.11+, ftrace hooks take ftrace_regs as argument. +// Hacky way to fix this for older kernels. +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) +typedef struct pt_regs* ftrace_regs_ptr; +#define ftrace_get_regs(reg_ptr) reg_ptr; +#define FTRACE_OPS_FL_RECURSION 0 +#else +typedef struct ftrace_regs* ftrace_regs_ptr; +#define FTRACE_OPS_FL_RECURSION_SAFE 0 +#endif + +#endif /* __FTRACE_UTIL_H */ diff --git a/src/hook.c b/src/hook.c index 3b2b23e..6015394 100644 --- a/src/hook.c +++ b/src/hook.c @@ -5,13 +5,7 @@ #include #include #include "debug.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) -struct ftrace_regs { - struct pt_regs regs; -}; -#define FTRACE_OPS_FL_RECURSION 0 -#endif +#include "ftrace_helper.h" // TODO(andrea) switch from Kprobes to Ftrace struct hook { diff --git a/src/memory.c b/src/memory.c index 9649052..468228e 100644 --- a/src/memory.c +++ b/src/memory.c @@ -605,7 +605,7 @@ static long return_0_stub_func(void) { } int wp_page_hook(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *regs) { + struct ftrace_ops *op, ftrace_regs_ptr regs) { struct vm_fault * vmf; struct mm_struct * mm; @@ -615,9 +615,9 @@ int wp_page_hook(unsigned long ip, unsigned long parent_ip, pte_t entry; char * vfrom; + struct pt_regs* pregs = ftrace_get_regs(regs); - - vmf = (struct vm_fault *)regs->regs.di; + vmf = (struct vm_fault *)pregs->di; mm = vmf->vma->vm_mm; ss_page = NULL; @@ -706,7 +706,7 @@ int wp_page_hook(unsigned long ip, unsigned long parent_ip, pte_unmap_unlock(vmf->pte, vmf->ptl); // skip original function - regs->regs.ip = (long unsigned int)&return_0_stub_func; + pregs->ip = (long unsigned int)&return_0_stub_func; return 1; } @@ -718,7 +718,7 @@ int wp_page_hook(unsigned long ip, unsigned long parent_ip, // actually hooking page_add_new_anon_rmap, but we really only care about calls // from do_anonymous_page int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *regs) { + struct ftrace_ops *op, ftrace_regs_ptr regs) { struct vm_area_struct *vma; struct mm_struct * mm; @@ -726,8 +726,10 @@ int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, struct snapshot_page * ss_page; unsigned long address; - vma = (struct vm_area_struct *)regs->regs.si; - address = regs->regs.dx; + struct pt_regs* pregs = ftrace_get_regs(regs); + + vma = (struct vm_area_struct *)pregs->si; + address = pregs->dx; mm = vma->vm_mm; ss_page = NULL; diff --git a/src/snapshot.h b/src/snapshot.h index ef30d5e..12b1331 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -98,20 +98,10 @@ #define MODULE 1 #include #include -#include #include "afl_snapshot.h" +#include "ftrace_util.h" -// In 5.11+, ftrace hooks take ftrace_regs as argument. -// Hacky way to fix this for older kernels. -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) -struct ftrace_regs { - struct pt_regs regs; -}; -#define FTRACE_OPS_FL_RECURSION 0 -#else -#define FTRACE_OPS_FL_RECURSION_SAFE 0 -#endif struct task_data; // TODO lock VMA restore From ce2d17b3805c277075fb1ea1b0e7dff19c573746 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:25:20 +0200 Subject: [PATCH 19/25] fix compile error --- src/hook.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hook.c b/src/hook.c index 6015394..f0946ef 100644 --- a/src/hook.c +++ b/src/hook.c @@ -5,7 +5,7 @@ #include #include #include "debug.h" -#include "ftrace_helper.h" +#include "ftrace_util.h" // TODO(andrea) switch from Kprobes to Ftrace struct hook { From f57a41bcbbf9ea5711f56fa3bfabc24885fd9457 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:26:42 +0200 Subject: [PATCH 20/25] forgot these --- src/snapshot.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/snapshot.h b/src/snapshot.h index 12b1331..d19f1cb 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -217,11 +217,11 @@ void recover_threads_snapshot(struct task_data *data); int snapshot_initialize_k_funcs(void); int wp_page_hook(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *regs); + struct ftrace_ops *op, ftrace_regs_ptr regs); int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *regs); + struct ftrace_ops *op, ftrace_regs_ptr regs); int exit_hook(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *regs); + struct ftrace_ops *op, ftrace_regs_ptr regs); int take_snapshot(int config); void recover_snapshot(void); From 16a3e8d9742d7cd1ae4a2f988160d4e3fa0415ea Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Fri, 30 Apr 2021 23:27:39 +0200 Subject: [PATCH 21/25] forgot this as well --- src/snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snapshot.c b/src/snapshot.c index 55405bd..703c86b 100644 --- a/src/snapshot.c +++ b/src/snapshot.c @@ -4,7 +4,7 @@ #include "snapshot.h" int exit_hook(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *regs) { + struct ftrace_ops *op, ftrace_regs_ptr regs) { clean_snapshot(); return 0; From 8de3d8467f52ff50fde15de60d1ee7812d57f8f9 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Sat, 8 May 2021 15:47:43 +0200 Subject: [PATCH 22/25] added guarding agains weird issue. Also more in depth test cases --- Makefile | 9 +++ src/memory.c | 105 ++++++++++++++++++++++-- src/module.c | 11 +++ src/snapshot.h | 1 + test/Makefile | 2 + test/test3.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 334 insertions(+), 7 deletions(-) create mode 100644 test/Makefile create mode 100644 test/test3.c diff --git a/Makefile b/Makefile index e55d68b..9402b40 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,22 @@ .PHONY: all +test: all + sudo rmmod afl_snapshot || echo "Not loaded anyways..." + sudo insmod src/afl_snapshot.ko + ./test/test3 + + + all: cd src && $(MAKE) cd lib && $(MAKE) + cd test && $(MAKE) clean: cd src && $(MAKE) clean cd lib && $(MAKE) clean + cd test && $(MAKE) code-format: ./.custom-format.py -i src/*.c diff --git a/src/memory.c b/src/memory.c index 468228e..d158ccf 100644 --- a/src/memory.c +++ b/src/memory.c @@ -292,6 +292,8 @@ void make_snapshot_page(struct task_data *data, struct mm_struct *mm, } +// TODO: This seems broken? +// If I have a page that is right below the page of the stack, then it will count as a stack page. inline bool is_stack(struct vm_area_struct *vma) { return vma->vm_start <= vma->vm_mm->start_stack && @@ -336,8 +338,9 @@ void take_memory_snapshot(struct task_data *data) { add_snapshot_vma(data, pvma->vm_start, pvma->vm_end); // We only care about writable pages. Shared memory pages are skipped - // if notsack is specified, skip if this this the stack + // if nostack is specified, skip if this this the stack // Otherwise, look into the allowlist + // SAYF("Considering: 0x%016lx - 0x%016lx (stack: %d)", pvma->vm_start, pvma->vm_end, is_stack(pvma)); if (((pvma->vm_flags & VM_WRITE) && !(pvma->vm_flags & VM_SHARED) && !((data->config & AFL_SNAPSHOT_NOSTACK) && is_stack(pvma))) || intersect_allowlist(pvma->vm_start, pvma->vm_end)) { @@ -485,6 +488,8 @@ void recover_memory_snapshot(struct task_data *data) { pte_t * pte, entry; int i; + int count = 0; + if (data->config & AFL_SNAPSHOT_MMAP) munmap_new_vmas(data); // Instead of iterating over all pages in the snapshot and then restoring the dirty ones, // we can save a lot of computing time by keeping a list of only dirty pages. @@ -495,6 +500,7 @@ void recover_memory_snapshot(struct task_data *data) { // hash_for_each(data->ss.ss_page, i, sp, next) { struct list_head* ptr; for (ptr = data->ss.dirty_pages.next; ptr != &data->ss.dirty_pages; ptr = ptr->next){ + count++; sp = list_entry(ptr, struct snapshot_page, dirty_list); if (sp->dirty && sp->has_been_copied) { // it has been captured by page fault @@ -519,7 +525,7 @@ void recover_memory_snapshot(struct task_data *data) { } - // } else if (is_snapshot_page_private(sp)) { + } else if (is_snapshot_page_private(sp)) { // private page that has not been captured // still write protected @@ -532,13 +538,21 @@ void recover_memory_snapshot(struct task_data *data) { sp->has_had_pte = false; } - + if (!sp->in_dirty_list) { + WARNF("0x%016lx: sp->in_dirty_list = false, but we just encountered it in dirty list!?", sp->page_base); + } + sp->in_dirty_list = false; + if (ptr->next == ptr || ptr->prev == ptr || ptr->prev == ptr->next) { + WARNF("0x%016lx: DETECTED CIRCLE IN DIRTY LIST: ptr: %px, ptr->next: %px", sp->page_base, &ptr, ptr->next); + break; + } } + DBG_PRINT("HAD %d dirty pages!", count); + // haha this is really dumb // surely this will not come back to bite me later, right?? INIT_LIST_HEAD(&data->ss.dirty_pages); - } void clean_snapshot_vmas(struct task_data *data) { @@ -658,10 +672,15 @@ int wp_page_hook(unsigned long ip, unsigned long parent_ip, if (ss_page->dirty) return 0; ss_page->dirty = true; - list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); + if (ss_page->in_dirty_list) { + WARNF("0x%016lx: Adding page to dirty list, but it's already there???", ss_page->page_base); + } else { + ss_page->in_dirty_list = true; + list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); + } DBG_PRINT("wp_page_hook 0x%08lx", vmf->address); - + // dump_stack(); /* the page has been copied? * the page becomes COW page again. we do not need to take care of it. */ @@ -770,14 +789,86 @@ int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, } DBG_PRINT("do_anonymous_page 0x%08lx", address); + // dump_stack(); // HAVE PTE NOW ss_page->has_had_pte = true; if (is_snapshot_page_none_pte(ss_page)) { - list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); + if (ss_page->in_dirty_list) { + WARNF("0x%016lx: Adding page to dirty list, but it's already there???", ss_page->page_base); + } else { + ss_page->in_dirty_list = true; + list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); + } } return 0; } +void finish_fault_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, ftrace_regs_ptr regs) +{ + struct pt_regs* pregs = ftrace_get_regs(regs); + struct vm_fault *vmf = (struct vm_fault*)pregs->di; + struct vm_area_struct *vma; + struct mm_struct * mm; + struct task_data * data; + struct snapshot_page * ss_page; + unsigned long address; + + vma = vmf->vma; + address = vmf->address; + + struct task_struct* ltask = get_cpu_var(last_task); + if (ltask == mm->owner) { + + // fast path + data = get_cpu_var(last_data); + put_cpu_var(last_task); + put_cpu_var(last_data); + } else { + + // query the radix tree + data = get_task_data(mm->owner); + get_cpu_var(last_task) = mm->owner; + get_cpu_var(last_data) = data; + put_cpu_var(last_task); + put_cpu_var(last_task); + put_cpu_var(last_data); + + } + + if (data && have_snapshot(data)) { + + ss_page = get_snapshot_page(data, address & PAGE_MASK); + + } else { + + return; + + } + + if (!ss_page) { + + /* not a snapshot'ed page */ + return; + + } + + DBG_PRINT("finish_fault 0x%08lx", address); + dump_stack(); + + // HAVE PTE NOW + ss_page->has_had_pte = true; + if (is_snapshot_page_none_pte(ss_page)) { + if (ss_page->in_dirty_list) { + WARNF("0x%016lx: Adding page to dirty list, but it's already there???", ss_page->page_base); + } else { + ss_page->in_dirty_list = true; + list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); + } + } + + return; +} diff --git a/src/module.c b/src/module.c index 413ae3c..f0b0c74 100644 --- a/src/module.c +++ b/src/module.c @@ -197,6 +197,9 @@ int snapshot_initialize_k_funcs() { } +void finish_fault_hook(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, ftrace_regs_ptr regs); + static int __init mod_init(void) { SAYF("Loading AFL++ snapshot LKM"); @@ -275,6 +278,14 @@ static int __init mod_init(void) { } + // if (!try_hook("finish_fault", &finish_fault_hook)) { + // FATAL("Unable to hook handle_pte_fault"); + + // unhook_all(); + // // unpatch_syscall_table(); + // return -ENOENT; + // } + // initialize snapshot non-exported funcs return snapshot_initialize_k_funcs(); diff --git a/src/snapshot.h b/src/snapshot.h index d19f1cb..3fce9f0 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -128,6 +128,7 @@ struct snapshot_page { bool has_been_copied; bool has_had_pte; bool dirty; + bool in_dirty_list; struct hlist_node next; diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..3e2a1f9 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,2 @@ +test3: test3.c Makefile + gcc -I ../include -g ../lib/libaflsnapshot.o test3.c -o test3 \ No newline at end of file diff --git a/test/test3.c b/test/test3.c new file mode 100644 index 0000000..62fd757 --- /dev/null +++ b/test/test3.c @@ -0,0 +1,213 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libaflsnapshot.h" + +#define PAGE_SIZE 0x1000 + +#define PAGE_ALIGN(addr) ((uint64_t)addr & (~(PAGE_SIZE-1))) + +#define NUM_PAGES 0x2 + +#define NUM_WRITES 0x4 + +#define NUM_LOOPS 0x2 + +#define PRE_FORK_BASE 0x30000000 +#define POST_FORK_BASE 0x40000000 +#define POST_SNAP_BASE 0x50000000 + +void* pre_fork_pages[NUM_PAGES] = {0}; +void* post_fork_pages[NUM_PAGES] = {0}; +void* post_snapshot[NUM_PAGES] = {0}; + +// gcc -I ../include -g ../lib/libaflsnapshot.o test2.c -o test2 + +void randomly_map(void* pages[], void* base) { + for (int i = 0; i < NUM_PAGES; i++) { + void* fixed_addr = base + i * PAGE_SIZE; + void* addr = mmap((void*)fixed_addr, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, 0, 0); + if (addr != fixed_addr) { + fprintf(stderr, "Failed to map page to %p\n", fixed_addr); + exit(1); + } + memset(addr, 0x42, PAGE_SIZE); + pages[i] = addr; + } +} + +void unmap_pages(void* pages[]) { + for (int i = 0; i < NUM_PAGES; i++) { + void* addr = pages[i]; + munmap(addr, PAGE_SIZE); + } +} + +void randomly_incl_excl(void* pages[]) { + for (int i = 0; i < NUM_PAGES; i++) { + long int result = random(); + void* addr = pages[i]; + if (i % 2 == 1) { + afl_snapshot_exclude_vmrange(addr, addr + PAGE_SIZE); + } else { + afl_snapshot_include_vmrange(addr, addr + PAGE_SIZE); + } + } +} + +void random_write() +{ + int rand_idx = random() % NUM_PAGES; + int rand_page_off = random() % (PAGE_SIZE / 8); // we write a qword + int rand_arr = random() % 3; + void* page = 0; + switch (rand_arr) + { + case 0: + page = pre_fork_pages[rand_idx]; + break; + case 1: + page = post_fork_pages[rand_idx]; + break; + case 2: + page = post_snapshot[rand_idx]; + break; + default: + fprintf(stderr, "DAFUQ: %d\n", rand_arr); + break; + } + void* rand_loc = page + rand_page_off; + *((uint64_t*)rand_loc) = 0x6969696969696969; +} + +void random_writes() +{ + for (int j = 0; j < NUM_WRITES; j++) { + random_write(); + } +} + +void check_page(void* page) +{ + uint64_t* conts = (uint64_t*)page; + if (*conts != 0x4242424242424242) { + fprintf(stderr, "ERROR (%p) not correctly restored: %p\n", page, *conts); + } +} + +void test3() { + + if (afl_snapshot_take(AFL_SNAPSHOT_BLOCK | AFL_SNAPSHOT_FDS) == 1) + fprintf(stderr, "first time!\n"); + + for (int i = 0; i < NUM_LOOPS; i++) { + if (afl_snapshot_take(AFL_SNAPSHOT_BLOCK | AFL_SNAPSHOT_FDS) == 1) + fprintf(stderr, "first time!\n"); + printf("Current Loop: %d\n", i); + random_writes(); + afl_snapshot_restore(); + random_writes(); + afl_snapshot_restore(); + afl_snapshot_restore(); + random_write(); + } +} + +void not_random_writes(void* pages[]) +{ + for (int j = 0; j < NUM_PAGES; j++) { + void* addr = pages[j]; + *(uint64_t*)addr = 0x6868686868686868; + } +} + +void not_random_writes_all() +{ + not_random_writes(pre_fork_pages); + not_random_writes(post_fork_pages); + not_random_writes(post_snapshot); +} + +void test3b() { + if (afl_snapshot_take(AFL_SNAPSHOT_BLOCK | AFL_SNAPSHOT_FDS) == 1) + fprintf(stderr, "first time!\n"); + + for (int i = 0; i < NUM_LOOPS; i++) { + if (afl_snapshot_take(AFL_SNAPSHOT_BLOCK | AFL_SNAPSHOT_FDS) == 1) + fprintf(stderr, "first time!\n"); + printf("Current Loop: %d\n", i); + not_random_writes_all(); + afl_snapshot_restore(); + check_page(pre_fork_pages[0]); + not_random_writes_all(); + afl_snapshot_restore(); + afl_snapshot_restore(); + not_random_writes_all(); + } +} + +void print_maps() +{ + printf("\nMAPS\n\n"); + int fd = open("/proc/self/maps", O_RDONLY); + char buf[4096]; + int size = 1; + while (size > 0) { + size = read(fd, buf, 4096); + write(2, buf, size); + } + printf("\n\n"); +} + +int main() { + randomly_map(pre_fork_pages, PRE_FORK_BASE); + printf("First random page: %p\n", pre_fork_pages[0]); + pid_t pid = fork(); + if (pid == 0) { + printf("In child!\n"); + print_maps(); + afl_snapshot_init(); + randomly_map(post_fork_pages, POST_FORK_BASE); + randomly_incl_excl(pre_fork_pages); + randomly_incl_excl(post_fork_pages); + void* data_start = &pre_fork_pages[0]; + void* data_end = &post_snapshot[NUM_PAGES-1]; + printf("DATA: %p - %p\n", data_start, data_end); + data_start = PAGE_ALIGN(data_start); + data_end = PAGE_ALIGN(data_end) + PAGE_SIZE; + printf("DATA: %p - %p\n", data_start, data_end); + afl_snapshot_exclude_vmrange(data_start, data_end); + if (afl_snapshot_take(AFL_SNAPSHOT_NOSTACK) == 1) + fprintf(stderr, "first time!\n"); + randomly_map(post_snapshot, POST_SNAP_BASE); + randomly_incl_excl(post_snapshot); + test3b(); + unmap_pages(pre_fork_pages); + // test3b(); + // void* first_addr = pre_fork_pages[0]; + // *((uint64_t*)first_addr) = 0x6868686868686868; + // print_maps(); + // test3(); + } else { + printf("In parent, waiting on child...\n"); + int status = 0; + waitpid(pid, &status, 0); + printf("Child exited: %d, going as well\n", status); + } + + return 0; +} + + From 6f34e27d05e7853673010d38bb20c02f79d24bed Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Sat, 8 May 2021 16:00:51 +0200 Subject: [PATCH 23/25] fix some stuff --- src/memory.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/memory.c b/src/memory.c index d158ccf..7717dc3 100644 --- a/src/memory.c +++ b/src/memory.c @@ -542,8 +542,8 @@ void recover_memory_snapshot(struct task_data *data) { WARNF("0x%016lx: sp->in_dirty_list = false, but we just encountered it in dirty list!?", sp->page_base); } sp->in_dirty_list = false; - if (ptr->next == ptr || ptr->prev == ptr || ptr->prev == ptr->next) { - WARNF("0x%016lx: DETECTED CIRCLE IN DIRTY LIST: ptr: %px, ptr->next: %px", sp->page_base, &ptr, ptr->next); + if (ptr->next == ptr || ptr->prev == ptr) { + WARNF("0x%016lx: DETECTED CYCLE IN DIRTY LIST: ptr: %px, ptr->next: %px", sp->page_base, &ptr, ptr->next); break; } } @@ -673,7 +673,7 @@ int wp_page_hook(unsigned long ip, unsigned long parent_ip, ss_page->dirty = true; if (ss_page->in_dirty_list) { - WARNF("0x%016lx: Adding page to dirty list, but it's already there???", ss_page->page_base); + WARNF("0x%016lx: Adding page to dirty list, but it's already there??? (dirty: %d, copied: %d)", ss_page->page_base, ss_page->dirty, ss_page->has_been_copied); } else { ss_page->in_dirty_list = true; list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); @@ -795,7 +795,7 @@ int do_anonymous_hook(unsigned long ip, unsigned long parent_ip, ss_page->has_had_pte = true; if (is_snapshot_page_none_pte(ss_page)) { if (ss_page->in_dirty_list) { - WARNF("0x%016lx: Adding page to dirty list, but it's already there???", ss_page->page_base); + WARNF("0x%016lx: Adding page to dirty list, but it's already there??? (dirty: %d, copied: %d)", ss_page->page_base, ss_page->dirty, ss_page->has_been_copied); } else { ss_page->in_dirty_list = true; list_add_tail(&ss_page->dirty_list, &data->ss.dirty_pages); From f45f1f0e146f86d7f65921b17777f4a052956c78 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Sat, 8 May 2021 16:12:17 +0200 Subject: [PATCH 24/25] fix old code being there --- src/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memory.c b/src/memory.c index 7717dc3..ebeebd8 100644 --- a/src/memory.c +++ b/src/memory.c @@ -525,7 +525,7 @@ void recover_memory_snapshot(struct task_data *data) { } - } else if (is_snapshot_page_private(sp)) { + // } else if (is_snapshot_page_private(sp)) { // private page that has not been captured // still write protected From 6ed0d528348a3c61a5c6f0ef6af2cf7940587753 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Sat, 8 May 2021 16:20:35 +0200 Subject: [PATCH 25/25] revert perf fix until further investigation --- src/memory.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/memory.c b/src/memory.c index ebeebd8..676ffb2 100644 --- a/src/memory.c +++ b/src/memory.c @@ -497,11 +497,11 @@ void recover_memory_snapshot(struct task_data *data) { // This had a massive boost on performance for me, >50%. (Might be more or less depending on a few factors). // // original loop below - // hash_for_each(data->ss.ss_page, i, sp, next) { + hash_for_each(data->ss.ss_page, i, sp, next) { struct list_head* ptr; - for (ptr = data->ss.dirty_pages.next; ptr != &data->ss.dirty_pages; ptr = ptr->next){ + // for (ptr = data->ss.dirty_pages.next; ptr != &data->ss.dirty_pages; ptr = ptr->next){ count++; - sp = list_entry(ptr, struct snapshot_page, dirty_list); + // sp = list_entry(ptr, struct snapshot_page, dirty_list); if (sp->dirty && sp->has_been_copied) { // it has been captured by page fault @@ -525,7 +525,7 @@ void recover_memory_snapshot(struct task_data *data) { } - // } else if (is_snapshot_page_private(sp)) { + } else if (is_snapshot_page_private(sp)) { // private page that has not been captured // still write protected @@ -539,13 +539,13 @@ void recover_memory_snapshot(struct task_data *data) { } if (!sp->in_dirty_list) { - WARNF("0x%016lx: sp->in_dirty_list = false, but we just encountered it in dirty list!?", sp->page_base); + // WARNF("0x%016lx: sp->in_dirty_list = false, but we just encountered it in dirty list!?", sp->page_base); } sp->in_dirty_list = false; - if (ptr->next == ptr || ptr->prev == ptr) { - WARNF("0x%016lx: DETECTED CYCLE IN DIRTY LIST: ptr: %px, ptr->next: %px", sp->page_base, &ptr, ptr->next); - break; - } + // if (ptr->next == ptr || ptr->prev == ptr) { + // WARNF("0x%016lx: DETECTED CYCLE IN DIRTY LIST: ptr: %px, ptr->next: %px", sp->page_base, &ptr, ptr->next); + // break; + // } } DBG_PRINT("HAD %d dirty pages!", count);