about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--examples/qemu_persistent_hook/README.md20
-rw-r--r--examples/qemu_persistent_hook/read_into_rdi.c42
-rw-r--r--examples/qemu_persistent_hook/test.c34
-rw-r--r--include/afl-fuzz.h2
-rwxr-xr-xqemu_mode/build_qemu_support.sh10
-rw-r--r--qemu_mode/patches/afl-qemu-common.h6
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-inl.h35
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-translate-inl.h112
-rw-r--r--qemu_mode/patches/configure.diff26
-rw-r--r--src/afl-fuzz-cmplog.c2
-rw-r--r--src/afl-fuzz-globals.c2
-rw-r--r--src/afl-fuzz-init.c2
-rw-r--r--src/afl-fuzz.c2
13 files changed, 235 insertions, 60 deletions
diff --git a/examples/qemu_persistent_hook/README.md b/examples/qemu_persistent_hook/README.md
new file mode 100644
index 00000000..3278b60c
--- /dev/null
+++ b/examples/qemu_persistent_hook/README.md
@@ -0,0 +1,20 @@
+# QEMU persistent hook example
+
+Compile the test binary and the library:
+
+```
+gcc -no-pie test.c -o test
+gcc -fPIC -shared read_into_rdi.c -o read_into_rdi.so
+```
+
+Fuzz with:
+
+```
+export AFL_QEMU_PERSISTENT_ADDR=0x$(nm test | grep "T target_func" | awk '{print $1}')
+export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so
+
+mkdir in
+echo 0000 > in/in
+
+../../afl-fuzz -Q -i in -o out -- ./test
+```
diff --git a/examples/qemu_persistent_hook/read_into_rdi.c b/examples/qemu_persistent_hook/read_into_rdi.c
new file mode 100644
index 00000000..4c5119e0
--- /dev/null
+++ b/examples/qemu_persistent_hook/read_into_rdi.c
@@ -0,0 +1,42 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
+#define h2g(x) ((uint64_t)(x) - guest_base)
+
+enum {
+    R_EAX = 0,
+    R_ECX = 1,
+    R_EDX = 2,
+    R_EBX = 3,
+    R_ESP = 4,
+    R_EBP = 5,
+    R_ESI = 6,
+    R_EDI = 7,
+    R_R8 = 8,
+    R_R9 = 9,
+    R_R10 = 10,
+    R_R11 = 11,
+    R_R12 = 12,
+    R_R13 = 13,
+    R_R14 = 14,
+    R_R15 = 15,
+
+    R_AL = 0,
+    R_CL = 1,
+    R_DL = 2,
+    R_BL = 3,
+    R_AH = 4,
+    R_CH = 5,
+    R_DH = 6,
+    R_BH = 7,
+};
+
+void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) {
+
+  printf("reading into %p\n", regs[R_EDI]);
+  size_t r = read(0, g2h(regs[R_EDI]), 1024);
+  printf("readed %ld bytes\n", r);
+
+}
diff --git a/examples/qemu_persistent_hook/test.c b/examples/qemu_persistent_hook/test.c
new file mode 100644
index 00000000..079d2be4
--- /dev/null
+++ b/examples/qemu_persistent_hook/test.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+int target_func(char *buf, int size) {
+
+  printf("buffer:%p, size:%p\n", buf, size);
+  switch (buf[0]) {
+
+    case 1:
+      if (buf[1] == '\x44') {
+        puts("a");
+      }
+      break;
+    case 0xff:
+      if (buf[2] == '\xff') {
+        if (buf[1] == '\x44') {
+          puts("b");
+        }
+      }
+      break;
+    default: break;
+
+  }
+
+  return 1;
+
+}
+
+char data[1024];
+
+int main() {
+
+  target_func(data, 1024);
+
+}
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 751bd93c..c62fcc84 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -455,7 +455,7 @@ u8* (*post_handler)(u8* buf, u32* len);
 /* CmpLog */
 
 extern u8* cmplog_binary;
