Index: third_party/afl/src/libtokencap/libtokencap.so.c |
diff --git a/third_party/afl/src/libtokencap/libtokencap.so.c b/third_party/afl/src/libtokencap/libtokencap.so.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..696c913daf5a7d6dd4c526a42dadc10fb5ecbcbd |
--- /dev/null |
+++ b/third_party/afl/src/libtokencap/libtokencap.so.c |
@@ -0,0 +1,253 @@ |
+/* |
+ |
+ american fuzzy lop - extract tokens passed to strcmp / memcmp |
+ ------------------------------------------------------------- |
+ |
+ Written and maintained by Michal Zalewski <lcamtuf@google.com> |
+ |
+ Copyright 2016 Google Inc. All rights reserved. |
+ |
+ Licensed under the Apache License, Version 2.0 (the "License"); |
+ you may not use this file except in compliance with the License. |
+ You may obtain a copy of the License at: |
+ |
+ http://www.apache.org/licenses/LICENSE-2.0 |
+ |
+ This Linux-only companion library allows you to instrument strcmp(), |
+ memcmp(), and related functions to automatically extract tokens. |
+ See README.tokencap for more info. |
+ |
+ */ |
+ |
+#include <stdio.h> |
+#include <string.h> |
+#include <ctype.h> |
+ |
+#include "../types.h" |
+#include "../config.h" |
+ |
+#ifndef __linux__ |
+# error "Sorry, this library is Linux-specific for now!" |
+#endif /* !__linux__ */ |
+ |
+ |
+/* Mapping data and such */ |
+ |
+#define MAX_MAPPINGS 1024 |
+ |
+static struct mapping { |
+ void *st, *en; |
+} __tokencap_ro[MAX_MAPPINGS]; |
+ |
+static u32 __tokencap_ro_cnt; |
+static u8 __tokencap_ro_loaded; |
+static FILE* __tokencap_out_file; |
+ |
+ |
+/* Identify read-only regions in memory. Only parameters that fall into these |
+ ranges are worth dumping when passed to strcmp() and so on. Read-write |
+ regions are far more likely to contain user input instead. */ |
+ |
+static void __tokencap_load_mappings(void) { |
+ |
+ u8 buf[MAX_LINE]; |
+ FILE* f = fopen("/proc/self/maps", "r"); |
+ |
+ __tokencap_ro_loaded = 1; |
+ |
+ if (!f) return; |
+ |
+ while (fgets(buf, MAX_LINE, f)) { |
+ |
+ u8 rf, wf; |
+ void* st, *en; |
+ |
+ if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue; |
+ if (wf == 'w' || rf != 'r') continue; |
+ |
+ __tokencap_ro[__tokencap_ro_cnt].st = (void*)st; |
+ __tokencap_ro[__tokencap_ro_cnt].en = (void*)en; |
+ |
+ if (++__tokencap_ro_cnt == MAX_MAPPINGS) break; |
+ |
+ } |
+ |
+ fclose(f); |
+ |
+} |
+ |
+ |
+/* Check an address against the list of read-only mappings. */ |
+ |
+static u8 __tokencap_is_ro(const void* ptr) { |
+ |
+ u32 i; |
+ |
+ if (!__tokencap_ro_loaded) __tokencap_load_mappings(); |
+ |
+ for (i = 0; i < __tokencap_ro_cnt; i++) |
+ if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1; |
+ |
+ return 0; |
+ |
+} |
+ |
+ |
+/* Dump an interesting token to output file, quoting and escaping it |
+ properly. */ |
+ |
+static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { |
+ |
+ u8 buf[MAX_AUTO_EXTRA * 4 + 1]; |
+ u32 i; |
+ u32 pos = 0; |
+ |
+ if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA) return; |
+ |
+ for (i = 0; i < len; i++) { |
+ |
+ if (is_text && !ptr[i]) break; |
+ |
+ switch (ptr[i]) { |
+ |
+ case 0 ... 31: |
+ case 127 ... 255: |
+ case '\"': |
+ case '\\': |
+ |
+ sprintf(buf + pos, "\\x%02x", ptr[i]); |
+ pos += 4; |
+ break; |
+ |
+ default: |
+ |
+ buf[pos++] = ptr[i]; |
+ |
+ } |
+ |
+ } |
+ |
+ buf[pos] = 0; |
+ |
+ fprintf(__tokencap_out_file, "\"%s\"\n", buf); |
+ |
+} |
+ |
+ |
+/* Replacements for strcmp(), memcmp(), and so on. Note that these will be used |
+ only if the target is compiled with -fno-builtins and linked dynamically. */ |
+ |
+#undef strcmp |
+ |
+int strcmp(const char* str1, const char* str2) { |
+ |
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1); |
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1); |
+ |
+ while (1) { |
+ |
+ unsigned char c1 = *str1, c2 = *str2; |
+ |
+ if (c1 != c2) return (c1 > c2) ? 1 : -1; |
+ if (!c1) return 0; |
+ str1++; str2++; |
+ |
+ } |
+ |
+} |
+ |
+ |
+#undef strncmp |
+ |
+int strncmp(const char* str1, const char* str2, size_t len) { |
+ |
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1); |
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1); |
+ |
+ while (len--) { |
+ |
+ unsigned char c1 = *str1, c2 = *str2; |
+ |
+ if (!c1) return 0; |
+ if (c1 != c2) return (c1 > c2) ? 1 : -1; |
+ str1++; str2++; |
+ |
+ } |
+ |
+ return 0; |
+ |
+} |
+ |
+ |
+#undef strcasecmp |
+ |
+int strcasecmp(const char* str1, const char* str2) { |
+ |
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1); |
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1); |
+ |
+ while (1) { |
+ |
+ unsigned char c1 = tolower(*str1), c2 = tolower(*str2); |
+ |
+ if (c1 != c2) return (c1 > c2) ? 1 : -1; |
+ if (!c1) return 0; |
+ str1++; str2++; |
+ |
+ } |
+ |
+} |
+ |
+ |
+#undef strncasecmp |
+ |
+int strncasecmp(const char* str1, const char* str2, size_t len) { |
+ |
+ if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1); |
+ if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1); |
+ |
+ while (len--) { |
+ |
+ unsigned char c1 = tolower(*str1), c2 = tolower(*str2); |
+ |
+ if (!c1) return 0; |
+ if (c1 != c2) return (c1 > c2) ? 1 : -1; |
+ str1++; str2++; |
+ |
+ } |
+ |
+ return 0; |
+ |
+} |
+ |
+ |
+#undef memcmp |
+ |
+int memcmp(const void* mem1, const void* mem2, size_t len) { |
+ |
+ if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0); |
+ if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0); |
+ |
+ while (len--) { |
+ |
+ unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2; |
+ if (c1 != c2) return (c1 > c2) ? 1 : -1; |
+ mem1++; mem2++; |
+ |
+ } |
+ |
+ return 0; |
+ |
+} |
+ |
+ |
+/* Init code to open the output file (or default to stderr). */ |
+ |
+__attribute__((constructor)) void __tokencap_init(void) { |
+ |
+ u8* fn = getenv("AFL_TOKEN_FILE"); |
+ if (fn) __tokencap_out_file = fopen(fn, "a"); |
+ if (!__tokencap_out_file) __tokencap_out_file = stderr; |
+ |
+} |
+ |