about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xafl-cmin2
-rw-r--r--docs/Changelog.md4
-rw-r--r--include/t1ha_bits.h15
-rw-r--r--include/xxhash.h30
-rw-r--r--instrumentation/afl-gcc-cmptrs-pass.so.cc15
-rw-r--r--src/afl-cc.c3
-rw-r--r--src/afl-forkserver.c9
-rw-r--r--src/afl-fuzz.c11
-rw-r--r--unicorn_mode/helper_scripts/unicorn_dumper_pwndbg.py4
-rw-r--r--unicorn_mode/helper_scripts/unicorn_loader.py23
-rw-r--r--utils/afl_network_proxy/GNUmakefile1
11 files changed, 80 insertions, 37 deletions
diff --git a/afl-cmin b/afl-cmin
index 4aaf3953..a1d5401f 100755
--- a/afl-cmin
+++ b/afl-cmin
@@ -108,7 +108,7 @@ function usage() {
 "\n" \
 "Execution control settings:\n" \
 "  -T tasks      - how many parallel tasks to run (default: 1, all=nproc)\n" \
-"  -f file       - location read by the fuzzed program (stdin)\n" \
+"  -f file       - location read by the fuzzed program (default: stdin)\n" \
 "  -m megs       - memory limit for child process ("mem_limit" MB)\n" \
 "  -t msec       - run time limit for child process (default: 5000)\n" \
 "  -O            - use binary-only instrumentation (FRIDA mode)\n" \
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 6408785a..da4b3a20 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -22,12 +22,14 @@
     - small improvements to CMPLOG/redqueen
     - workround for a bug with MOpt -L when used with -M - in the future
       we will either remove or rewrite MOpt.
+    - fix for `-t xxx+` feature
   - afl-cc:
     - added collision free caller instrumentation to LTO mode. activate with
       `AFL_LLVM_LTO_CALLER=1`. You can set a max depth to go through single
       block functions with `AFL_LLVM_LTO_CALLER_DEPTH` (default 0)
+    - fix for GCC_PLUGIN cmplog that broke on std::strings
   - afl-whatsup:
-    - Now also displays current average speed
+    - now also displays current average speed
     - small bugfixes
   - Minor edits to afl-persistent-config
   - Prevent temporary files being left behind on aborted afl-whatsup
diff --git a/include/t1ha_bits.h b/include/t1ha_bits.h
index e7a8d53c..0b9bbda5 100644
--- a/include/t1ha_bits.h
+++ b/include/t1ha_bits.h
@@ -207,7 +207,7 @@ static __maybe_unused __always_inline unsigned e2k_add64carry_first(
   return (unsigned)__builtin_e2k_addcd_c(base, addend, 0);
 
 }
-\
+
       #define add64carry_first(base, addend, sum) \
         e2k_add64carry_first(base, addend, sum)
 
@@ -218,7 +218,7 @@ static __maybe_unused __always_inline unsigned e2k_add64carry_next(
   return (unsigned)__builtin_e2k_addcd_c(base, addend, carry);
 
 }
-\
+
       #define add64carry_next(carry, base, addend, sum) \
         e2k_add64carry_next(carry, base, addend, sum)
 
@@ -230,7 +230,7 @@ static __maybe_unused __always_inline void e2k_add64carry_last(unsigned  carry,
   *sum = __builtin_e2k_addcd(base, addend, carry);
 
 }
-\
+
       #define add64carry_last(carry, base, addend, sum) \
         e2k_add64carry_last(carry, base, addend, sum)
     #endif                                                 /* __iset__ >= 5 */
@@ -311,7 +311,7 @@ static __forceinline char msvc32_add64carry_first(uint64_t  base,
                          base_32h, addend_32h, sum32 + 1);
 
 }
-\
+
       #define add64carry_first(base, addend, sum) \
         msvc32_add64carry_first(base, addend, sum)
 
@@ -328,7 +328,7 @@ static __forceinline char msvc32_add64carry_next(char carry, uint64_t base,
                          base_32h, addend_32h, sum32 + 1);
 
 }
-\
+
       #define add64carry_next(carry, base, addend, sum) \
         msvc32_add64carry_next(carry, base, addend, sum)
 
@@ -345,7 +345,7 @@ static __forceinline void msvc32_add64carry_last(char carry, uint64_t base,
                   addend_32h, sum32 + 1);
 
 }
