diff options
Diffstat (limited to 'src/afl-fuzz-redqueen.c')
-rw-r--r-- | src/afl-fuzz-redqueen.c | 2209 |
1 files changed, 1971 insertions, 238 deletions
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 28585afe..d631332a 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -28,13 +28,43 @@ #include "afl-fuzz.h" #include "cmplog.h" -///// Colorization +//#define _DEBUG +//#define COMBINE +//#define CMPLOG_INTROSPECTION +//#define ARITHMETIC_LESSER_GREATER +//#define TRANSFORM +//#define TRANSFORM_BASE64 + +// CMP attribute enum +enum { + + IS_EQUAL = 1, // arithemtic equal comparison + IS_GREATER = 2, // arithmetic greater comparison + IS_LESSER = 4, // arithmetic lesser comparison + IS_FP = 8, // is a floating point, not an integer + /* --- below are internal settings, not from target cmplog */ + IS_FP_MOD = 16, // arithemtic changed floating point + IS_INT_MOD = 32, // arithmetic changed interger + IS_TRANSFORM = 64 // transformed integer + +}; + +// CMPLOG LVL +enum { + + LVL1 = 1, // Integer solving + LVL2 = 2, // FP solving + LVL3 = 4 // expensive tranformations + +}; struct range { u32 start; u32 end; struct range *next; + struct range *prev; + u8 ok; }; @@ -44,6 +74,8 @@ static struct range *add_range(struct range *ranges, u32 start, u32 end) { r->start = start; r->end = end; r->next = ranges; + r->ok = 0; + if (likely(ranges)) ranges->prev = r; return r; } @@ -51,155 +83,357 @@ static struct range *add_range(struct range *ranges, u32 start, u32 end) { static struct range *pop_biggest_range(struct range **ranges) { struct range *r = *ranges; - struct range *prev = NULL; struct range *rmax = NULL; - struct range *prev_rmax = NULL; u32 max_size = 0; while (r) { - u32 s = r->end - r->start; - if (s >= max_size) { + if (!r->ok) { - max_size = s; - prev_rmax = prev; - rmax = r; + u32 s = 1 + r->end - r->start; + + if (s >= max_size) { + + max_size = s; + rmax = r; + + } } - prev = r; r = r->next; } - if (rmax) { + return rmax; + +} - if (prev_rmax) { +#ifdef _DEBUG +// static int logging = 0; +static void dump(char *txt, u8 *buf, u32 len) { - prev_rmax->next = rmax->next; + u32 i; + fprintf(stderr, "DUMP %s %016llx ", txt, hash64(buf, len, HASH_CONST)); + for (i = 0; i < len; i++) + fprintf(stderr, "%02x", buf[i]); + fprintf(stderr, "\n"); - } else { +} - *ranges = rmax->next; +static void dump_file(char *path, char *name, u32 counter, u8 *buf, u32 len) { - } + char fn[4096]; + if (!path) path = "."; + snprintf(fn, sizeof(fn), "%s/%s%d", path, name, counter); + int fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (fd >= 0) { - } + write(fd, buf, len); + close(fd); - return rmax; + } } +#endif + static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) { if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; } *cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + return 0; } -static void xor_replace(u8 *buf, u32 len) { +/* replace everything with different values but stay in the same type */ +static void type_replace(afl_state_t *afl, u8 *buf, u32 len) { u32 i; + u8 c; for (i = 0; i < len; ++i) { - buf[i] ^= 0xff; + // wont help for UTF or non-latin charsets + do { + + switch (buf[i]) { + + case 'A' ... 'F': + c = 'A' + rand_below(afl, 1 + 'F' - 'A'); + break; + case 'a' ... 'f': + c = 'a' + rand_below(afl, 1 + 'f' - 'a'); + break; + case '0': + c = '1'; + break; + case '1': + c = '0'; + break; + case '2' ... '9': + c = '2' + rand_below(afl, 1 + '9' - '2'); + break; + case 'G' ... 'Z': + c = 'G' + rand_below(afl, 1 + 'Z' - 'G'); + break; + case 'g' ... 'z': + c = 'g' + rand_below(afl, 1 + 'z' - 'g'); + break; + case '!' ... '*': + c = '!' + rand_below(afl, 1 + '*' - '!'); + break; + case ',' ... '.': + c = ',' + rand_below(afl, 1 + '.' - ','); + break; + case ':' ... '@': + c = ':' + rand_below(afl, 1 + '@' - ':'); + break; + case '[' ... '`': + c = '[' + rand_below(afl, 1 + '`' - '['); + break; + case '{' ... '~': + c = '{' + rand_below(afl, 1 + '~' - '{'); + break; + case '+': + c = '/'; + break; + case '/': + c = '+'; + break; + case ' ': + c = '\t'; + break; + case '\t': + c = ' '; + break; + /* + case '\r': + case '\n': + // nothing ... + break; + */ + default: + c = (buf[i] ^ 0xff); + + } + + } while (c == buf[i]); + + buf[i] = c; } } -static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { +static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, + struct tainted **taints) { - struct range *ranges = add_range(NULL, 0, len); - u8 * backup = ck_alloc_nozero(len); + struct range * ranges = add_range(NULL, 0, len - 1), *rng; + struct tainted *taint = NULL; + u8 * backup = ck_alloc_nozero(len); + u8 * changed = ck_alloc_nozero(len); - u64 orig_hit_cnt, new_hit_cnt; +#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION) + u64 start_time = get_cur_time(); +#endif + + u32 screen_update = 1000000 / afl->queue_cur->exec_us; + u64 orig_hit_cnt, new_hit_cnt, exec_cksum; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_name = "colorization"; afl->stage_short = "colorization"; - afl->stage_max = 1000; - - struct range *rng = NULL; + afl->stage_max = (len << 1); afl->stage_cur = 0; + + // in colorization we do not classify counts, hence we have to calculate + // the original checksum! + if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) { + + goto checksum_fail; + + } + + memcpy(backup, buf, len); + memcpy(changed, buf, len); + type_replace(afl, changed, len); + while ((rng = pop_biggest_range(&ranges)) != NULL && afl->stage_cur < afl->stage_max) { - u32 s = rng->end - rng->start; + u32 s = 1 + rng->end - rng->start; - if (s != 0) { + memcpy(buf + rng->start, changed + rng->start, s); - /* Range not empty */ + u64 cksum = 0; + u64 start_us = get_cur_time_us(); + if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) { - memcpy(backup, buf + rng->start, s); - xor_replace(buf + rng->start, s); + goto checksum_fail; - u64 cksum; - u64 start_us = get_cur_time_us(); - if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) { + } - goto checksum_fail; + u64 stop_us = get_cur_time_us(); + + /* Discard if the mutations change the path or if it is too decremental + in speed - how could the same path have a much different speed + though ...*/ + if (cksum != exec_cksum || + (unlikely(stop_us - start_us > 3 * afl->queue_cur->exec_us) && + likely(!afl->fixed_seed))) { + + memcpy(buf + rng->start, backup + rng->start, s); + + if (s > 1) { // to not add 0 size ranges + + ranges = add_range(ranges, rng->start, rng->start - 1 + s / 2); + ranges = add_range(ranges, rng->start + s / 2, rng->end); } - u64 stop_us = get_cur_time_us(); + if (ranges == rng) { + + ranges = rng->next; + if (ranges) { ranges->prev = NULL; } + + } else if (rng->next) { - /* Discard if the mutations change the paths or if it is too decremental - in speed */ - if (cksum != exec_cksum || - ((stop_us - start_us > 2 * afl->queue_cur->exec_us) && - likely(!afl->fixed_seed))) { + rng->prev->next = rng->next; + rng->next->prev = rng->prev; - ranges = add_range(ranges, rng->start, rng->start + s / 2); - ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); - memcpy(buf + rng->start, backup, s); + } else { + + if (rng->prev) { rng->prev->next = NULL; } } + free(rng); + + } else { + + rng->ok = 1; + } - ck_free(rng); - rng = NULL; - ++afl->stage_cur; + if (++afl->stage_cur % screen_update) { show_stats(afl); }; } - if (afl->stage_cur < afl->stage_max) { afl->queue_cur->fully_colorized = 1; } + rng = ranges; + while (rng) { - new_hit_cnt = afl->queued_paths + afl->unique_crashes; - afl->stage_finds[STAGE_COLORIZATION] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur; - ck_free(backup); + rng = rng->next; - ck_free(rng); - rng = NULL; + } - while (ranges) { + u32 i = 1; + u32 positions = 0; + while (i) { + restart: + i = 0; + struct range *r = NULL; + u32 pos = (u32)-1; rng = ranges; - ranges = rng->next; - ck_free(rng); - rng = NULL; - } + while (rng) { - return 0; + if (rng->ok == 1 && rng->start < pos) { -checksum_fail: - if (rng) { ck_free(rng); } - ck_free(backup); + if (taint && taint->pos + taint->len == rng->start) { + + taint->len += (1 + rng->end - rng->start); + positions += (1 + rng->end - rng->start); + rng->ok = 2; + goto restart; + + } else { + + r = rng; + pos = rng->start; + + } + + } + + rng = rng->next; + + } + + if (r) { + + struct tainted *t = ck_alloc_nozero(sizeof(struct tainted)); + t->pos = r->start; + t->len = 1 + r->end - r->start; + positions += (1 + r->end - r->start); + if (likely(taint)) { taint->prev = t; } + t->next = taint; + t->prev = NULL; + taint = t; + r->ok = 2; + i = 1; + } + + } + + *taints = taint; + + /* temporary: clean ranges */ while (ranges) { rng = ranges; ranges = rng->next; ck_free(rng); - rng = NULL; } + new_hit_cnt = afl->queued_paths + afl->unique_crashes; + +#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION) + FILE *f = stderr; + #ifndef _DEBUG + if (afl->not_on_tty) { + + char fn[4096]; + snprintf(fn, sizeof(fn), "%s/introspection_cmplog.txt", afl->out_dir); + f = fopen(fn, "a"); + + } + + #endif + + if (f) { + + fprintf( + f, + "Colorization: fname=%s len=%u ms=%llu result=%u execs=%u found=%llu " + "taint=%u\n", + afl->queue_cur->fname, len, get_cur_time() - start_time, + afl->queue_cur->colorized, afl->stage_cur, new_hit_cnt - orig_hit_cnt, + positions); + + #ifndef _DEBUG + if (afl->not_on_tty) { fclose(f); } + #endif + + } + +#endif + + afl->stage_finds[STAGE_COLORIZATION] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur; + ck_free(backup); + ck_free(changed); + + return 0; + +checksum_fail: + ck_free(backup); + ck_free(changed); + return 1; } @@ -212,12 +446,19 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { orig_hit_cnt = afl->queued_paths + afl->unique_crashes; +#ifdef _DEBUG + dump("DATA", buf, len); +#endif + if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; } new_hit_cnt = afl->queued_paths + afl->unique_crashes; if (unlikely(new_hit_cnt != orig_hit_cnt)) { +#ifdef _DEBUG + fprintf(stderr, "NEW FIND\n"); +#endif *status = 1; } else { @@ -230,6 +471,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { } +#ifdef TRANSFORM static int strntoll(const char *str, size_t sz, char **end, int base, long long *out) { @@ -277,12 +519,161 @@ static int strntoull(const char *str, size_t sz, char **end, int base, } -static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, - u64 pattern, u64 repl, u64 o_pattern, u32 idx, - u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse, - u8 *status) { +static u8 hex_table_up[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; +static u8 hex_table_low[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; +static u8 hex_table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15}; + +// tests 2 bytes at location +static int is_hex(const char *str) { + + u32 i; + + for (i = 0; i < 2; i++) { + + switch (str[i]) { + + case '0' ... '9': + case 'A' ... 'F': + case 'a' ... 'f': + break; + default: + return 0; + + } + + } + + return 1; + +} + + #ifdef TRANSFORM_BASE64 +// tests 4 bytes at location +static int is_base64(const char *str) { + + u32 i; + + for (i = 0; i < 4; i++) { + + switch (str[i]) { + + case '0' ... '9': + case 'A' ... 'Z': + case 'a' ... 'z': + case '+': + case '/': + case '=': + break; + default: + return 0; + + } + + } + + return 1; + +} + +static u8 base64_encode_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static u8 base64_decode_table[] = { + + 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; + +static u32 from_base64(u8 *src, u8 *dst, u32 dst_len) { + + u32 i, j, v; + u32 len = ((dst_len / 3) << 2); + u32 ret = 0; + + for (i = 0, j = 0; i < len; i += 4, j += 3) { + + v = base64_decode_table[src[i] - 43]; + v = (v << 6) | base64_decode_table[src[i + 1] - 43]; + v = src[i + 2] == '=' ? v << 6 + : (v << 6) | base64_decode_table[src[i + 2] - 43]; + v = src[i + 3] == '=' ? v << 6 + : (v << 6) | base64_decode_table[src[i + 3] - 43]; + + dst[j] = (v >> 16) & 0xFF; + ++ret; + + if (src[i + 2] != '=') { + + dst[j + 1] = (v >> 8) & 0xFF; + ++ret; + + } - if (!buf) { FATAL("BUG: buf was NULL. Please report this.\n"); } + if (src[i + 3] != '=') { + + dst[j + 2] = v & 0xFF; + ++ret; + + } + + } + + return ret; + +} + +static void to_base64(u8 *src, u8 *dst, u32 dst_len) { + + u32 i, j, v; + u32 len = (dst_len >> 2) * 3; + + for (i = 0, j = 0; i < len; i += 3, j += 4) { + + v = src[i]; + v = i + 1 < len ? v << 8 | src[i + 1] : v << 8; + v = i + 2 < len ? v << 8 | src[i + 2] : v << 8; + + dst[j] = base64_encode_table[(v >> 18) & 0x3F]; + dst[j + 1] = base64_encode_table[(v >> 12) & 0x3F]; + if (i + 1 < len) { + + dst[j + 2] = base64_encode_table[(v >> 6) & 0x3F]; + + } else { + + dst[j + 2] = '='; + + } + + if (i + 2 < len) { + + dst[j + 3] = base64_encode_table[v & 0x3F]; + + } else { + + dst[j + 3] = '='; + + } + + } + +} + + #endif + +#endif + +static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, + u64 pattern, u64 repl, u64 o_pattern, + u64 changed_val, u8 attr, u32 idx, u32 taint_len, + u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len, + u8 do_reverse, u8 lvl, u8 *status) { u64 *buf_64 = (u64 *)&buf[idx]; u32 *buf_32 = (u32 *)&buf[idx]; @@ -293,102 +684,424 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u16 *o_buf_16 = (u16 *)&orig_buf[idx]; u8 * o_buf_8 = &orig_buf[idx]; - u32 its_len = len - idx; - // *status = 0; + u32 its_len = MIN(len - idx, taint_len); - u8 * endptr; - u8 use_num = 0, use_unum = 0; - unsigned long long unum; - long long num; + // fprintf(stderr, + // "Encode: %llx->%llx into %llx(<-%llx) at idx=%u " + // "taint_len=%u shape=%u attr=%u\n", + // o_pattern, pattern, repl, changed_val, idx, taint_len, + // h->shape + 1, attr); - if (afl->queue_cur->is_ascii) { +#ifdef TRANSFORM + // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 + if (lvl & LVL3) { - endptr = buf_8; - if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) { + u8 * endptr; + u8 use_num = 0, use_unum = 0; + unsigned long long unum; + long long num; - if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum)) - use_unum = 1; + if (afl->queue_cur->is_ascii) { - } else + endptr = buf_8; + if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) { - use_num = 1; + if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum)) + use_unum = 1; - } + } else - if (use_num && (u64)num == pattern) { + use_num = 1; - size_t old_len = endptr - buf_8; - size_t num_len = snprintf(NULL, 0, "%lld", num); + } - u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - memcpy(new_buf, buf, idx); + #ifdef _DEBUG + if (idx == 0) + fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n", + afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern); + #endif - snprintf(new_buf + idx, num_len, "%lld", num); - memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + // num is likely not pattern as atoi("AAA") will be zero... + if (use_num && ((u64)num == pattern || !num)) { - if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } + u8 tmp_buf[32]; + size_t num_len = snprintf(tmp_buf, sizeof(tmp_buf), "%lld", repl); + size_t old_len = endptr - buf_8; - } else if (use_unum && unum == pattern) { + u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } - size_t old_len = endptr - buf_8; - size_t num_len = snprintf(NULL, 0, "%llu", unum); + memcpy(new_buf, buf, idx); + memcpy(new_buf + idx, tmp_buf, num_len); + memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); - u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - memcpy(new_buf, buf, idx); + if (new_buf[idx + num_len] >= '0' && new_buf[idx + num_len] <= '9') { - snprintf(new_buf + idx, num_len, "%llu", unum); - memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + new_buf[idx + num_len] = ' '; - if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } + } - } + if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } - if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) { + } else if (use_unum && (unum == pattern || !unum)) { - if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) { + u8 tmp_buf[32]; + size_t num_len = snprintf(tmp_buf, sizeof(tmp_buf), "%llu", repl); + size_t old_len = endptr - buf_8; - *buf_64 = repl; - if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_64 = pattern; + u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + + memcpy(new_buf, buf, idx); + memcpy(new_buf + idx, tmp_buf, num_len); + memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + + if (new_buf[idx + num_len] >= '0' && new_buf[idx + num_len] <= '9') { + + new_buf[idx + num_len] = ' '; + + } + + if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } } - // reverse encoding - if (do_reverse && *status != 1) { + // Try to identify transform magic + if (pattern != o_pattern && repl == changed_val && attr <= IS_EQUAL) { + + u64 *ptr = (u64 *)&buf[idx]; + u64 *o_ptr = (u64 *)&orig_buf[idx]; + u64 b_val, o_b_val, mask; + + switch (SHAPE_BYTES(h->shape)) { + + case 0: + case 1: + b_val = (u64)(*ptr % 0x100); + o_b_val = (u64)(*o_ptr % 0x100); + mask = 0xff; + break; + case 2: + case 3: + b_val = (u64)(*ptr % 0x10000); + o_b_val = (u64)(*o_ptr % 0x10000); + mask = 0xffff; + break; + case 4: + case 5: + case 6: + case 7: + b_val = (u64)(*ptr % 0x100000000); + o_b_val = (u64)(*o_ptr % 0x100000000); + mask = 0xffffffff; + break; + default: + b_val = *ptr; + o_b_val = *o_ptr; + mask = 0xffffffffffffffff; - if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), - SWAP64(o_pattern), idx, orig_buf, buf, - len, 0, status))) { + } - return 1; + // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..." + s64 diff = pattern - b_val; + s64 o_diff = o_pattern - o_b_val; + /* + fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, + h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, + b_val, diff);*/ + if (diff == o_diff && diff) { + + // this could be an arithmetic transformation + + u64 new_repl = (u64)((s64)repl - diff); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + + if (unlikely(cmp_extend_encoding( + afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + // if (*status == 1) { fprintf(stderr, "FOUND!\n"); } + + } + + // test for XOR, eg. "if ((user_val ^ 0xabcd) == 0x1234) ..." + if (*status != 1) { + + diff = pattern ^ b_val; + s64 o_diff = o_pattern ^ o_b_val; + + /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, + "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + if (diff == o_diff && diff) { + + // this could be a XOR transformation + + u64 new_repl = (u64)((s64)repl ^ diff); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + + if (unlikely(cmp_extend_encoding( + afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + // if (*status == 1) { fprintf(stderr, "FOUND!\n"); } + + } + + } + + // test for to lowercase, eg. "new_val = (user_val | 0x2020) ..." + if (*status != 1) { + + if ((b_val | (0x2020202020202020 & mask)) == (pattern & mask)) { + + diff = 1; + + } else { + + diff = 0; + + } + + if ((o_b_val | (0x2020202020202020 & mask)) == (o_pattern & mask)) { + + o_diff = 1; + + } else { + + diff = 0; + + } + + /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, + "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + if (o_diff && diff) { + + // this could be a lower to upper + + u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask)); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + + if (unlikely(cmp_extend_encoding( + afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + // if (*status == 1) { fprintf(stderr, "FOUND!\n"); } + + } + + } + + // test for to uppercase, eg. "new_val = (user_val | 0x5f5f) ..." + if (*status != 1) { + + if ((b_val & (0x5f5f5f5f5f5f5f5f & mask)) == (pattern & mask)) { + + diff = 1; + + } else { + + diff = 0; + + } + + if ((o_b_val & (0x5f5f5f5f5f5f5f5f & mask)) == (o_pattern & mask)) { + + o_diff = 1; + + } else { + + o_diff = 0; + + } + + /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, + "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + if (o_diff && diff) { + + // this could be a lower to upper + + u64 new_repl = (repl | (0x2020202020202020 & mask)); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + + if (unlikely(cmp_extend_encoding( + afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + // if (*status == 1) { fprintf(stderr, "FOUND!\n"); } + + } } + *status = 0; + } } - if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) { +#endif - if (its_len >= 4 && *buf_32 == (u32)pattern && - *o_buf_32 == (u32)o_pattern) { + // we only allow this for ascii2integer (above) + if (unlikely(pattern == o_pattern)) { return 0; } - *buf_32 = (u32)repl; - if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_32 = pattern; + if ((lvl & LVL1) || ((lvl & LVL2) && (attr >= IS_FP && attr < IS_FP_MOD)) || + attr >= IS_FP_MOD) { + + if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) { + + // if (its_len >= 8) + // fprintf(stderr, + // "TestU64: %u>=8 (idx=%u attr=%u) %llx==%llx" + // " %llx==%llx <= %llx<-%llx\n", + // its_len, idx, attr, *buf_64, pattern, *o_buf_64, o_pattern, + // repl, changed_val); + + // if this is an fcmp (attr & 8 == 8) then do not compare the patterns - + // due to a bug in llvm dynamic float bitcasts do not work :( + // the value 16 means this is a +- 1.0 test case + if (its_len >= 8 && ((*buf_64 == pattern && *o_buf_64 == o_pattern) || + attr >= IS_FP_MOD)) { + + u64 tmp_64 = *buf_64; + *buf_64 = repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } +#ifdef COMBINE + if (*status == 1) { memcpy(cbuf + idx, buf_64, 8); } +#endif + *buf_64 = tmp_64; + + // fprintf(stderr, "Status=%u\n", *status); + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), + SWAP64(o_pattern), SWAP64(changed_val), + attr, idx, taint_len, orig_buf, buf, + cbuf, len, 0, lvl, status))) { + + return 1; + + } + + } } - // reverse encoding - if (do_reverse && *status != 1) { + if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) { - if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), - SWAP32(o_pattern), idx, orig_buf, buf, - len, 0, status))) { + // if (its_len >= 4 && (attr <= 1 || attr >= 8)) + // fprintf(stderr, + // "TestU32: %u>=4 (idx=%u attr=%u) %x==%x" + // " %x==%x <= %x<-%x\n", + // its_len, idx, attr, *buf_32, (u32)pattern, *o_buf_32, + // (u32)o_pattern, (u32)repl, (u32)changed_val); - return 1; + if (its_len >= 4 && + ((*buf_32 == (u32)pattern && *o_buf_32 == (u32)o_pattern) || + attr >= IS_FP_MOD)) { + + u32 tmp_32 = *buf_32; + *buf_32 = (u32)repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } +#ifdef COMBINE + if (*status == 1) { memcpy(cbuf + idx, buf_32, 4); } +#endif + *buf_32 = tmp_32; + + // fprintf(stderr, "Status=%u\n", *status); + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), + SWAP32(o_pattern), SWAP32(changed_val), + attr, idx, taint_len, orig_buf, buf, + cbuf, len, 0, lvl, status))) { + + return 1; + + } + + } + + } + + if (SHAPE_BYTES(h->shape) >= 2 && *status != 1) { + + if (its_len >= 2 && + ((*buf_16 == (u16)pattern && *o_buf_16 == (u16)o_pattern) || + attr >= IS_FP_MOD)) { + + u16 tmp_16 = *buf_16; + *buf_16 = (u16)repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } +#ifdef COMBINE + if (*status == 1) { memcpy(cbuf + idx, buf_16, 2); } +#endif + *buf_16 = tmp_16; + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), + SWAP16(o_pattern), SWAP16(changed_val), + attr, idx, taint_len, orig_buf, buf, + cbuf, len, 0, lvl, status))) { + + return 1; + + } + + } + + } + + if (*status != 1) { // u8 + + // if (its_len >= 1) + // fprintf(stderr, + // "TestU8: %u>=1 (idx=%u attr=%u) %x==%x %x==%x <= %x<-%x\n", + // its_len, idx, attr, *buf_8, (u8)pattern, *o_buf_8, + // (u8)o_pattern, (u8)repl, (u8)changed_val); + + if (its_len >= 1 && + ((*buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) || + attr >= IS_FP_MOD)) { + + u8 tmp_8 = *buf_8; + *buf_8 = (u8)repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } +#ifdef COMBINE + if (*status == 1) { cbuf[idx] = *buf_8; } +#endif + *buf_8 = tmp_8; } @@ -396,40 +1109,228 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - if (SHAPE_BYTES(h->shape) >= 2 && *status != 1) { + // here we add and subract 1 from the value, but only if it is not an + // == or != comparison + // Bits: 1 = Equal, 2 = Greater, 4 = Lesser, 8 = Float + // 16 = modified float, 32 = modified integer (modified = wont match + // in original buffer) - if (its_len >= 2 && *buf_16 == (u16)pattern && - *o_buf_16 == (u16)o_pattern) { +#ifdef ARITHMETIC_LESSER_GREATER + if (lvl < LVL3 || attr == IS_TRANSFORM) { return 0; } - *buf_16 = (u16)repl; - if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_16 = (u16)pattern; + // lesser/greater FP comparison + if ((attr & (IS_LESSER + IS_GREATER)) && + (attr >= IS_FP && attr < IS_FP_MOD)) { + + u64 repl_new; + if (SHAPE_BYTES(h->shape) == 4 && its_len >= 4) { + + float *f = (float *)&repl; + float g = *f; + g += 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; + + } else if (SHAPE_BYTES(h->shape) == 8 && its_len >= 8) { + + double *f = (double *)&repl; + double g = *f; + g += 1.0; + + u64 *r = (u64 *)&g; + repl_new = *r; + + } else { + + return 0; } - // reverse encoding - if (do_reverse && *status != 1) { + changed_val = repl_new; + + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 16, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + if (SHAPE_BYTES(h->shape) == 4) { + + float *f = (float *)&repl; + float g = *f; + g -= 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; + + } else if (SHAPE_BYTES(h->shape) == 8) { + + double *f = (double *)&repl; + double g = *f; + g -= 1.0; + u64 *r = (u64 *)&g; + repl_new = *r; + + } else { + + return 0; + + } + + changed_val = repl_new; + + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 16, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + // transform double to float, llvm likes to do that internally ... + if (SHAPE_BYTES(h->shape) == 8 && its_len >= 4) { + + double *f = (double *)&repl; + float g = (float)*f; + repl_new = 0; + #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + memcpy((char *)&repl_new, (char *)&g, 4); + #else + memcpy(((char *)&repl_new) + 4, (char *)&g, 4); + #endif + changed_val = repl_new; + h->shape = 3; // modify shape + + // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new); - if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), - SWAP16(o_pattern), idx, orig_buf, buf, - len, 0, status))) { + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + h->shape = 7; // recover shape return 1; } + h->shape = 7; // recover shape + + } + + } else if ((attr & (IS_LESSER + IS_GREATER)) && attr < IS_FP) { + + // lesser/greater integer comparison + + u64 repl_new; + + repl_new = repl + 1; + changed_val = repl_new; + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 32, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + repl_new = repl - 1; + changed_val = repl_new; + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 32, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + } } - /* avoid CodeQL warning on unsigned overflow */ - if (/* SHAPE_BYTES(h->shape) >= 1 && */ *status != 1) { +#endif /* ARITHMETIC_LESSER_GREATER */ - if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) { + return 0; + +} + +#ifdef WORD_SIZE_64 + +static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h, + u128 pattern, u128 repl, u128 o_pattern, + u128 changed_val, u8 attr, u32 idx, + u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u8 do_reverse, u8 lvl, u8 *status) { + + u8 *ptr = (u8 *)&buf[idx]; + u8 *o_ptr = (u8 *)&orig_buf[idx]; + u8 *p = (u8 *)&pattern; + u8 *o_p = (u8 *)&o_pattern; + u8 *r = (u8 *)&repl; + u8 backup[16]; + u32 its_len = MIN(len - idx, taint_len); + u32 shape = h->shape + 1; + #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + size_t off = 0; + #else + size_t off = 16 - shape; + #endif + + if (its_len >= shape) { + + #ifdef _DEBUG + fprintf(stderr, "TestUN: %u>=%u (len=%u idx=%u attr=%u off=%lu) (%u) ", + its_len, shape, len, idx, attr, off, do_reverse); + u32 i; + u8 *o_r = (u8 *)&changed_val; + for (i = 0; i < shape; i++) + fprintf(stderr, "%02x", ptr[i]); + fprintf(stderr, "=="); + for (i = 0; i < shape; i++) + fprintf(stderr, "%02x", p[off + i]); + fprintf(stderr, " "); + for (i = 0; i < shape; i++) + fprintf(stderr, "%02x", o_ptr[i]); + fprintf(stderr, "=="); + for (i = 0; i < shape; i++) + fprintf(stderr, "%02x", o_p[off + i]); + fprintf(stderr, " <= "); + for (i = 0; i < shape; i++) + fprintf(stderr, "%02x", r[off + i]); + fprintf(stderr, "<-"); + for (i = 0; i < shape; i++) + fprintf(stderr, "%02x", o_r[off + i]); + fprintf(stderr, "\n"); + #endif + + if (!memcmp(ptr, p + off, shape) && !memcmp(o_ptr, o_p + off, shape)) { + + memcpy(backup, ptr, shape); + memcpy(ptr, r + off, shape); - *buf_8 = (u8)repl; if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_8 = (u8)pattern; + + #ifdef COMBINE + if (*status == 1) { memcpy(cbuf + idx, r, shape); } + #endif + + memcpy(ptr, backup, shape); + + #ifdef _DEBUG + fprintf(stderr, "Status=%u\n", *status); + #endif + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encodingN( + afl, h, SWAPN(pattern, (shape << 3)), SWAPN(repl, (shape << 3)), + SWAPN(o_pattern, (shape << 3)), SWAPN(changed_val, (shape << 3)), + attr, idx, taint_len, orig_buf, buf, cbuf, len, 0, lvl, + status))) { + + return 1; + + } } @@ -439,16 +1340,14 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } +#endif + static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { u8 *b = (u8 *)&v; u32 k; u8 cons_ff = 0, cons_0 = 0; - - if (shape > sizeof(v)) - FATAL("shape is greater than %zu, please report!", sizeof(v)); - for (k = 0; k < shape; ++k) { if (b[k] == 0) { @@ -457,7 +1356,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } else if (b[k] == 0xff) { - ++cons_ff; + ++cons_0; } else { @@ -493,28 +1392,90 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } -static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { +#ifdef WORD_SIZE_64 +static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) { - struct cmp_header *h = &afl->shm.cmp_map->headers[key]; - u32 i, j, idx; + u8 *b = (u8 *)&v; + + u32 k; + u8 cons_ff = 0, cons_0 = 0; + #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + u32 off = 0; + for (k = 0; k < size; ++k) { + + #else + u32 off = 16 - size; + for (k = 16 - size; k < 16; ++k) { + + #endif + if (b[k] == 0) { + + ++cons_0; + + } else if (b[k] == 0xff) { + + ++cons_0; + + } else { + + cons_0 = cons_ff = 0; + + } + + } + + maybe_add_auto(afl, (u8 *)&v + off, size); + u128 rev = SWAPN(v, size); + maybe_add_auto(afl, (u8 *)&rev + off, size); + +} - u32 loggeds = h->hits; - if (h->hits > CMP_MAP_H) { loggeds = CMP_MAP_H; } +#endif - u8 status = 0; - // opt not in the paper - u32 fails; - u8 found_one = 0; +static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u32 lvl, struct tainted *taint) { + + struct cmp_header *h = &afl->shm.cmp_map->headers[key]; + // FP handling only from lvl 2 onwards + if ((h->attribute & IS_FP) && lvl < LVL2) { return 0; } + + struct tainted *t; + u32 i, j, idx, taint_len, loggeds; + u32 have_taint = 1, is_n = 0; + u8 status = 0, found_one = 0; /* loop cmps are useless, detect and ignore them */ +#ifdef WORD_SIZE_64 + u128 s128_v0 = 0, s128_v1 = 0, orig_s128_v0 = 0, orig_s128_v1 = 0; +#endif u64 s_v0, s_v1; u8 s_v0_fixed = 1, s_v1_fixed = 1; u8 s_v0_inc = 1, s_v1_inc = 1; u8 s_v0_dec = 1, s_v1_dec = 1; - for (i = 0; i < loggeds; ++i) { + if (h->hits > CMP_MAP_H) { + + loggeds = CMP_MAP_H; + + } else { + + loggeds = h->hits; + + } - fails = 0; + switch (SHAPE_BYTES(h->shape)) { + + case 1: + case 2: + case 4: + case 8: + break; + default: + is_n = 1; + + } + + for (i = 0; i < loggeds; ++i) { struct cmp_operands *o = &afl->shm.cmp_map->log[key][i]; @@ -551,55 +1512,171 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } - for (idx = 0; idx < len && fails < 8; ++idx) { +#ifdef _DEBUG + fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n", + orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, + SHAPE_BYTES(h->shape)); +#endif + + t = taint; + while (t->next) { + + t = t->next; + + } + +#ifdef WORD_SIZE_64 + if (unlikely(is_n)) { + + s128_v0 = ((u128)o->v0) + (((u128)o->v0_128) << 64); + s128_v1 = ((u128)o->v1) + (((u128)o->v1_128) << 64); + orig_s128_v0 = ((u128)orig_o->v0) + (((u128)orig_o->v0_128) << 64); + orig_s128_v1 = ((u128)orig_o->v1) + (((u128)orig_o->v1_128) << 64); + + } + +#endif + + for (idx = 0; idx < len; ++idx) { + + if (have_taint) { + + if (!t || idx < t->pos) { + + continue; + + } else { + + taint_len = t->pos + t->len - idx; + + if (idx == t->pos + t->len - 1) { t = t->prev; } + + } + + } else { + + taint_len = len - idx; + + } status = 0; - if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, - orig_buf, buf, len, 1, &status))) { - return 1; +#ifdef WORD_SIZE_64 + if (is_n) { // _ExtInt special case including u128 + + if (s128_v0 != orig_s128_v0 && orig_s128_v0 != orig_s128_v1) { + + if (unlikely(cmp_extend_encodingN( + afl, h, s128_v0, s128_v1, orig_s128_v0, orig_s128_v1, + h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1, + lvl, &status))) { + + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; + break; + + } + + if (s128_v1 != orig_s128_v1 && orig_s128_v1 != orig_s128_v0) { + + if (unlikely(cmp_extend_encodingN( + afl, h, s128_v1, s128_v0, orig_s128_v1, orig_s128_v0, + h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1, + lvl, &status))) { + + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; + break; + + } } - if (status == 2) { +#endif + + // even for u128 and _ExtInt we do cmp_extend_encoding() because + // if we got here their own special trials failed and it might just be + // a cast from e.g. u64 to u128 from the input data. - ++fails; + if ((o->v0 != orig_o->v0 || lvl >= LVL3) && orig_o->v0 != orig_o->v1) { - } else if (status == 1) { + if (unlikely(cmp_extend_encoding( + afl, h, o->v0, o->v1, orig_o->v0, orig_o->v1, h->attribute, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, &status))) { + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; break; } status = 0; - if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, - orig_buf, buf, len, 1, &status))) { + if ((o->v1 != orig_o->v1 || lvl >= LVL3) && orig_o->v0 != orig_o->v1) { - return 1; + if (unlikely(cmp_extend_encoding( + afl, h, o->v1, o->v0, orig_o->v1, orig_o->v0, h->attribute, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, &status))) { - } + return 1; - if (status == 2) { + } - ++fails; + } - } else if (status == 1) { + if (status == 1) { + found_one = 1; break; } } - if (status == 1) { found_one = 1; } +#ifdef _DEBUG + fprintf(stderr, + "END: %llx->%llx vs %llx->%llx attr=%u i=%u found=%u " + "isN=%u size=%u\n", + orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, i, found_one, + is_n, SHAPE_BYTES(h->shape)); +#endif // If failed, add to dictionary - if (fails == 8) { + if (!found_one) { if (afl->pass_stats[key].total == 0) { - try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape)); - try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape)); + if (unlikely(is_n)) { + + try_to_add_to_dictN(afl, s128_v0, SHAPE_BYTES(h->shape)); + try_to_add_to_dictN(afl, s128_v1, SHAPE_BYTES(h->shape)); + + } else { + + try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape)); + try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape)); + + } } @@ -630,53 +1707,454 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, - u8 *o_pattern, u32 idx, u8 *orig_buf, u8 *buf, - u32 len, u8 *status) { - - u32 i; + u8 *o_pattern, u8 *changed_val, u32 idx, + u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u8 lvl, u8 *status) { + +#ifndef COMBINE + (void)(cbuf); +#endif +#ifndef TRANSFORM + (void)(changed_val); +#endif + + u8 save[40]; + u32 saved_idx = idx, pre, from = 0, to = 0, i, j; u32 its_len = MIN((u32)32, len - idx); + its_len = MIN(its_len, taint_len); + u32 saved_its_len = its_len; + + if (lvl & LVL3) { - u8 save[32]; - memcpy(save, &buf[idx], its_len); + u32 max_to = MIN(4U, idx); + if (!(lvl & LVL1) && max_to) { from = 1; } + to = max_to; - *status = 0; + } - for (i = 0; i < its_len; ++i) { + memcpy(save, &buf[saved_idx - to], its_len + to); + (void)(j); - if (pattern[i] != buf[idx + i] || o_pattern[i] != orig_buf[idx + i] || - *status == 1) { +#ifdef _DEBUG + fprintf(stderr, "RTN T idx=%u lvl=%02x ", idx, lvl); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", orig_buf[idx + j]); + fprintf(stderr, " -> "); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", o_pattern[j]); + fprintf(stderr, " <= "); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", repl[j]); + fprintf(stderr, "\n"); + fprintf(stderr, " "); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", buf[idx + j]); + fprintf(stderr, " -> "); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", pattern[j]); + fprintf(stderr, " <= "); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", changed_val[j]); + fprintf(stderr, "\n"); +#endif - break; + // Try to match the replace value up to 4 bytes before the current idx. + // This allows matching of eg.: + // if (memcmp(user_val, "TEST") == 0) + // if (memcmp(user_val, "TEST-VALUE") == 0) ... + // We only do this in lvl 3, otherwise we only do direct matching + + for (pre = from; pre <= to; pre++) { + + if (*status != 1 && (!pre || !memcmp(buf + saved_idx - pre, repl, pre))) { + + idx = saved_idx - pre; + its_len = saved_its_len + pre; + + for (i = 0; i < its_len; ++i) { + + if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) || + *status == 1) { + + break; + + } + + buf[idx + i] = repl[i]; + + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + +#ifdef COMBINE + if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i); } +#endif + + } + + memcpy(&buf[idx], save + to - pre, i); } - buf[idx + i] = repl[i]; + } + +#ifdef TRANSFORM + + if (*status == 1) return 0; + + if (lvl & LVL3) { + + u32 toupper = 0, tolower = 0, xor = 0, arith = 0, tohex = 0, fromhex = 0; + #ifdef TRANSFORM_BASE64 + u32 tob64 = 0, fromb64 = 0; + #endif + u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0; + u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0; + u8 xor_val[32], arith_val[32], tmp[48]; + + idx = saved_idx; + its_len = saved_its_len; + + memcpy(save, &buf[idx], its_len); + + for (i = 0; i < its_len; ++i) { + + xor_val[i] = pattern[i] ^ buf[idx + i]; + arith_val[i] = pattern[i] - buf[idx + i]; + + if (i == 0) { + + if (orig_buf[idx] == '0') { + + from_0 = 1; + + } else if (orig_buf[idx] == '\\') { + + from_slash = 1; + + } + + if (repl[0] == '0') { + + to_0 = 1; + + } else if (repl[0] == '\\') { + + to_slash = 1; + + } + + } else if (i == 1) { + + if (orig_buf[idx + 1] == 'x') { + + from_x = 1; + + } else if (orig_buf[idx + 1] == 'X') { + + from_X = from_x = 1; + + } + + if (repl[1] == 'x' || repl[1] == 'X') { to_x = 1; } + + } + + if (i < 16 && is_hex(repl + (i << 1))) { + + ++tohex; + + if (!to_up) { + + if (repl[i << 1] >= 'A' && repl[i << 1] <= 'F') + to_up = 1; + else if (repl[i << 1] >= 'a' && repl[i << 1] <= 'f') + to_up = 2; + if (repl[(i << 1) + 1] >= 'A' && repl[(i << 1) + 1] <= 'F') + to_up = 1; + else if (repl[(i << 1) + 1] >= 'a' && repl[(i << 1) + 1] <= 'f') + to_up = 2; + + } + + } + + if ((i % 2)) { + + if (len > idx + i && is_hex(orig_buf + idx + i)) { + + fromhex += 2; + + if (!from_up) { - if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + if (orig_buf[idx + i] >= 'A' && orig_buf[idx + i] <= 'F') + from_up = 1; + else if (orig_buf[idx + i] >= 'a' && orig_buf[idx + i] <= 'f') + from_up = 2; + if (orig_buf[idx + i - 1] >= 'A' && orig_buf[idx + i - 1] <= 'F') + from_up = 1; + else if (orig_buf[idx + i - 1] >= 'a' && + orig_buf[idx + i - 1] <= 'f') + from_up = 2; + + } + + } + + } + + #ifdef TRANSFORM_BASE64 + if (i % 3 == 2 && i < 24) { + + if (is_base64(repl + ((i / 3) << 2))) tob64 += 3; + + } + + if (i % 4 == 3 && i < 24) { + + if (is_base64(orig_buf + idx + i - 3)) fromb64 += 4; + + } + + #endif + + if ((o_pattern[i] ^ orig_buf[idx + i]) == xor_val[i] && xor_val[i]) { + + ++xor; + + } + + if ((o_pattern[i] - orig_buf[idx + i]) == arith_val[i] && arith_val[i]) { + + ++arith; + + } + + if ((buf[idx + i] | 0x20) == pattern[i] && + (orig_buf[idx + i] | 0x20) == o_pattern[i]) { + + ++tolower; + + } + + if ((buf[idx + i] & 0x5a) == pattern[i] && + (orig_buf[idx + i] & 0x5a) == o_pattern[i]) { + + ++toupper; + + } + + #ifdef _DEBUG + fprintf(stderr, + "RTN idx=%u loop=%u xor=%u arith=%u tolower=%u toupper=%u " + "tohex=%u fromhex=%u to_0=%u to_slash=%u to_x=%u " + "from_0=%u from_slash=%u from_x=%u\n", + idx, i, xor, arith, tolower, toupper, tohex, fromhex, to_0, + to_slash, to_x, from_0, from_slash, from_x); + #ifdef TRANSFORM_BASE64 + fprintf(stderr, "RTN idx=%u loop=%u tob64=%u from64=%u\n", tob64, + fromb64); + #endif + #endif + + #ifdef TRANSFORM_BASE64 + // input is base64 and converted to binary? convert repl to base64! + if ((i % 4) == 3 && i < 24 && fromb64 > i) { + + to_base64(repl, tmp, i + 1); + memcpy(buf + idx, tmp, i + 1); + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT fromb64 %u result %u\n", fromb64, + // *status); + + } + + // input is converted to base64? decode repl with base64! + if ((i % 3) == 2 && i < 24 && tob64 > i) { + + u32 olen = from_base64(repl, tmp, i + 1); + memcpy(buf + idx, tmp, olen); + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT tob64 %u idx=%u result %u\n", tob64, + // idx, *status); + + } + + #endif + + // input is converted to hex? convert repl to binary! + if (i < 16 && tohex > i) { + + u32 off; + if (to_slash + to_x + to_0 == 2) { + + off = 2; + + } else { + + off = 0; + + } + + for (j = 0; j <= i; j++) + tmp[j] = (hex_table[repl[off + (j << 1)] - '0'] << 4) + + hex_table[repl[off + (j << 1) + 1] - '0']; + + memcpy(buf + idx, tmp, i + 1); + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, *status); + + } + + // input is hex and converted to binary? convert repl to hex! + if (i && (i % 2) && i < 16 && fromhex && + fromhex + from_slash + from_x + from_0 > i) { + + u8 off = 0; + if (from_slash && from_x) { + + tmp[0] = '\\'; + if (from_X) { + + tmp[1] = 'X'; + + } else { + + tmp[1] = 'x'; + + } + + off = 2; + + } else if (from_0 && from_x) { + + tmp[0] = '0'; + if (from_X) { + + tmp[1] = 'X'; + + } else { + + tmp[1] = 'x'; + + } + + off = 2; + + } + + if (to_up == 1) { + + for (j = 0; j <= (i >> 1); j++) { + + tmp[off + (j << 1)] = hex_table_up[repl[j] >> 4]; + tmp[off + (j << 1) + 1] = hex_table_up[repl[j] % 16]; + + } + + } else { + + for (j = 0; j <= (i >> 1); j++) { + + tmp[off + (j << 1)] = hex_table_low[repl[j] >> 4]; + tmp[off + (j << 1) + 1] = hex_table_low[repl[j] % 16]; + + } + + } + + memcpy(buf + idx, tmp, i + 1 + off); + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT fromhex %u result %u\n", fromhex, + // *status); + memcpy(buf + idx + i, save + i, i + 1 + off); + + } + + if (xor > i) { + + for (j = 0; j <= i; j++) + buf[idx + j] = repl[j] ^ xor_val[j]; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT xor %u result %u\n", xor, *status); + + } + + if (arith > i && *status != 1) { + + for (j = 0; j <= i; j++) + buf[idx + j] = repl[j] - arith_val[j]; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, *status); + + } + + if (toupper > i && *status != 1) { + + for (j = 0; j <= i; j++) + buf[idx + j] = repl[j] | 0x20; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT toupper %u result %u\n", toupper, + // *status); + + } + + if (tolower > i && *status != 1) { + + for (j = 0; j <= i; j++) + buf[idx + j] = repl[j] & 0x5f; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + // fprintf(stderr, "RTN ATTEMPT tolower %u result %u\n", tolower, + // *status); + + } + + #ifdef COMBINE + if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i + 1); } + #endif + + if ((i >= 7 && + (i >= xor&&i >= arith &&i >= tolower &&i >= toupper &&i > tohex &&i > + (fromhex + from_0 + from_x + from_slash + 1) + #ifdef TRANSFORM_BASE64 + && i > tob64 + 3 && i > fromb64 + 4 + #endif + )) || + repl[i] != changed_val[i] || *status == 1) { + + break; + + } + + } + + memcpy(&buf[idx], save, i); } - memcpy(&buf[idx], save, i); +#endif + return 0; } -static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { +static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u8 lvl, struct tainted *taint) { + struct tainted * t; struct cmp_header *h = &afl->shm.cmp_map->headers[key]; - u32 i, j, idx; + u32 i, j, idx, have_taint = 1, taint_len, loggeds; + u8 status = 0, found_one = 0; - u32 loggeds = h->hits; - if (h->hits > CMP_MAP_RTN_H) { loggeds = CMP_MAP_RTN_H; } + if (h->hits > CMP_MAP_RTN_H) { - u8 status = 0; - // opt not in the paper - // u32 fails = 0; - u8 found_one = 0; + loggeds = CMP_MAP_RTN_H; - for (i = 0; i < loggeds; ++i) { + } else { + + loggeds = h->hits; + + } - u32 fails = 0; + for (i = 0; i < loggeds; ++i) { struct cmpfn_operands *o = &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i]; @@ -696,50 +2174,89 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } - for (idx = 0; idx < len && fails < 8; ++idx) { + /* + struct cmp_header *hh = &afl->orig_cmp_map->headers[key]; + fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id, + h->shape, h->attribute); for (j = 0; j < 8; j++) fprintf(stderr, "%02x", + o->v0[j]); fprintf(stderr, " v1="); for (j = 0; j < 8; j++) fprintf(stderr, + "%02x", o->v1[j]); fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u + o0=", hh->hits, hh->id, hh->shape, hh->attribute); for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", orig_o->v0[j]); + fprintf(stderr, " o1="); + for (j = 0; j < 8; j++) + fprintf(stderr, "%02x", orig_o->v1[j]); + fprintf(stderr, "\n"); + */ + + t = taint; + while (t->next) { + + t = t->next; - if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0, idx, - orig_buf, buf, len, &status))) { + } - return 1; + for (idx = 0; idx < len; ++idx) { - } + if (have_taint) { - if (status == 2) { + if (!t || idx < t->pos) { - ++fails; + continue; - } else if (status == 1) { + } else { - break; + taint_len = t->pos + t->len - idx; + + if (idx == t->pos + t->len - 1) { t = t->prev; } + + } + + } else { + + taint_len = len - idx; } - if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1, idx, - orig_buf, buf, len, &status))) { + status = 0; + + if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0, + orig_o->v1, idx, taint_len, orig_buf, + buf, cbuf, len, lvl, &status))) { return 1; } - if (status == 2) { + if (status == 1) { - ++fails; + found_one = 1; + break; - } else if (status == 1) { + } + + status = 0; + + if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1, + orig_o->v0, idx, taint_len, orig_buf, + buf, cbuf, len, lvl, &status))) { + + return 1; + } + + if (status == 1) { + + found_one = 1; break; } } - if (status == 1) { found_one = 1; } - // If failed, add to dictionary - if (fails == 8) { + if (!found_one && (lvl & LVL1)) { - if (afl->pass_stats[key].total == 0) { + if (unlikely(!afl->pass_stats[key].total)) { maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape)); maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape)); @@ -768,54 +2285,133 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { ///// Input to State stage // afl->queue_cur->exec_cksum -u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, - u64 exec_cksum) { +u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { u8 r = 1; - if (unlikely(!afl->orig_cmp_map)) { + if (unlikely(!afl->pass_stats)) { - afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map)); + afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W); } - if (unlikely(!afl->pass_stats)) { + struct tainted *taint = NULL; - afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W); + if (!afl->queue_cur->taint || !afl->queue_cur->cmplog_colorinput) { + + if (unlikely(colorization(afl, buf, len, &taint))) { return 1; } + + // no taint? still try, create a dummy to prevent again colorization + if (!taint) { + +#ifdef _DEBUG + fprintf(stderr, "TAINT FAILED\n"); +#endif + afl->queue_cur->colorized = CMPLOG_LVL_MAX; + return 0; + + } + +#ifdef _DEBUG + else if (taint->pos == 0 && taint->len == len) { + + fprintf(stderr, "TAINT FULL\n"); + + } + +#endif + + } else { + + buf = afl->queue_cur->cmplog_colorinput; + taint = afl->queue_cur->taint; } - // do it manually, forkserver clear only afl->fsrv.trace_bits - memset(afl->shm.cmp_map->headers, 0, sizeof(afl->shm.cmp_map->headers)); + struct tainted *t = taint; - if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) { return 1; } + while (t) { - memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map)); +#ifdef _DEBUG + fprintf(stderr, "T: idx=%u len=%u\n", t->pos, t->len); +#endif + t = t->next; + + } + +#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION) + u64 start_time = get_cur_time(); + u32 cmp_locations = 0; +#endif - if (unlikely(colorization(afl, buf, len, exec_cksum))) { return 1; } + // Generate the cmplog data - // do it manually, forkserver clear only afl->fsrv.trace_bits - memset(afl->shm.cmp_map->headers, 0, sizeof(afl->shm.cmp_map->headers)); + // manually clear the full cmp_map + memset(afl->shm.cmp_map, 0, sizeof(struct cmp_map)); + if (unlikely(common_fuzz_cmplog_stuff(afl, orig_buf, len))) { return 1; } + if (unlikely(!afl->orig_cmp_map)) { + + afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map)); + } + + memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map)); + memset(afl->shm.cmp_map->headers, 0, sizeof(struct cmp_header) * CMP_MAP_W); if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) { return 1; } +#ifdef _DEBUG + dump("ORIG", orig_buf, len); + dump("NEW ", buf, len); +#endif + + // Start insertion loop + u64 orig_hit_cnt, new_hit_cnt; u64 orig_execs = afl->fsrv.total_execs; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; + u64 screen_update = 1000000 / afl->queue_cur->exec_us, + execs = afl->fsrv.total_execs; afl->stage_name = "input-to-state"; afl->stage_short = "its"; afl->stage_max = 0; afl->stage_cur = 0; + u32 lvl; + u32 cmplog_done = afl->queue_cur->colorized; + u32 cmplog_lvl = afl->cmplog_lvl; + if (!cmplog_done) { + + lvl = LVL1; + + } else { + + lvl = 0; + + } + + if (cmplog_lvl >= 2 && cmplog_done < 2) { lvl += LVL2; } + if (cmplog_lvl >= 3 && cmplog_done < 3) { lvl += LVL3; } + +#ifdef COMBINE + u8 *cbuf = afl_realloc((void **)&afl->in_scratch_buf, len + 128); + memcpy(cbuf, orig_buf, len); + u8 *virgin_backup = afl_realloc((void **)&afl->ex_buf, afl->shm.map_size); + memcpy(virgin_backup, afl->virgin_bits, afl->shm.map_size); +#else + u8 *cbuf = NULL; +#endif + u32 k; for (k = 0; k < CMP_MAP_W; ++k) { if (!afl->shm.cmp_map->headers[k].hits) { continue; } - if (afl->pass_stats[k].total && - (rand_below(afl, afl->pass_stats[k].total) >= - afl->pass_stats[k].faileds || - afl->pass_stats[k].total == 0xff)) { + if (afl->pass_stats[k].faileds == 0xff || + afl->pass_stats[k].total == 0xff) { + +#ifdef _DEBUG + fprintf(stderr, "DISABLED %u\n", k); +#endif afl->shm.cmp_map->headers[k].hits = 0; // ignore this cmp @@ -839,13 +2435,37 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, if (!afl->shm.cmp_map->headers[k].hits) { continue; } +#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION) + ++cmp_locations; +#endif + if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) { - if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, len))) { goto exit_its; } + if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) { - } else { + goto exit_its; + + } + + } else if ((lvl & LVL1) + +#ifdef TRANSFORM + || (lvl & LVL3) +#endif + ) { - if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, len))) { goto exit_its; } + if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) { + + goto exit_its; + + } + + } + + if (afl->fsrv.total_execs - execs > screen_update) { + + execs = afl->fsrv.total_execs; + show_stats(afl); } @@ -854,13 +2474,126 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, r = 0; exit_its: + + afl->queue_cur->colorized = afl->cmplog_lvl; + if (afl->cmplog_lvl == CMPLOG_LVL_MAX) { + + ck_free(afl->queue_cur->cmplog_colorinput); + t = taint; + while (taint) { + + t = taint->next; + ck_free(taint); + taint = t; + + } + + afl->queue_cur->taint = NULL; + + } else { + + if (!afl->queue_cur->taint) { afl->queue_cur->taint = taint; } + + if (!afl->queue_cur->cmplog_colorinput) { + + afl->queue_cur->cmplog_colorinput = ck_alloc_nozero(len); + memcpy(afl->queue_cur->cmplog_colorinput, buf, len); + memcpy(buf, orig_buf, len); + + } + + } + +#ifdef COMBINE + if (afl->queued_paths + afl->unique_crashes > orig_hit_cnt + 1) { + + // copy the current virgin bits so we can recover the information + u8 *virgin_save = afl_realloc((void **)&afl->eff_buf, afl->shm.map_size); + memcpy(virgin_save, afl->virgin_bits, afl->shm.map_size); + // reset virgin bits to the backup previous to redqueen + memcpy(afl->virgin_bits, virgin_backup, afl->shm.map_size); + + u8 status = 0; + its_fuzz(afl, cbuf, len, &status); + + // now combine with the saved virgin bits + #ifdef WORD_SIZE_64 + u64 *v = (u64 *)afl->virgin_bits; + u64 *s = (u64 *)virgin_save; + u32 i; + for (i = 0; i < (afl->shm.map_size >> 3); i++) { + + v[i] &= s[i]; + + } + + #else + u32 *v = (u64 *)afl->virgin_bits; + u32 *s = (u64 *)virgin_save; + u32 i; + for (i = 0; i < (afl->shm.map_size >> 2); i++) { + + v[i] &= s[i]; + + } + + #endif + + #ifdef _DEBUG + dump("COMB", cbuf, len); + if (status == 1) { + + fprintf(stderr, "NEW COMBINED\n"); + + } else { + + fprintf(stderr, "NO new combined\n"); + + } + + #endif + + } + +#endif + new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs; - memcpy(buf, orig_buf, len); +#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION) + FILE *f = stderr; + #ifndef _DEBUG + if (afl->not_on_tty) { + + char fn[4096]; + snprintf(fn, sizeof(fn), "%s/introspection_cmplog.txt", afl->out_dir); + f = fopen(fn, "a"); + + } + + #endif + + if (f) { + + fprintf(f, + "Cmplog: fname=%s len=%u ms=%llu result=%u finds=%llu entries=%u\n", + afl->queue_cur->fname, len, get_cur_time() - start_time, r, + new_hit_cnt - orig_hit_cnt, cmp_locations); + + #ifndef _DEBUG + if (afl->not_on_tty) { fclose(f); } + #endif + + } + +#endif return r; } +#ifdef COMBINE + #undef COMBINE +#endif + |