mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-19 04:58:08 +00:00
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. ]
This commit is contained in:
108
src/afl-cc.c
108
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";
|
if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
|
||||||
#endif
|
#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++] = "-D__AFL_COMPILER=1";
|
||||||
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=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
|
/* As documented in instrumentation/README.persistent_mode.md, deferred
|
||||||
appending a single line to the program, we want to reliably inject a
|
forkserver initialization and persistent mode are not available in afl-gcc
|
||||||
signature into the binary (to be picked up by afl-fuzz) and we want
|
and afl-clang. */
|
||||||
to call a function from the runtime .o file. This is unnecessarily
|
if (compiler_mode != GCC && compiler_mode != CLANG) {
|
||||||
painful for three reasons:
|
|
||||||
|
|
||||||
1) We need to convince the compiler not to optimize out the signature.
|
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
|
||||||
This is done with __attribute__((used)).
|
|
||||||
|
|
||||||
2) We need to convince the linker, when called with -Wl,--gc-sections,
|
/* When the user tries to use persistent or deferred forkserver modes by
|
||||||
not to do the same. This is done by forcing an assignment to a
|
appending a single line to the program, we want to reliably inject a
|
||||||
'volatile' pointer.
|
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,
|
1) We need to convince the compiler not to optimize out the signature.
|
||||||
but doing this within a method in a class is hard - :: and extern "C"
|
This is done with __attribute__((used)).
|
||||||
are forbidden and __attribute__((alias(...))) doesn't work. Hence the
|
|
||||||
__asm__ aliasing trick.
|
|
||||||
|
|
||||||
*/
|
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++] =
|
3) We need to declare __afl_persistent_loop() in the global namespace,
|
||||||
"-D__AFL_FUZZ_INIT()="
|
but doing this within a method in a class is hard - :: and extern "C"
|
||||||
"int __afl_sharedmem_fuzzing = 1;"
|
are forbidden and __attribute__((alias(...))) doesn't work. Hence the
|
||||||
"extern unsigned int *__afl_fuzz_len;"
|
__asm__ aliasing trick.
|
||||||
"extern unsigned char *__afl_fuzz_ptr;"
|
|
||||||
"unsigned char __afl_fuzz_alt[1048576];"
|
*/
|
||||||
"unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
|
|
||||||
|
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) {
|
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 "
|
"(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
|
||||||
"? 0 : *__afl_fuzz_len)";
|
"? 0 : *__afl_fuzz_len)";
|
||||||
|
|
||||||
cc_params[cc_par_cnt++] =
|
if (compiler_mode != GCC && compiler_mode != CLANG) {
|
||||||
"-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\"); "
|
|
||||||
#else
|
|
||||||
"__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); })";
|
|
||||||
|
|
||||||
cc_params[cc_par_cnt++] =
|
cc_params[cc_par_cnt++] =
|
||||||
"-D__AFL_INIT()="
|
"-D__AFL_LOOP(_A)="
|
||||||
"do { static volatile const char *_A __attribute__((used,unused)); "
|
"({ static volatile const char *_B __attribute__((used,unused)); "
|
||||||
" _A = (const char*)\"" DEFER_SIG
|
" _B = (const char*)\"" PERSIST_SIG
|
||||||
"\"; "
|
"\"; "
|
||||||
|
"extern int __afl_connected;"
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
"__attribute__((visibility(\"default\"))) "
|
"__attribute__((visibility(\"default\"))) "
|
||||||
"void _I(void) __asm__(\"___afl_manual_init\"); "
|
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
|
||||||
#else
|
#else
|
||||||
"__attribute__((visibility(\"default\"))) "
|
"__attribute__((visibility(\"default\"))) "
|
||||||
"void _I(void) __asm__(\"__afl_manual_init\"); "
|
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
|
||||||
#endif /* ^__APPLE__ */
|
#endif /* ^__APPLE__ */
|
||||||
"_I(); } while (0)";
|
// 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
|
||||||
|
"\"; "
|
||||||
|
#ifdef __APPLE__
|
||||||
|
"__attribute__((visibility(\"default\"))) "
|
||||||
|
"void _I(void) __asm__(\"___afl_manual_init\"); "
|
||||||
|
#else
|
||||||
|
"__attribute__((visibility(\"default\"))) "
|
||||||
|
"void _I(void) __asm__(\"__afl_manual_init\"); "
|
||||||
|
#endif /* ^__APPLE__ */
|
||||||
|
"_I(); } while (0)";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (x_set) {
|
if (x_set) {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user