-\
+
       #define add64carry_last(carry, base, addend, sum) \
         msvc32_add64carry_last(carry, base, addend, sum)
     #endif                                    /* _MSC_FULL_VER >= 190024231 */
@@ -454,7 +454,7 @@ typedef struct {
   uint64_t unaligned_64;
 
 } __attribute__((__packed__)) t1ha_unaligned_proxy;
-\
+
     #define read_unaligned(ptr, bits)                                   \
       (((const t1ha_unaligned_proxy *)((const uint8_t *)(ptr)-offsetof( \
             t1ha_unaligned_proxy, unaligned_##bits)))                   \
@@ -539,6 +539,7 @@ static __always_inline const uint64_t *__attribute__((
         (void)(ptr);      \
                           \
       } while (0)
+
   #endif
 #endif                                                          /* prefetch */
 
diff --git a/include/xxhash.h b/include/xxhash.h
index 7697d0f2..991a8f1e 100644
--- a/include/xxhash.h
+++ b/include/xxhash.h
@@ -1734,7 +1734,7 @@ XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t *src);
  * These declarations should only be used with static linking.
  * Never use them in association with dynamic linking!
  *****************************************************************************
-*/
+ */
 
 /*
  * These definitions are only present to allow static allocation
@@ -2399,9 +2399,9 @@ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(
     #define XXH_NO_STREAM
     #undef XXH_NO_STREAM                                  /* don't actually */
   #endif                                                     /* XXH_DOXYGEN */
-/*!
- * @}
- */
+                         /*!
+                          * @}
+                          */
 
   #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command \
                                      line for example */
@@ -2614,6 +2614,7 @@ static void *XXH_memcpy(void *dest, const void *src, size_t size) {
           _Static_assert((c), m);                  \
                                                    \
         } while (0)
+
     #elif defined(__cplusplus) && (__cplusplus >= 201103L)         /* C++11 */
       #define XXH_STATIC_ASSERT_WITH_MESSAGE(c, m) \
         do {                                       \
@@ -2621,6 +2622,7 @@ static void *XXH_memcpy(void *dest, const void *src, size_t size) {
           static_assert((c), m);                   \
                                                    \
         } while (0)
+
     #else
       #define XXH_STATIC_ASSERT_WITH_MESSAGE(c, m) \
         do {                                       \
@@ -2632,6 +2634,7 @@ static void *XXH_memcpy(void *dest, const void *src, size_t size) {
           };                                       \
                                                    \
         } while (0)
+
     #endif
     #define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c), #c)
   #endif
@@ -2850,7 +2853,7 @@ static int XXH_isLittleEndian(void) {
   return one.c[0];
 
 }
-\
+
       #define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian()
     #endif
   #endif
@@ -4679,6 +4682,7 @@ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) {
             acc = svadd_u64_x(mask, acc, mul);                               \
                                                                              \
           } while (0)
+
       #endif                                       /* XXH_VECTOR == XXH_SVE */
 
       /* prefetch
@@ -4737,12 +4741,14 @@ static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = {
 
 };
 
-static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!<
-                                                           0b0001011001010110011001111001000110011110001101110111100111111001
-                                                         */
-static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!<
-                                                           0b1001111110110010000111000110010100011110100110001101111100100101
-                                                         */
+static const xxh_u64 PRIME_MX1 =
+    0x165667919E3779F9ULL; /*!<
+                              0b0001011001010110011001111001000110011110001101110111100111111001
+                            */
+static const xxh_u64 PRIME_MX2 =
+    0x9FB21C651E98DF25ULL; /*!<
+                              0b1001111110110010000111000110010100011110100110001101111100100101
+                            */
 
       #ifdef XXH_OLD_NAMES
         #define kSecret XXH3_kSecret
@@ -7854,7 +7860,7 @@ XXH3_128bits_digest(XXH_NOESCAPE const XXH3_state_t *state) {
 }
 
       #endif                                              /* !XXH_NO_STREAM */
-    /* 128-bit utility functions */
+             /* 128-bit utility functions */
 
       #include <string.h>                                 /* memcmp, memcpy */
 
diff --git a/instrumentation/afl-gcc-cmptrs-pass.so.cc b/instrumentation/afl-gcc-cmptrs-pass.so.cc
index 929a9d7a..96bd5ba8 100644
--- a/instrumentation/afl-gcc-cmptrs-pass.so.cc
+++ b/instrumentation/afl-gcc-cmptrs-pass.so.cc
@@ -180,19 +180,19 @@ struct afl_cmptrs_pass : afl_base_pass {
     c = DECL_CONTEXT(c);
     if (c && TREE_CODE(c) != TRANSLATION_UNIT_DECL) return false;
 
-    /* Check that the first nonstatic data member of the record type
+    /* Check that the first nonstatic named data member of the record type
        is named _M_dataplus.  */
     for (c = TYPE_FIELDS(t); c; c = DECL_CHAIN(c))
-      if (TREE_CODE(c) == FIELD_DECL) break;
+      if (TREE_CODE(c) == FIELD_DECL && DECL_NAME(c)) break;
     if (!c || !integer_zerop(DECL_FIELD_BIT_OFFSET(c)) ||
         strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "_M_dataplus") != 0)
       return false;
 
-    /* Check that the second nonstatic data member of the record type
+    /* Check that the second nonstatic named data member of the record type
        is named _M_string_length.  */
     tree f2;
     for (f2 = DECL_CHAIN(c); f2; f2 = DECL_CHAIN(f2))
-      if (TREE_CODE(f2) == FIELD_DECL) break;
+      if (TREE_CODE(f2) == FIELD_DECL && DECL_NAME(f2)) break;
     if (!f2                       /* No need to check this field's offset.  */
         || strcmp(IDENTIFIER_POINTER(DECL_NAME(f2)), "_M_string_length") != 0)
       return false;
@@ -208,9 +208,12 @@ struct afl_cmptrs_pass : afl_base_pass {
         strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(c)), "_Alloc_hider") != 0)
       return false;
 
-    /* And its first data member is named _M_p.  */
+    /* And its first nonstatic named data member should be named _M_p.
+       There may be (unnamed) subobjects from empty base classes.  We
+       skip the subobjects, then check the offset of the first data
+       member. */
     for (c = TYPE_FIELDS(c); c; c = DECL_CHAIN(c))
-      if (TREE_CODE(c) == FIELD_DECL) break;
+      if (TREE_CODE(c) == FIELD_DECL && DECL_NAME(c)) break;
     if (!c || !integer_zerop(DECL_FIELD_BIT_OFFSET(c)) ||
         strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "_M_p") != 0)
       return false;
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 6aa0da6a..faa46103 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -828,7 +828,8 @@ static void instrument_mode_old_environ(aflcc_state_t *aflcc) {
   }
 
   if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
-  if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_LTO_CALLER") || getenv("AFL_LLVM_LTO_CTX"))
+  if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_LTO_CALLER") ||
+      getenv("AFL_LLVM_LTO_CTX"))
     aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
 
   if (getenv("AFL_LLVM_NGRAM_SIZE")) {
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 0d7c19c6..4877843d 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -1152,12 +1152,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
         }
 
