Skip to content

Instantly share code, notes, and snippets.

@NeatMonster
Created July 3, 2017 08:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NeatMonster/b5ab334047567bf1cc9b2f721003dcdc to your computer and use it in GitHub Desktop.
Save NeatMonster/b5ab334047567bf1cc9b2f721003dcdc to your computer and use it in GitHub Desktop.
This small patch adds support for value profiling into AFL 2.44b.
diff -Naur a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
--- a/llvm_mode/afl-llvm-rt.o.c 2017-02-01 02:59:41.000000000 +0100
+++ b/llvm_mode/afl-llvm-rt.o.c 2017-06-29 15:55:53.052681442 +0200
@@ -304,3 +304,205 @@
}
}
+
+/* This function is called on every indirect call, but only if the binary has
+ been compiled with -fsanitize-coverage=trace-pc,indirect-calls. */
+
+void __sanitizer_cov_trace_pc_indir(uptr callee) {
+
+ uptr caller = (uptr)__builtin_return_address(0);
+
+ const uptr bits = MAP_SIZE_POW2 / 2;
+ const uptr mask = (1 << bits) - 1;
+
+ /* For now we use the less significant bits of the caller and the callee
+ addresses to add an hit to the output map. */
+
+ uptr index = (caller & mask) | ((callee & mask) << bits);
+ __afl_area_ptr[index]++;
+}
+
+/* This function is called by all functions operating on integers. It computes
+ an index using the program counter and the two values being compared. */
+
+void __afl_handle_cmp(uptr pc, u64 arg1, u64 arg2, u8 size) {
+
+ u64 dist = 0;
+ u64 xor = arg1 ^ arg2;
+ if (xor & 0x00000000000000ff) dist++;
+ if (xor & 0x000000000000ff00) dist++;
+ if (xor & 0x0000000000ff0000) dist++;
+ if (xor & 0x00000000ff000000) dist++;
+ if (xor & 0x000000ff00000000) dist++;
+ if (xor & 0x0000ff0000000000) dist++;
+ if (xor & 0x00ff000000000000) dist++;
+ if (xor & 0xff00000000000000) dist++;
+
+ /* If the two values have nothing in common, do not reward. */
+
+ if (dist >= size) return;
+
+ const u64 bits = MAP_SIZE_POW2 - 3;
+ const u64 mask = (1 << bits) - 1;
+
+ /* For now we use the less significant bits of the program counter, and the
+ number of bytes in common between the two values. */
+
+ uptr index = (pc & mask) | (dist << bits);
+ __afl_area_ptr[index]++;
+}
+
+/* The functions below are called on every integer comparison, but only if the
+ binary has been compiled with -fsanitize-coverage=trace-cmp. */
+
+//void __sanitizer_cov_trace_cmp1(u8 arg1, u8 arg2) {
+//
+// uptr pc = (uptr)__builtin_return_address(0);
+//
+// __afl_handle_cmp(pc, arg1, arg2, 1);
+//}
+
+void __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2) {
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ __afl_handle_cmp(pc, arg1, arg2, 2);
+}
+
+void __sanitizer_cov_trace_cmp4(u32 arg1, u32 arg2) {
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ __afl_handle_cmp(pc, arg1, arg2, 4);
+}
+
+void __sanitizer_cov_trace_cmp8(u64 arg1, u64 arg2) {
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ __afl_handle_cmp(pc, arg1, arg2, 8);
+}
+
+/* This function are called on every switch being executed, but only if the
+ binary has been compiled with -fsanitize-coverage=trace-cmp. */
+
+void __sanitizer_cov_trace_switch(u64 val, u64 *cases) {
+
+ u64 len = cases[0];
+ u64 size = cases[2];
+ u64 *vals = cases + 2;
+
+ if (size < 16) return; /* Ignore integers smaller than 16 bits. */
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ u64 i = 0, token = 0;
+ for (i = 0; i < len; ++i) {
+ token = val ^ vals[i];
+ if (val < vals[i]) break;
+ }
+
+ __afl_handle_cmp(pc + i, token, 0, MAX(1, size / 8));
+}
+
+/* The functions below are called on every division, but only if the binary has
+ been compiled with -fsanitize-coverage=trace-div. */
+
+void __sanitizer_cov_trace_div4(u32 val) {
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ __afl_handle_cmp(pc, val, 0, 4);
+}
+
+void __sanitizer_cov_trace_div8(u64 val) {
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ __afl_handle_cmp(pc, val, 0, 8);
+}
+
+/* This function are called on every array indexing, but only if the binary has
+ been compiled with -fsanitize-coverage=trace-gep. */
+
+void __sanitizer_cov_trace_gep(uptr idx) {
+
+ uptr pc = (uptr)__builtin_return_address(0);
+
+ __afl_handle_cmp(pc, idx, 0, sizeof(size_t));
+}
+
+#ifdef USE_WEAK_HOOKS
+
+/* This function is called when doing memory comparisons. It computes an index
+ using the program counter and the two strings being compared. */
+
+void __afl_handle_memcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n, int is_str) {
+
+ const u8 *b1 = (const u8 *)s1;
+ const u8 *b2 = (const u8 *)s2;
+
+ /* Count how many starting bytes the two strings have in common. */
+
+ size_t i, len = MIN(n, 32);
+ for (i = 0; i < len; ++i)
+ if (b1[i] != b2[i] || (is_str && (b1[i] == 0 || b2[i] == 0))) break;
+
+ const u64 bits = MAP_SIZE_POW2 - 5;
+ const u64 mask = (1 << bits) - 1;
+
+ /* For now we use the less significant bits of the program counter, and the
+ number of starting bytes in common between the two strings. */
+
+ size_t pc = (size_t)caller_pc;
+ size_t index = (pc & mask) | (i << bits);
+ __afl_area_ptr[index]++;
+}
+
+/* The functions below are called on every call to their eponymous function, but
+ only if the binary has been compiled with at least a sanitizer enabled. */
+
+void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
+ const void *s2, size_t n, int result) {
+
+ if (!result || n <= 1) return;
+
+ __afl_handle_memcmp(caller_pc, s1, s2, n, 0);
+}
+
+void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
+ const char *s2, int result) {
+
+ if (!result) return;
+
+ /* We need to calculate the length ourselves . */
+
+ size_t n = 0;
+ while (s1[n] && s2[n]) ++n;
+ if (n <= 1) return;
+
+ __afl_handle_memcmp(caller_pc, s1, s2, n, 1);
+}
+
+void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
+ const char *s2, size_t n, int result) {
+
+ if (!result || n <= 1) return;
+
+ __afl_handle_memcmp(caller_pc, s1, s2, n, 1);
+}
+
+void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+ const char *s2, int result) {
+
+ return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
+}
+
+void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+ const char *s2, size_t n, int result) {
+
+ return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
+}
+
+#endif /* USE_WEAK_HOOKS */
diff -Naur a/llvm_mode/Makefile b/llvm_mode/Makefile
--- a/llvm_mode/Makefile 2016-06-24 04:38:49.000000000 +0200
+++ b/llvm_mode/Makefile 2017-06-29 13:12:50.003040093 +0200
@@ -30,6 +30,9 @@
-DVERSION=\"$(VERSION)\"
ifdef AFL_TRACE_PC
CFLAGS += -DUSE_TRACE_PC=1
+ ifdef AFL_WEAK_HOOKS
+ CFLAGS += -DUSE_WEAK_HOOKS=1
+ endif
endif
CXXFLAGS ?= -O3 -funroll-loops
diff -Naur a/types.h b/types.h
--- a/types.h 2017-06-02 08:34:36.000000000 +0200
+++ b/types.h 2017-06-29 10:15:00.309117731 +0200
@@ -45,6 +45,7 @@
#else
typedef uint64_t u64;
#endif /* ^__x86_64__ */
+typedef uintptr_t uptr;
typedef int8_t s8;
typedef int16_t s16;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment