diff options
-rwxr-xr-x | afl-cmin | 2 | ||||
-rw-r--r-- | docs/Changelog.md | 4 | ||||
-rw-r--r-- | include/t1ha_bits.h | 15 | ||||
-rw-r--r-- | include/xxhash.h | 30 | ||||
-rw-r--r-- | instrumentation/afl-gcc-cmptrs-pass.so.cc | 15 | ||||
-rw-r--r-- | src/afl-cc.c | 3 | ||||
-rw-r--r-- | src/afl-forkserver.c | 9 | ||||
-rw-r--r-- | src/afl-fuzz.c | 11 | ||||
-rw-r--r-- | unicorn_mode/helper_scripts/unicorn_dumper_pwndbg.py | 4 | ||||
-rw-r--r-- | unicorn_mode/helper_scripts/unicorn_loader.py | 23 | ||||
-rw-r--r-- | utils/afl_network_proxy/GNUmakefile | 1 |
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 |