about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJonathan Neuschäfer <j.neuschaefer@gmx.net>2023-04-10 12:22:42 +0200
committerJonathan Neuschäfer <j.neuschaefer@gmx.net>2023-04-10 13:47:19 +0200
commit9e3e1a5512acd44020430f24c9ec1260aeeda285 (patch)
treec4baa6c4a7721658171dadfdf8b76d799bab1140 /src
parent0911525194f4a9d40fcb65e0ab7a83ccf661c192 (diff)
downloadafl++-9e3e1a5512acd44020430f24c9ec1260aeeda285.tar.gz
afl-cc: Don't offer __AFL_INIT() etc. in GCC/CLANG modes
instrumentation/README.persistent_mode.md documents in the section about
deferred forkserver initialization:

> With the location selected, add this code in the appropriate spot:
>
> ```c
> #ifdef __AFL_HAVE_MANUAL_CONTROL
>   __AFL_INIT();
> #endif
> ```
>
> You don't need the #ifdef guards, but including them ensures that the program
> will keep working normally when compiled with a tool other than afl-clang-fast/
> afl-clang-lto/afl-gcc-fast.
>
> Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast
> (afl-gcc or afl-clang will *not* generate a deferred-initialization binary) -
> and you should be all set!


This strongly implies that you can compile a program that uses __AFL_INIT()
under an `#ifdef __AFL_HAVE_MANUAL_CONTROL` guard with afl-gcc/-clang.

However, this currently fails:

  $ cat example.c
  #include <stdio.h>

  int main(void) {
  #ifdef __AFL_HAVE_MANUAL_CONTROL
  	__AFL_INIT();
  #endif

  	puts("Hello");
  }
  $ afl-gcc example.c -o example
  afl-cc++4.06a by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: GCC-GCC
  [!] WARNING: You are using outdated instrumentation, install LLVM and/or gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast instead!
  afl-as++4.06a by Michal Zalewski
  [+] Instrumented 1 locations (64-bit, non-hardened mode, ratio 100%).
  /usr/bin/ld: /tmp/ccuJHcpt.o: in function `main':
  /home/jn/dev/fuzz/AFLplusplus/example.c:5: undefined reference to `__afl_manual_init'
  collect2: error: ld returned 1 exit status


The issue here is an inconsistency in afl-gcc (i.e. afl-cc operating in GCC mode):

 - afl-cc defines __AFL_HAVE_MANUAL_CONTROL and __AFL_INIT unconditionally
 - __AFL_INIT relies on __afl_manual_init, which is defined in afl-compiler-rt.o
 - afl-cc doesn't link afl-compiler-rt in GCC or CLANG mode


Since afl-gcc/-clang is documented as not supporting deferred forkserver
initialization, this patch omits the definitions of __AFL_HAVE_MANUAL_CONTROL
and related macros in GCC/CLANG mode.

This restores the ability to compile a deferred-forkserver program under
afl-gcc, if it can also be compiled under gcc.

[ In case someone reads this an feels adventurous enough (as I did) to
  think about enabling deferred forkserver under afl-gcc: Whether the
  deferred forkserver actually works can be verified by placing a
  usleep(100000) or similar at the start of main (before __AFL_INIT()),
  and watching the execution speed. It doesn't work. ]
Diffstat (limited to 'src')
-rw-r--r--src/afl-cc.c102
1 files changed, 57 insertions, 45 deletions
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 35b90a5c..7f15ad76 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -1101,37 +1101,45 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
 #endif
 
-  cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
   cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
   cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
 
-  /* When the user tries to use persistent or deferred forkserver modes by
-     appending a single line to the program, we want to reliably inject a
-     signature into the binary (to be picked up by afl-fuzz) and we want
-     to call a function from the runtime .o file. This is unnecessarily
-     painful for three reasons:
+  /* As documented in instrumentation/README.persistent_mode.md, deferred
+     forkserver initialization and persistent mode are not available in afl-gcc
+     and afl-clang. */
+  if (compiler_mode != GCC && compiler_mode != CLANG) {
 
-     1) We need to convince the compiler not to optimize out the signature.
-        This is done with __attribute__((used)).
+    cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
 
-     2) We need to convince the linker, when called with -Wl,--gc-sections,
-        not to do the same. This is done by forcing an assignment to a
-        'volatile' pointer.
+    /* When the user tries to use persistent or deferred forkserver modes by
+       appending a single line to the program, we want to reliably inject a
+       signature into the binary (to be picked up by afl-fuzz) and we want
+       to call a function from the runtime .o file. This is unnecessarily
+       painful for three reasons:
 
-     3) We need to declare __afl_persistent_loop() in the global namespace,
-        but doing this within a method in a class is hard - :: and extern "C"
-        are forbidden and __attribute__((alias(...))) doesn't work. Hence the
-        __asm__ aliasing trick.
+       1) We need to convince the compiler not to optimize out the signature.
+          This is done with __attribute__((used)).
 
-   */
+       2) We need to convince the linker, when called with -Wl,--gc-sections,
+          not to do the same. This is done by forcing an assignment to a
+          'volatile' pointer.
 
-  cc_params[cc_par_cnt++] =
-      "-D__AFL_FUZZ_INIT()="
-      "int __afl_sharedmem_fuzzing = 1;"
-      "extern unsigned int *__afl_fuzz_len;"
-      "extern unsigned char *__afl_fuzz_ptr;"
-      "unsigned char __afl_fuzz_alt[1048576];"
-      "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
+       3) We need to declare __afl_persistent_loop() in the global namespace,
+          but doing this within a method in a class is hard - :: and extern "C"
+          are forbidden and __attribute__((alias(...))) doesn't work. Hence the
+          __asm__ aliasing trick.
+
+     */
+
+    cc_params[cc_par_cnt++] =
+        "-D__AFL_FUZZ_INIT()="
+        "int __afl_sharedmem_fuzzing = 1;"
+        "extern unsigned int *__afl_fuzz_len;"
+        "extern unsigned char *__afl_fuzz_ptr;"
+        "unsigned char __afl_fuzz_alt[1048576];"
+        "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
+
+  }
 
   if (plusplus_mode) {
 
@@ -1169,35 +1177,39 @@ static void edit_params(u32 argc, char **argv, char **envp) {
       "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
       "? 0 : *__afl_fuzz_len)";
 
-  cc_params[cc_par_cnt++] =
-      "-D__AFL_LOOP(_A)="
-      "({ static volatile const char *_B __attribute__((used,unused)); "
-      " _B = (const char*)\"" PERSIST_SIG
-      "\"; "
-      "extern int __afl_connected;"
+  if (compiler_mode != GCC && compiler_mode != CLANG) {
+
+    cc_params[cc_par_cnt++] =
+        "-D__AFL_LOOP(_A)="
+        "({ static volatile const char *_B __attribute__((used,unused)); "
+        " _B = (const char*)\"" PERSIST_SIG
+        "\"; "
+        "extern int __afl_connected;"
 #ifdef __APPLE__
-      "__attribute__((visibility(\"default\"))) "
-      "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
+        "__attribute__((visibility(\"default\"))) "
+        "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
 #else
-      "__attribute__((visibility(\"default\"))) "
-      "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
+        "__attribute__((visibility(\"default\"))) "
+        "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
 #endif                                                        /* ^__APPLE__ */
-      // if afl is connected, we run _A times, else once.
-      "_L(__afl_connected ? _A : 1); })";
+        // if afl is connected, we run _A times, else once.
+        "_L(__afl_connected ? _A : 1); })";
 
-  cc_params[cc_par_cnt++] =
-      "-D__AFL_INIT()="
-      "do { static volatile const char *_A __attribute__((used,unused)); "
-      " _A = (const char*)\"" DEFER_SIG
-      "\"; "
+    cc_params[cc_par_cnt++] =
+        "-D__AFL_INIT()="
+        "do { static volatile const char *_A __attribute__((used,unused)); "
+        " _A = (const char*)\"" DEFER_SIG
+        "\"; "
 #ifdef __APPLE__
-      "__attribute__((visibility(\"default\"))) "
-      "void _I(void) __asm__(\"___afl_manual_init\"); "
+        "__attribute__((visibility(\"default\"))) "
+        "void _I(void) __asm__(\"___afl_manual_init\"); "
 #else
-      "__attribute__((visibility(\"default\"))) "
-      "void _I(void) __asm__(\"__afl_manual_init\"); "
+        "__attribute__((visibility(\"default\"))) "
+        "void _I(void) __asm__(\"__afl_manual_init\"); "
 #endif                                                        /* ^__APPLE__ */
-      "_I(); } while (0)";
+        "_I(); } while (0)";
+
+  }
 
   if (x_set) {