-        while (dict_size != 0) {
+        while (offset < dict_size) {
 
-          rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size);
+          rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size - offset);
           if (rlen > 0) {
 
-            dict_size -= rlen;
             offset += rlen;
 
           } else {
@@ -1165,7 +1164,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
             FATAL(
                 "Reading autodictionary fail at position %u with %u bytes "
                 "left.",
-                offset, dict_size);
+                offset, dict_size - offset);
 
           }
 
@@ -1931,7 +1930,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   if (exec_ms > timeout) {
 
-    /* If there was no response from forkserver after timeout seconds,
+    /* If there was no response from forkserver after timeout milliseconds,
     we kill the child. The forkserver should inform us afterwards */
 
     s32 tmp_pid = fsrv->child_pid;
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 9c89b2a1..443d93b0 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -2493,8 +2493,15 @@ int main(int argc, char **argv_orig, char **envp) {
 
       for (entry = 0; entry < afl->queued_items; ++entry)
         if (!afl->queue_buf[entry]->disabled)
-          if (afl->queue_buf[entry]->exec_us > max_ms)
-            max_ms = afl->queue_buf[entry]->exec_us;
+          if ((afl->queue_buf[entry]->exec_us / 1000) > max_ms)
+            max_ms = afl->queue_buf[entry]->exec_us / 1000;
+
+      // Add 20% as a safety margin, capped to exec_tmout given in -t option
+      max_ms *= 1.2;
+      if (max_ms > afl->fsrv.exec_tmout) max_ms = afl->fsrv.exec_tmout;
+
+      // Ensure that there is a sensible timeout even for very fast binaries
+      if (max_ms < 5) max_ms = 5;
 
       afl->fsrv.exec_tmout = max_ms;
       afl->timeout_given = 1;
diff --git a/unicorn_mode/helper_scripts/unicorn_dumper_pwndbg.py b/unicorn_mode/helper_scripts/unicorn_dumper_pwndbg.py
index 7e97f6a7..76eaf54f 100644
--- a/unicorn_mode/helper_scripts/unicorn_dumper_pwndbg.py
+++ b/unicorn_mode/helper_scripts/unicorn_dumper_pwndbg.py
@@ -111,12 +111,14 @@ def dump_regs():
     reg_state = {}
     for reg in pwndbg.gdblib.regs.all:
         reg_val = pwndbg.gdblib.regs[reg]
+        if reg_val is None:
+            continue
         # current dumper script looks for register values to be hex strings
         #         reg_str = "0x{:08x}".format(reg_val)
         #         if "64" in get_arch():
         #             reg_str = "0x{:016x}".format(reg_val)
         #         reg_state[reg.strip().strip('$')] = reg_str
-        reg_state[reg.strip().strip("$")] = reg_val
+        reg_state[reg.strip().strip("$")] = int(reg_val)
     return reg_state
 
 
diff --git a/unicorn_mode/helper_scripts/unicorn_loader.py b/unicorn_mode/helper_scripts/unicorn_loader.py
index d0995f83..a83e7000 100644
--- a/unicorn_mode/helper_scripts/unicorn_loader.py
+++ b/unicorn_mode/helper_scripts/unicorn_loader.py
@@ -87,9 +87,10 @@ class UnicornSimpleHeap(object):
 
     _uc = None  # Unicorn engine instance to interact with
     _chunks = []  # List of all known chunks
+    _chunks_freed = [] # List of all freed chunks
     _debug_print = False  # True to print debug information
 
-    def __init__(self, uc, debug_print=False):
+    def __init__(self, uc, debug_print=False, uaf_check=False):
         self._uc = uc
         self._debug_print = debug_print
 
@@ -111,6 +112,13 @@ class UnicornSimpleHeap(object):
             try:
                 self._uc.mem_map(addr, total_chunk_size, UC_PROT_READ | UC_PROT_WRITE)
                 chunk = self.HeapChunk(addr, total_chunk_size, size)
+
+                if self.uaf_check:
+                    for chunk_freed in self._chunks_freed:
+                        if chunk_freed.is_buffer_in_chunk(chunk.data_addr, 1):
+                            self._chunks_freed.remove(chunk_freed)
+                            break
+
                 if self._debug_print:
                     print(
                         "Allocating 0x{0:x}-byte chunk @ 0x{1:016x}".format(
@@ -164,6 +172,10 @@ class UnicornSimpleHeap(object):
                         )
                     )
                 self._uc.mem_unmap(chunk.actual_addr, chunk.total_size)
+
+                if self.uaf_check:
+                    self._chunks_freed.append(chunk)
+                    
                 self._chunks.remove(chunk)
                 return True
         # Freed an object that doesn't exist. Maybe 'dobule-free' or 'invalid free' vulnerability here.
@@ -187,6 +199,15 @@ class UnicornSimpleHeap(object):
                     # Force a memory-based crash
                     uc.force_crash(UcError(UC_ERR_READ_PROT))
 
+        if self.uaf_check:
+            for chunk in self._chunks_freed:
+                if address >= chunk.actual_addr and (
+                    (address + size) <= (chunk.actual_addr + chunk.total_size)
+                ):
+                    if chunk.is_buffer_in_chunk(address, size):
+                        print("Use-after-free @ 0x{0:016x}".format(address))
+                        uc.force_crash(UcError(UC_ERR_FETCH_UNMAPPED))
+
 
 # ---------------------------
 # ---- Loading function
diff --git a/utils/afl_network_proxy/GNUmakefile b/utils/afl_network_proxy/GNUmakefile
index 7c8c22ff..47d9a7d3 100644
--- a/utils/afl_network_proxy/GNUmakefile
+++ b/utils/afl_network_proxy/GNUmakefile
@@ -10,6 +10,7 @@ PROGRAMS = afl-network-client afl-network-server
 HASH=\#
 
 CFLAGS += -Wno-pointer-sign
+LDFLAGS += -ldl
 
 ifdef STATIC
   CFLAGS += -static