diff --git a/Makefile b/Makefile index 09a59471..0bbb054c 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ # PROGNAME = afl -VERSION = 1.76b +VERSION = 1.77b PREFIX ?= /usr/local BIN_PATH = $(PREFIX)/bin diff --git a/afl-as.c b/afl-as.c index 216b8e39..70ae7b77 100644 --- a/afl-as.c +++ b/afl-as.c @@ -211,7 +211,7 @@ static void edit_params(int argc, char** argv) { static void add_instrumentation(void) { - static u8 line[MAX_AS_LINE]; + static u8 line[MAX_LINE]; FILE* inf; FILE* outf; @@ -242,7 +242,7 @@ static void add_instrumentation(void) { if (!outf) PFATAL("fdopen() failed"); - while (fgets(line, MAX_AS_LINE, inf)) { + while (fgets(line, MAX_LINE, inf)) { /* In some cases, we want to defer writing the instrumentation trampoline until after all the labels, macros, comments, etc. If we're in this diff --git a/afl-fuzz.c b/afl-fuzz.c index 57b1fde4..0ee6e3b6 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -1353,6 +1353,133 @@ static int compare_extras_use_d(const void* p1, const void* p2) { } +/* Read extras from a file, sort by size. */ + +static void load_extras_file(u8* fname) { + + FILE* f; + u32 min_len = MAX_DICT_FILE, max_len = 0; + u8 buf[MAX_LINE]; + u8 *lptr; + u32 cur_line = 0; + + f = fopen(fname, "r"); + + if (!f) PFATAL("Unable to open '%s'", fname); + + while ((lptr = fgets(buf, MAX_LINE, f))) { + + u8 *rptr, *wptr; + u32 klen = 0; + + cur_line++; + + /* Trim on left and right. */ + + while (isspace(*lptr)) lptr++; + + rptr = lptr + strlen(lptr) - 1; + while (rptr >= lptr && isspace(*rptr)) rptr--; + rptr++; + *rptr = 0; + + /* Skip empty lines and comments. */ + + if (!*lptr || *lptr == '#') continue; + + /* All other lines must end with '"', which we can consume. */ + + rptr--; + + if (rptr < lptr || *rptr != '"') + FATAL("Malformed name=\"value\" pair in line %u.", cur_line); + + *rptr = 0; + + /* Skip alphanumerics and dashes (label). */ + + while (isalnum(*lptr) || *lptr == '_') lptr++; + + /* Skip whitespace and = signs. */ + + while (isspace(*lptr) || *lptr == '=') lptr++; + + /* Consume opening '"'. */ + + if (*lptr != '"') + FATAL("Malformed name=\"keyword\" pair in line %u.", cur_line); + + lptr++; + + if (!*lptr) FATAL("Empty keyword in line %u.", cur_line); + + /* Okay, let's allocate memory and copy data between "...", handling + \xNN escaping, \\, and \". */ + + extras = ck_realloc_block(extras, (extras_cnt + 1) * + sizeof(struct extra_data)); + + wptr = extras[extras_cnt].data = ck_alloc(rptr - lptr); + + while (*lptr) { + + char* hexdigits = "0123456789abcdef"; + + switch (*lptr) { + + case 1 ... 31: + case 128 ... 255: + FATAL("Non-printable characters in line %u.", cur_line); + + case '\\': + + lptr++; + + if (*lptr == '\\' || *lptr == '"') { + *(wptr++) = *(lptr++); + klen++; + break; + } + + if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) + FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line); + + *(wptr++) = + ((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) | + (strchr(hexdigits, tolower(lptr[2])) - hexdigits); + + lptr += 3; + klen++; + + break; + + default: + + *(wptr++) = *(lptr++); + klen++; + + } + + } + + extras[extras_cnt].len = klen; + + if (extras[extras_cnt].len > MAX_DICT_FILE) + FATAL("Keyword too big in line %u (%s, limit is %s)", cur_line, + DMS(klen), DMS(MAX_DICT_FILE)); + + if (min_len > klen) min_len = klen; + if (max_len < klen) max_len = klen; + + extras_cnt++; + + } + + fclose(f); + +} + + /* Read extras from the extras directory and sort them by size. */ static void load_extras(u8* dir) { @@ -1365,7 +1492,16 @@ static void load_extras(u8* dir) { d = opendir(dir); - if (!d) PFATAL("Unable to open '%s'", dir); + if (!d) { + + if (errno == ENOTDIR) { + load_extras_file(dir); + goto check_and_sort; + } + + PFATAL("Unable to open '%s'", dir); + + } while ((de = readdir(d))) { @@ -1411,6 +1547,9 @@ static void load_extras(u8* dir) { } closedir(d); + +check_and_sort: + if (!extras_cnt) FATAL("No usable files in '%s'", dir); qsort(extras, extras_cnt, sizeof(struct extra_data), compare_extras_len); @@ -1429,6 +1568,8 @@ static void load_extras(u8* dir) { } + + /* Helper function for maybe_add_auto() */ static inline u8 memcmp_nocase(u8* m1, u8* m2, u32 len) { diff --git a/config.h b/config.h index f4bcce95..5ef46b03 100644 --- a/config.h +++ b/config.h @@ -250,9 +250,10 @@ #define RESEED_RNG 10000 -/* Maximum line length passed from GCC to 'as': */ +/* Maximum line length passed from GCC to 'as' and used for parsing + configuration files: */ -#define MAX_AS_LINE 8192 +#define MAX_LINE 8192 /* Environment variable used to pass SHM ID to the called program. */ diff --git a/docs/ChangeLog b/docs/ChangeLog index 9bfb1ea9..75cad310 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -16,15 +16,27 @@ Not sure if you should upgrade? The lowest currently recommended version is 1.76b. If you're stuck on an earlier release, it's strongly advisable to get on with the times. +-------------- +Version 1.77b: +-------------- + + - Extended the -x option to support single-file dictionaries. + + - Removed newlines from HTML keywords in testcases/_extras/html/. + -------------- Version 1.76b: -------------- - Very significantly reduced the number of duplicate execs during - deterministic checks, chiefly in int16 and int32 stages. + deterministic checks, chiefly in int16 and int32 stages. Confirmed + identical path yields. This should improve early-stage efficiency by + around 5-10%. - Reduced the likelihood of duplicate non-deterministic execs by - bumping up lowest stacking factor from 1 to 2. + bumping up lowest stacking factor from 1 to 2. Quickly confirmed + that this doesn't seem to have significant impact on coverage with + libpng. - Added a note about integrating afl-fuzz with third-party tools. diff --git a/docs/README b/docs/README index 4ddacfe3..118cf955 100644 --- a/docs/README +++ b/docs/README @@ -296,6 +296,11 @@ existing syntax tokens in the input corpus by watching the instrumentation very closely during deterministic byte flips. This works for some types of parsers and grammars, but isn't nearly as good as the -x mode. +PPS. Due to popular demand, it is now also possible to specify a file dictionary +via -x. The file must follow the name="value" format, one token per line. +Alphanumeric names are ignored, along with empty lines of lines that start with #. +Non-printable and control characters must be escaped within values using \xNN. + 10) Crash triage ---------------- diff --git a/testcases/_extras/html/basic_tags/tag_a b/testcases/_extras/html/basic_tags/tag_a index ece61086..64113133 100644 --- a/testcases/_extras/html/basic_tags/tag_a +++ b/testcases/_extras/html/basic_tags/tag_a @@ -1 +1 @@ - + \ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_abbr b/testcases/_extras/html/basic_tags/tag_abbr index a82b65c5..747b11bc 100644 --- a/testcases/_extras/html/basic_tags/tag_abbr +++ b/testcases/_extras/html/basic_tags/tag_abbr @@ -1 +1 @@ - + \ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_acronym b/testcases/_extras/html/basic_tags/tag_acronym index 5e47c03e..55565205 100644 --- a/testcases/_extras/html/basic_tags/tag_acronym +++ b/testcases/_extras/html/basic_tags/tag_acronym @@ -1 +1 @@ - + \ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_address b/testcases/_extras/html/basic_tags/tag_address index bf0a7a0e..85d13fe7 100644 --- a/testcases/_extras/html/basic_tags/tag_address +++ b/testcases/_extras/html/basic_tags/tag_address @@ -1 +1 @@ -
+
\ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_annotation-xml b/testcases/_extras/html/basic_tags/tag_annotation-xml index 926a1b6f..a8749679 100644 --- a/testcases/_extras/html/basic_tags/tag_annotation-xml +++ b/testcases/_extras/html/basic_tags/tag_annotation-xml @@ -1 +1 @@ - + \ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_applet b/testcases/_extras/html/basic_tags/tag_applet index beead0b0..f1673627 100644 --- a/testcases/_extras/html/basic_tags/tag_applet +++ b/testcases/_extras/html/basic_tags/tag_applet @@ -1 +1 @@ - + \ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_area b/testcases/_extras/html/basic_tags/tag_area index 728d5bca..53e96a69 100644 --- a/testcases/_extras/html/basic_tags/tag_area +++ b/testcases/_extras/html/basic_tags/tag_area @@ -1 +1 @@ - + \ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_article b/testcases/_extras/html/basic_tags/tag_article index b4fbf3f2..6974a8a4 100644 --- a/testcases/_extras/html/basic_tags/tag_article +++ b/testcases/_extras/html/basic_tags/tag_article @@ -1 +1 @@ -
+
\ No newline at end of file diff --git a/testcases/_extras/html/basic_tags/tag_aside b/testcases/_extras/html/basic_tags/tag_aside index fbfaf4bc..1617ac71 100644 --- a/testcases/_extras/html/basic_tags/tag_aside +++ b/testcases/_extras/html/basic_tags/tag_aside @@ -1 +1 @@ -