-extern s32 cmplog_forksrv_pid;
+extern s32 cmplog_child_pid, cmplog_forksrv_pid;
 
 /* hooks for the custom mutator function */
 /**
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index 6f2bc448..0413228c 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -156,16 +156,18 @@ patch -p1 <../patches/arm-translate.diff || exit 1
 patch -p1 <../patches/i386-ops_sse.diff || exit 1
 patch -p1 <../patches/i386-fpu_helper.diff || exit 1
 patch -p1 <../patches/softfloat.diff || exit 1
+patch -p1 <../patches/configure.diff || exit 1
 
 echo "[+] Patching done."
 
 if [ "$STATIC" = "1" ]; then
 
-  CFLAGS="-O3 -ggdb" ./configure --disable-bsd-user --disable-guest-agent --disable-strip --disable-werror \
+  ./configure --extra-cflags="-O3 -ggdb -DAFL_QEMU_STATIC_BUILD=1" \
+     --disable-bsd-user --disable-guest-agent --disable-strip --disable-werror \
 	  --disable-gcrypt --disable-debug-info --disable-debug-tcg --disable-tcg-interpreter \
 	  --enable-attr --disable-brlapi --disable-linux-aio --disable-bzip2 --disable-bluez --disable-cap-ng \
 	  --disable-curl --disable-fdt --disable-glusterfs --disable-gnutls --disable-nettle --disable-gtk \
-	  --disable-rdma --disable-libiscsi --disable-vnc-jpeg --enable-kvm --disable-lzo --disable-curses \
+	  --disable-rdma --disable-libiscsi --disable-vnc-jpeg --disable-lzo --disable-curses \
 	  --disable-libnfs --disable-numa --disable-opengl --disable-vnc-png --disable-rbd --disable-vnc-sasl \
 	  --disable-sdl --disable-seccomp --disable-smartcard --disable-snappy --disable-spice --disable-libssh2 \
 	  --disable-libusb --disable-usb-redir --disable-vde --disable-vhost-net --disable-virglrenderer \
@@ -178,9 +180,9 @@ else
   # --enable-pie seems to give a couple of exec's a second performance
   # improvement, much to my surprise. Not sure how universal this is..
   
-  CFLAGS="-O3 -ggdb" ./configure --disable-system \
+  ./configure --disable-system \
     --enable-linux-user --disable-gtk --disable-sdl --disable-vnc \
-    --target-list="${CPU_TARGET}-linux-user" --enable-pie --enable-kvm $CROSS_PREFIX || exit 1
+    --target-list="${CPU_TARGET}-linux-user" --enable-pie $CROSS_PREFIX || exit 1
 
 fi
 
diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h
index 18c36f73..de6c7b73 100644
--- a/qemu_mode/patches/afl-qemu-common.h
+++ b/qemu_mode/patches/afl-qemu-common.h
@@ -59,6 +59,8 @@
 #define INC_AFL_AREA(loc) afl_area_ptr[loc]++
 #endif
 
+typedef void (*afl_persistent_hook_fn)(uint64_t* regs, uint64_t guest_base);
+
 /* Declared in afl-qemu-cpu-inl.h */
 
 extern unsigned char *afl_area_ptr;
@@ -72,9 +74,11 @@ extern unsigned char  is_persistent;
 extern target_long    persistent_stack_offset;
 extern unsigned char  persistent_first_pass;
 extern unsigned char  persistent_save_gpr;
-extern target_ulong   persistent_saved_gpr[AFL_REGS_NUM];
+extern uint64_t       persistent_saved_gpr[AFL_REGS_NUM];
 extern int            persisent_retaddr_offset;
 
+extern afl_persistent_hook_fn afl_persistent_hook_ptr;
+
 extern __thread abi_ulong afl_prev_loc;
 
 extern struct cmp_map* __afl_cmp_map;
diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h
index 9a98fde3..7ef54d78 100644
--- a/qemu_mode/patches/afl-qemu-cpu-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-inl.h
@@ -34,6 +34,10 @@
 #include <sys/shm.h>
 #include "afl-qemu-common.h"
 
+#ifndef AFL_QEMU_STATIC_BUILD
+#include <dlfcn.h>
+#endif
+
 /***************************
  * VARIOUS AUXILIARY STUFF *
  ***************************/
@@ -95,6 +99,8 @@ unsigned char persistent_save_gpr;
 target_ulong  persistent_saved_gpr[AFL_REGS_NUM];
 int           persisent_retaddr_offset;
 
+afl_persistent_hook_fn afl_persistent_hook_ptr;
+
 /* Instrumentation ratio: */
 
 unsigned int afl_inst_rms = MAP_SIZE;         /* Exported for afl_gen_trace */
@@ -192,7 +198,7 @@ static void afl_setup(void) {
 
       __afl_cmp_map = shmat(shm_id, NULL, 0);
 
-      if (__afl_cmp_map == (void*)-1) _exit(1);
+      if (__afl_cmp_map == (void*)-1) exit(1);
 
     }
     
@@ -240,6 +246,33 @@ static void afl_setup(void) {
 
   if (getenv("AFL_QEMU_PERSISTENT_GPR")) persistent_save_gpr = 1;
 
+  if (getenv("AFL_QEMU_PERSISTENT_HOOK")) {
+  
+#ifdef AFL_QEMU_STATIC_BUILD
+
+    fprintf(stderr, "[AFL] ERROR: you cannot use AFL_QEMU_PERSISTENT_HOOK when afl-qemu-trace is static\n");
+    exit(1);
+
+#else
+  
+    persistent_save_gpr = 1;
+  
+    void* plib = dlopen(getenv("AFL_QEMU_PERSISTENT_HOOK"), RTLD_NOW);
+    if (!plib) {
+      fprintf(stderr, "[AFL] ERROR: invalid AFL_QEMU_PERSISTENT_HOOK=%s\n", getenv("AFL_QEMU_PERSISTENT_HOOK"));
+      exit(1);
+    }
+    
+    afl_persistent_hook_ptr = dlsym(plib, "afl_persistent_hook");
+    if (!afl_persistent_hook_ptr) {
+      fprintf(stderr, "[AFL] ERROR: failed to find the function \"afl_persistent_hook\" in %s\n", getenv("AFL_QEMU_PERSISTENT_HOOK"));
+      exit(1);
+    }
+
+#endif
+
+  }
+  
   if (getenv("AFL_QEMU_PERSISTENT_RETADDR_OFFSET"))
     persisent_retaddr_offset =
         strtoll(getenv("AFL_QEMU_PERSISTENT_RETADDR_OFFSET"), NULL, 0);
diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
index 9f032feb..d081060f 100644
--- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
@@ -254,62 +254,71 @@ static void log_x86_sp_content(void) {
 
 }*/
 
-#define I386_RESTORE_STATE_FOR_PERSISTENT                               \
-  do {                                                                  \
-                                                                        \
-    if (persistent_save_gpr) {                                          \
-                                                                        \
-      int      i;                                                       \
-      TCGv_ptr gpr_sv;                                                  \
-                                                                        \
-      TCGv_ptr first_pass_ptr = tcg_const_ptr(&persistent_first_pass);  \
-      TCGv     first_pass = tcg_temp_local_new();                       \
-      TCGv     one = tcg_const_tl(1);                                   \
-      tcg_gen_ld8u_tl(first_pass, first_pass_ptr, 0);                   \
-                                                                        \
-      TCGLabel *lbl_save_gpr = gen_new_label();                         \
-      TCGLabel *lbl_finish_restore_gpr = gen_new_label();               \
-      tcg_gen_brcond_tl(TCG_COND_EQ, first_pass, one, lbl_save_gpr);    \
-                                                                        \
-      for (i = 0; i < CPU_NB_REGS; ++i) {                               \
-                                                                        \
-        gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]);               \
-        tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0);                          \
-                                                                        \
-      }                                                                 \
-                                                                        \
-      tcg_gen_br(lbl_finish_restore_gpr);                               \
-                                                                        \
-      gen_set_label(lbl_save_gpr);                                      \
-                                                                        \
-      for (i = 0; i < CPU_NB_REGS; ++i) {                               \
-                                                                        \
-        gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]);               \
-        tcg_gen_st_tl(cpu_regs[i], gpr_sv, 0);                          \
-                                                                        \
-      }                                                                 \
-                                                                        \
-      gen_set_label(lbl_finish_restore_gpr);                            \
-      tcg_temp_free(first_pass);                                        \
-                                                                        \
-    } else if (afl_persistent_ret_addr == 0) {                          \
-                                                                        \
-      TCGv_ptr stack_off_ptr = tcg_const_ptr(&persistent_stack_offset); \
-      TCGv     stack_off = tcg_temp_new();                              \
-      tcg_gen_ld_tl(stack_off, stack_off_ptr, 0);                       \
-      tcg_gen_sub_tl(cpu_regs[R_ESP], cpu_regs[R_ESP], stack_off);      \
-      tcg_temp_free(stack_off);                                         \
-                                                                        \
-    }                                                                   \
-                                                                        \
-  } while (0)
+
+static void callback_to_persistent_hook(void) {
+
+  afl_persistent_hook_ptr(persistent_saved_gpr, guest_base);
+  
+}
+
+static void i386_restore_state_for_persistent(TCGv* cpu_regs) {
+
+  if (persistent_save_gpr) {                                         
+                                                                       
+    int      i;                                                      
+    TCGv_ptr gpr_sv;                                                 
+                                                                     
+    TCGv_ptr first_pass_ptr = tcg_const_ptr(&persistent_first_pass); 
+    TCGv     first_pass = tcg_temp_local_new();                      
+    TCGv     one = tcg_const_tl(1);                                  
+    tcg_gen_ld8u_tl(first_pass, first_pass_ptr, 0);                  
+                                                                     
+    TCGLabel *lbl_restore_gpr = gen_new_label();                        
+    tcg_gen_brcond_tl(TCG_COND_NE, first_pass, one, lbl_restore_gpr);   
+              
+    // save GRP registers
+    for (i = 0; i < CPU_NB_REGS; ++i) {                              
+                                                                     
+      gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]);              
+      tcg_gen_st_tl(cpu_regs[i], gpr_sv, 0);                         
+                                                                     
+    }
+
+    gen_set_label(lbl_restore_gpr);
+    
+    tcg_gen_afl_call0(&afl_persistent_loop);
+    
+    if (afl_persistent_hook_ptr)
+      tcg_gen_afl_call0(callback_to_persistent_hook);
+
+    // restore GRP registers                                                     
+    for (i = 0; i < CPU_NB_REGS; ++i) {                              
+                                                                     
+      gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]);              
+      tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0);                         
+                                                                     
+    }
+                                                                     
+    tcg_temp_free(first_pass);                                       
+                                                                     
+  } else if (afl_persistent_ret_addr == 0) {
+                                                                     
+    TCGv_ptr stack_off_ptr = tcg_const_ptr(&persistent_stack_offset);
+    TCGv     stack_off = tcg_temp_new();                             
+    tcg_gen_ld_tl(stack_off, stack_off_ptr, 0);                      
+    tcg_gen_sub_tl(cpu_regs[R_ESP], cpu_regs[R_ESP], stack_off);     
+    tcg_temp_free(stack_off);                                        
+                                                                     
+  }                                                                  
+
+}
 
 #define AFL_QEMU_TARGET_i386_SNIPPET                                          \
   if (is_persistent) {                                                        \
                                                                               \
     if (s->pc == afl_persistent_addr) {                                       \
                                                                               \
-      I386_RESTORE_STATE_FOR_PERSISTENT;                                      \
+      i386_restore_state_for_persistent(cpu_regs);                            \
       /*tcg_gen_afl_call0(log_x86_saved_gpr);                                 \
       tcg_gen_afl_call0(log_x86_sp_content);*/                                \
                                                                               \
@@ -319,7 +328,8 @@ static void log_x86_sp_content(void) {
         tcg_gen_st_tl(paddr, cpu_regs[R_ESP], persisent_retaddr_offset);      \
                                                                               \
       }                                                                       \
-      tcg_gen_afl_call0(&afl_persistent_loop);                                \
+                                                                              \
+      if (!persistent_save_gpr) tcg_gen_afl_call0(&afl_persistent_loop);      \
       /*tcg_gen_afl_call0(log_x86_sp_content);*/                              \
                                                                               \
     } else if (afl_persistent_ret_addr && s->pc == afl_persistent_ret_addr) { \
diff --git a/qemu_mode/patches/configure.diff b/qemu_mode/patches/configure.diff
new file mode 100644
index 00000000..acb96294
--- /dev/null
+++ b/qemu_mode/patches/configure.diff
@@ -0,0 +1,26 @@
+diff --git a/configure b/configure
+index 1c9f609..3edc9a7 100755
+--- a/configure
++++ b/configure
+@@ -4603,6 +4603,21 @@ if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \
+     libs_softmmu="-lutil $libs_softmmu"
+ fi
+ 
++##########################################
++cat > $TMPC << EOF
++#include <dlfcn.h>
++#include <stdlib.h>
++int main(int argc, char **argv) { return dlopen("libc.so", RTLD_NOW) != NULL; }
++EOF
++if compile_prog "" "" ; then
++  :
++elif compile_prog "" "-ldl" ; then
++  LIBS="-ldl $LIBS"
++  libs_qga="-ldl $libs_qga"
++else
++  error_exit "libdl check failed"
++fi
++
+ ##########################################
+ # spice probe
+ if test "$spice" != "no" ; then
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 69efcffa..709abefe 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -27,7 +27,7 @@
 #include "afl-fuzz.h"
 #include "cmplog.h"
 
-static s32 cmplog_child_pid, cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
+static s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
 
 void init_cmplog_forkserver(char** argv) {
 
diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-globals.c
index 154f281e..d5d70542 100644
--- a/src/afl-fuzz-globals.c
+++ b/src/afl-fuzz-globals.c
@@ -252,7 +252,7 @@ u32                a_extras_cnt;        /* Total number of tokens available */
 u8 *(*post_handler)(u8 *buf, u32 *len);
 
 u8 *cmplog_binary;
-s32 cmplog_forksrv_pid;
+s32 cmplog_child_pid, cmplog_forksrv_pid;
 
 /* hooks for the custom mutator function */
 size_t (*custom_mutator)(u8 *data, size_t size, u8 *mutated_out,
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 9265e4a5..fc3e1140 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1822,6 +1822,8 @@ static void handle_stop_sig(int sig) {
 
   if (child_pid > 0) kill(child_pid, SIGKILL);
   if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);
+  if (cmplog_child_pid > 0) kill(cmplog_child_pid, SIGKILL);
+  if (cmplog_forksrv_pid > 0) kill(cmplog_forksrv_pid, SIGKILL);
 
 }
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 8833244d..5f453a27 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1017,6 +1017,8 @@ int main(int argc, char** argv) {
 
     if (child_pid > 0) kill(child_pid, SIGKILL);
     if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);
+    if (cmplog_child_pid > 0) kill(cmplog_child_pid, SIGKILL);
+    if (cmplog_forksrv_pid > 0) kill(cmplog_forksrv_pid, SIGKILL);
     /* Now that we've killed the forkserver, we wait for it to be able to get
      * rusage stats. */
     if (waitpid(forksrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }