Files
AFLplusplus/instrumentation
van Hauser 602eceed8b push to stable (#1983)
* Output afl-clang-fast stuffs only if necessary (#1912)

* afl-cc header

* afl-cc common declarations

 - Add afl-cc-state.c
 - Strip includes, find_object, debug/be_quiet/have_*/callname setting from afl-cc.c
 - Use debugf_args in main
 - Modify execvp stuffs to fit new aflcc struct

* afl-cc show usage

* afl-cc mode selecting

1. compiler_mode by callname in argv[0]
2. compiler_mode by env "AFL_CC_COMPILER"
3. compiler_mode/instrument_mode by command line options "--afl-..."
4. instrument_mode/compiler_mode by various env vars including "AFL_LLVM_INSTRUMENT"
5. final checking steps
6. print "... - mode: %s-%s\n"
7. determine real argv[0] according to compiler_mode

* afl-cc macro defs

* afl-cc linking behaviors

* afl-cc fsanitize behaviors

* afl-cc misc

* afl-cc body update

* afl-cc all-in-one

formated with custom-format.py

* nits

---------

Co-authored-by: vanhauser-thc <vh@thc.org>

* changelog

* update grammar mutator

* lto llvm 12+

* docs(custom_mutators): fix missing ':' (#1953)

* Fix broken LTO mode and response file support (#1948)

* Strip `-Wl,-no-undefined` during compilation (#1952)

Make the compiler wrapper stripping `-Wl,-no-undefined` in addition to `-Wl,--no-undefined`.
Both versions of the flag are accepted by clang and, therefore, used by building systems in the wild (e.g., samba will not build without this fix).

* Remove dead code in write_to_testcase (#1955)

The custom_mutators_count check in if case is duplicate with if condition.
The else case is custom_mutators_count == 0, neither custom_mutator_list iteration nor sent check needed.

Signed-off-by: Xeonacid <h.dwwwwww@gmail.com>

* update qemuafl

* WIP: Add ability to generate drcov trace using QEMU backend (#1956)

* Document new drcov QEMU plugin

* Add link to lightkeeper for QEMU drcov file loading

---------

Co-authored-by: Jean-Romain Garnier <jean-romain.garnier@airbus.com>

* code format

* changelog

* sleep on uid != 0 afl-system-config

* fix segv about skip_next, warn on unsupported cases of linking options (#1958)

* todos

* ensure afl-cc only allows available compiler modes

* update grammar mutator

* disable aslr on apple

* fix for arm64

* help selective instrumentation

* typos

* macos

* add compiler test script

* apple fixes

* bump nyx submodules (#1963)

* fix docs

* update changelog

* update grammar mutator

* improve compiler test script

* gcc asan workaround (#1966)

* fix github merge fuckup

* fix

* Fix afl-cc (#1968)

- Check if too many cmdline params here, each time before insert a new param.
 - Check if it is "-fsanitize=..." before we do sth.
 - Remove improper param_st transfer.

* Avoid adding llvmnative instrumentation when linking rust sanitizer runtime (#1969)

* Dynamic instrumentation filtering for LLVM native (#1971)

* Add two dynamic instrumentation filter methods to runtime

* Always use pc-table with native pcguard

* Add make_symbol_list.py and README

* changelog

* todos

* new forkserver check

* fix

* nyx test for CI

* improve nyx docs

* Fixes to afl-cc and documentation (#1974)

* Always compile with -ldl when building for CODE_COVERAGE

When building with CODE_COVERAGE, the afl runtime contains code that
calls `dladdr` which requires -ldl. Under most circumstances, clang
already adds this (e.g. when building with pc-table), but there are some
circumstances where it isn't added automatically.

* Add visibility declaration to __afl_connected

When building with hidden visibility, the use of __AFL_LOOP inside such
code can cause linker errors due to __afl_connected being declared
"hidden".

* Update docs to clarify that CODE_COVERAGE=1 is required for dynamic_covfilter

* nits

* nyx build script updates

* test error output

* debug ci

* debug ci

* Improve afl-cc (#1975)

* update response file support

 - full support of rsp file
 - fix some segv issues

* Improve afl-cc

 - remove dead code about allow/denylist options of sancov
 - missing `if (!aflcc->have_msan)`
 - add docs for each function
 - typo

* enable nyx

* debug ci

* debug ci

* debug ci

* debug ci

* debug ci

* debug ci

* debug ci

* debug ci

* fix ci

* clean test script

* NO_NYX

* NO_NYX

* fix ci

* debug ci

* fix ci

* finalize ci fix

* Enhancement on Deterministic stage (#1972)

* fuzzer: init commit based on aflpp 60dc37a8cf

* fuzzers: adding the skip variables and initialize

* log: profile the det/havoc finding

* log: add profile log output

* fuzzers: sperate log/skipdet module

* fuzzers: add quick eff_map calc

* fuzzers: add skip_eff_map in fuzz_one

* fuzzers: mark whole input space in eff_map

* fuzzers: add undet bit threshold to skip some seeds

* fuzzers: fix one byte overflow

* fuzzers: fix overflow

* fix code format

* add havoc only again

* code format

* remove log to INTROSPECTION, rename skipdet module

* rename skipdet module

* remove log to stats

* clean redundant code

* code format

* remove redundant code format check

* remove redundant doc

* remove redundant objects

* clean files

* change -d to default skipdet

* disable deterministic when using CUSTOM_MUTATOR

* revert fix

* final touches for skipdet

* remove unused var

* remove redundant eff struct (#1977)

* update QEMU-Nyx submodule (#1978)

* update QEMU-Nyx submodule (#1980)

* Fix type in AFL_NOOPT env variable in afl-cc help message (#1982)

* nits

* 2024 v4.10c release

* fixes

---------

Signed-off-by: Xeonacid <h.dwwwwww@gmail.com>
Co-authored-by: Sonic <50692172+SonicStark@users.noreply.github.com>
Co-authored-by: Xeonacid <h.dwwwwww@gmail.com>
Co-authored-by: Nils Bars <nils.bars@rub.de>
Co-authored-by: Jean-Romain Garnier <7504819+JRomainG@users.noreply.github.com>
Co-authored-by: Jean-Romain Garnier <jean-romain.garnier@airbus.com>
Co-authored-by: Sergej Schumilo <sergej@schumilo.de>
Co-authored-by: Christian Holler (:decoder) <choller@mozilla.com>
Co-authored-by: Han Zheng <35988108+kdsjZh@users.noreply.github.com>
Co-authored-by: Khaled Yakdan <yakdan@code-intelligence.com>
2024-02-03 10:55:51 +00:00
..
2024-02-03 10:55:51 +00:00
2024-02-03 10:55:51 +00:00
2024-02-03 10:55:51 +00:00
2024-02-01 14:13:07 +00:00
2023-05-17 15:25:26 +02:00
2024-02-03 10:55:51 +00:00
2021-11-06 10:28:22 +01:00
2024-02-03 10:55:51 +00:00
2024-02-03 10:55:51 +00:00
2023-12-24 10:35:02 +01:00
2022-05-31 11:10:37 +02:00
2024-02-03 10:55:51 +00:00
2021-12-02 21:08:26 +01:00
2023-07-05 13:03:17 +02:00
2024-02-01 14:13:07 +00:00
2023-12-24 10:35:02 +01:00
2023-11-06 10:13:59 +01:00

llvm_mode persistent mode

1) Introduction

In persistent mode, AFL++ fuzzes a target multiple times in a single forked process, instead of forking a new process for each fuzz execution. This is the most effective way to fuzz, as the speed can easily be x10 or x20 times faster without any disadvantages. All professional fuzzing uses this mode.

Persistent mode requires that the target can be called in one or more functions, and that it's state can be completely reset so that multiple calls can be performed without resource leaks, and that earlier runs will have no impact on future runs. An indicator for this is the stability value in the afl-fuzz UI. If this decreases to lower values in persistent mode compared to non-persistent mode, then the fuzz target keeps state.

Examples can be found in utils/persistent_mode.

2) TL;DR:

Example fuzz_target.c:

#include "what_you_need_for_your_target.h"

__AFL_FUZZ_INIT();

main() {

  // anything else here, e.g. command line arguments, initialization, etc.

#ifdef __AFL_HAVE_MANUAL_CONTROL
  __AFL_INIT();
#endif

  unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;  // must be after __AFL_INIT
                                                 // and before __AFL_LOOP!

  while (__AFL_LOOP(10000)) {

    int len = __AFL_FUZZ_TESTCASE_LEN;  // don't use the macro directly in a
                                        // call!

    if (len < 8) continue;  // check for a required/useful minimum input length

    /* Setup function call, e.g. struct target *tmp = libtarget_init() */
    /* Call function to be fuzzed, e.g.: */
    target_function(buf, len);
    /* Reset state. e.g. libtarget_free(tmp) */

  }

  return 0;

}

And then compile:

afl-clang-fast -o fuzz_target fuzz_target.c -lwhat_you_need_for_your_target

And that is it! The speed increase is usually x10 to x20.

If you want to be able to compile the target without afl-clang-fast/lto, then add this just after the includes:

#ifndef __AFL_FUZZ_TESTCASE_LEN
  ssize_t fuzz_len;
  #define __AFL_FUZZ_TESTCASE_LEN fuzz_len
  unsigned char fuzz_buf[1024000];
  #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
  #define __AFL_FUZZ_INIT() void sync(void);
  #define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
  #define __AFL_INIT() sync()
#endif

3) Deferred initialization

AFL++ tries to optimize performance by executing the targeted binary just once, stopping it just before main(), and then cloning this "main" process to get a steady supply of targets to fuzz.

Although this approach eliminates much of the OS-, linker- and libc-level costs of executing the program, it does not always help with binaries that perform other time-consuming initialization steps - say, parsing a large config file before getting to the fuzzed data.

In such cases, it's beneficial to initialize the forkserver a bit later, once most of the initialization work is already done, but before the binary attempts to read the fuzzed input and parse it; in some cases, this can offer a 10x+ performance gain. You can implement delayed initialization in LLVM mode in a fairly simple way.

First, find a suitable location in the code where the delayed cloning can take place. This needs to be done with extreme care to avoid breaking the binary. In particular, the program will probably malfunction if you select a location after:

  • The creation of any vital threads or child processes - since the forkserver can't clone them easily.

  • The initialization of timers via setitimer() or equivalent calls.

  • The creation of temporary files, network sockets, offset-sensitive file descriptors, and similar shared-state resources - but only provided that their state meaningfully influences the behavior of the program later on.

  • Any access to the fuzzed input, including reading the metadata about its size.

With the location selected, add this code in the appropriate spot:

#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!

4) Persistent mode

Some libraries provide APIs that are stateless, or whose state can be reset in between processing different input files. When such a reset is performed, a single long-lived process can be reused to try out multiple test cases, eliminating the need for repeated fork() calls and the associated OS overhead.

The basic structure of the program that does this would be:

  while (__AFL_LOOP(1000)) {

    /* Read input data. */
    /* Call library code to be fuzzed. */
    /* Reset state. */

  }

  /* Exit normally. */

The numerical value specified within the loop controls the maximum number of iterations before AFL++ will restart the process from scratch. This minimizes the impact of memory leaks and similar glitches; 1000 is a good starting point, and going much higher increases the likelihood of hiccups without giving you any real performance benefits.

A more detailed template is shown in utils/persistent_mode. Similarly to the deferred initialization, the feature works only with afl-clang-fast; #ifdef guards can be used to suppress it when using other compilers.

Note that as with the deferred initialization, the feature is easy to misuse; if you do not fully reset the critical state, you may end up with false positives or waste a whole lot of CPU power doing nothing useful at all. Be particularly wary of memory leaks and of the state of file descriptors.

When running in this mode, the execution paths will inherently vary a bit depending on whether the input loop is being entered for the first time or executed again.

5) Shared memory fuzzing

You can speed up the fuzzing process even more by receiving the fuzzing data via shared memory instead of stdin or files. This is a further speed multiplier of about 2x.

Setting this up is very easy:

After the includes set the following macro:

__AFL_FUZZ_INIT();

Directly at the start of main - or if you are using the deferred forkserver with __AFL_INIT(), then after __AFL_INIT():

  unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;

Then as first line after the __AFL_LOOP while loop:

  int len = __AFL_FUZZ_TESTCASE_LEN;

And that is all!