Merge pull request #392 from AFLplusplus/dev

Push to master
This commit is contained in:
van Hauser 2020-06-09 19:25:09 +02:00 committed by GitHub
commit 12bdefe00e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1475 additions and 386 deletions

View File

@ -100,7 +100,7 @@ ifeq "$(shell uname -s)" "DragonFly"
endif endif
ifeq "$(shell uname -s)" "OpenBSD" ifeq "$(shell uname -s)" "OpenBSD"
override CFLAGS += -I /usr/local/include/ override CFLAGS += -I /usr/local/include/ -mno-retpoline
LDFLAGS += -Wl,-z,notext -L /usr/local/lib/ LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
endif endif

View File

@ -62,7 +62,7 @@
* LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass) * LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
A more thorough list is available in the PATCHES file. A more thorough list is available in the [PATCHES](docs/PATCHES.md) file.
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode | | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
| ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:| | ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:|
@ -134,6 +134,8 @@ For everyone who wants to contribute (and send pull requests) please read
## Building and installing afl++ ## Building and installing afl++
An easy way to install afl++ with everything compiled is available via docker: An easy way to install afl++ with everything compiled is available via docker:
You can use the [Dockerfile](Dockerfile) (which has gcc-10 and clang-11 -
hence afl-clang-lto is available!) or just pull directly from the docker hub:
```shell ```shell
docker pull aflplusplus/aflplusplus docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
@ -149,6 +151,8 @@ sudo apt install build-essential libtool-bin python3-dev automake flex bison lib
make distrib make distrib
sudo make install sudo make install
``` ```
It is recommended to install the newest available gcc and clang and llvm-dev
possible in your distribution!
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
more. If you just want plain afl then do "make all", however compiling and more. If you just want plain afl then do "make all", however compiling and
@ -193,17 +197,6 @@ These build options exist:
e.g.: make ASAN_BUILD=1 e.g.: make ASAN_BUILD=1
Note that afl++ is faster and better the newer the compilers used are.
Hence at least gcc-9 and especially llvm-9 should be the compilers of choice.
If your distribution does not have them, you can use the Dockerfile:
```shell
cd AFLplusplus
sudo docker build -t aflplusplus .
```
## Challenges of guided fuzzing ## Challenges of guided fuzzing
Fuzzing is one of the most powerful and proven strategies for identifying Fuzzing is one of the most powerful and proven strategies for identifying
@ -388,10 +381,10 @@ The available schedules are:
- rare (experimental) - rare (experimental)
In parallel mode (-M/-S, several instances with the shared queue), we suggest to In parallel mode (-M/-S, several instances with the shared queue), we suggest to
run the master using the explore or fast schedule (-p explore) and the slaves run the main node using the explore or fast schedule (-p explore) and the secondary
with a combination of cut-off-exponential (-p coe), exponential (-p fast), nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast),
explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does
not perform well for a target, restart the slave with a different schedule. not perform well for a target, restart the secondary nodes with a different schedule.
In single mode, using -p fast is usually slightly more beneficial than the In single mode, using -p fast is usually slightly more beneficial than the
default explore mode. default explore mode.

View File

@ -11,19 +11,22 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version ++2.65d (dev) ### Version ++2.65d (dev)
- afl-fuzz: - afl-fuzz:
- -S slaves now only sync from the master to increase performance, - -S secondary nodes now only sync from the main node to increase performance,
the -M master still syncs from everyone. Added checks that ensure the -M main node still syncs from everyone. Added checks that ensure
exactly one master is present and warn otherwise exactly one main node is present and warn otherwise
- If no master is present at a sync one slave automatically becomes - If no main node is present at a sync one secondary node automatically becomes
a temporary master until a real master shows up a temporary main node until a real main nodes shows up
- fix/update to MOpt (thanks to arnow117) - fix/update to MOpt (thanks to arnow117)
- llvm_mode: - llvm_mode:
- the default instrumentation is now PCGUARD, as it is faster and provides - the default instrumentation is now PCGUARD, as it is faster and provides
better coverage. The original afl instrumentation can be set via better coverage. The original afl instrumentation can be set via
AFL_LLVM_INSTRUMENT=AFL. This is automatically done when the WHITELIST AFL_LLVM_INSTRUMENT=AFL. This is automatically done when the WHITELIST
feature is used. feature is used.
- some targets want a ld variant for LD that is not gcc/clang but ld, added
afl-ld-lto to solve this
- lowered minimum required llvm version to 3.4 (except LLVMInsTrim, - lowered minimum required llvm version to 3.4 (except LLVMInsTrim,
which needs 3.8.0) which needs 3.8.0)
- WHITELIST feature now supports wildcards (thanks to sirmc)
- small change to cmplog to make it work with current llvm 11-dev - small change to cmplog to make it work with current llvm 11-dev
- added AFL_LLVM_LAF_ALL, sets all laf-intel settings - added AFL_LLVM_LAF_ALL, sets all laf-intel settings
- LTO whitelist functionality rewritten, now main, _init etc functions - LTO whitelist functionality rewritten, now main, _init etc functions
@ -32,6 +35,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
tried to be instrumented with LTO tried to be instrumented with LTO
- fixed crash in cmplog with LTO - fixed crash in cmplog with LTO
- enable snapshot lkm also for persistent mode - enable snapshot lkm also for persistent mode
- Unicornafl
- Added powerPC support from unicorn/next
- persistent mode shared memory testcase handover (instead of via - persistent mode shared memory testcase handover (instead of via
files/stdin) - 10-100% performance increase files/stdin) - 10-100% performance increase
- General support for 64 bit PowerPC, RiscV, Sparc etc. - General support for 64 bit PowerPC, RiscV, Sparc etc.

View File

@ -4,7 +4,7 @@
it allows for very fast and coverage guided fuzzing. it allows for very fast and coverage guided fuzzing.
However, if there is only the binary program and no source code available, However, if there is only the binary program and no source code available,
then standard `afl-fuzz -n` (dumb mode) is not effective. then standard `afl-fuzz -n` (non-instrumented mode) is not effective.
The following is a description of how these binaries can be fuzzed with afl++ The following is a description of how these binaries can be fuzzed with afl++

View File

@ -28,9 +28,9 @@ Note that ASAN is incompatible with -static, so be mindful of that.
(You can also use AFL_USE_MSAN=1 to enable MSAN instead.) (You can also use AFL_USE_MSAN=1 to enable MSAN instead.)
NOTE: if you run several slaves only one should run the target compiled with NOTE: if you run several secondary instances, only one should run the target
ASAN (and UBSAN, CFISAN), the others should run the target with no sanitizers compiled with ASAN (and UBSAN, CFISAN), the others should run the target with
compiled in. no sanitizers compiled in.
There is also the option of generating a corpus using a non-ASAN binary, and There is also the option of generating a corpus using a non-ASAN binary, and
then feeding it to an ASAN-instrumented one to check for bugs. This is faster, then feeding it to an ASAN-instrumented one to check for bugs. This is faster,

View File

@ -13,12 +13,12 @@ In fact, if you rely on just a single job on a multi-core system, you will
be underutilizing the hardware. So, parallelization is usually the right be underutilizing the hardware. So, parallelization is usually the right
way to go. way to go.
When targeting multiple unrelated binaries or using the tool in "dumb" (-n) When targeting multiple unrelated binaries or using the tool in
mode, it is perfectly fine to just start up several fully separate instances "non-instrumented" (-n) mode, it is perfectly fine to just start up several
of afl-fuzz. The picture gets more complicated when you want to have multiple fully separate instances of afl-fuzz. The picture gets more complicated when
fuzzers hammering a common target: if a hard-to-hit but interesting test case you want to have multiple fuzzers hammering a common target: if a hard-to-hit
is synthesized by one fuzzer, the remaining instances will not be able to use but interesting test case is synthesized by one fuzzer, the remaining instances
that input to guide their work. will not be able to use that input to guide their work.
To help with this problem, afl-fuzz offers a simple way to synchronize test To help with this problem, afl-fuzz offers a simple way to synchronize test
cases on the fly. cases on the fly.
@ -37,7 +37,7 @@ system, simply create a new, empty output directory ("sync dir") that will be
shared by all the instances of afl-fuzz; and then come up with a naming scheme shared by all the instances of afl-fuzz; and then come up with a naming scheme
for every instance - say, "fuzzer01", "fuzzer02", etc. for every instance - say, "fuzzer01", "fuzzer02", etc.
Run the first one ("master", -M) like this: Run the first one ("main node", -M) like this:
``` ```
./afl-fuzz -i testcase_dir -o sync_dir -M fuzzer01 [...other stuff...] ./afl-fuzz -i testcase_dir -o sync_dir -M fuzzer01 [...other stuff...]
@ -57,26 +57,26 @@ Each fuzzer will keep its state in a separate subdirectory, like so:
Each instance will also periodically rescan the top-level sync directory Each instance will also periodically rescan the top-level sync directory
for any test cases found by other fuzzers - and will incorporate them into for any test cases found by other fuzzers - and will incorporate them into
its own fuzzing when they are deemed interesting enough. its own fuzzing when they are deemed interesting enough.
For performance reasons only -M masters sync the queue with everyone, the For performance reasons only -M main node syncs the queue with everyone, the
-S slaves will only sync from the master. -S secondary nodes will only sync from the main node.
The difference between the -M and -S modes is that the master instance will The difference between the -M and -S modes is that the main instance will
still perform deterministic checks; while the secondary instances will still perform deterministic checks; while the secondary instances will
proceed straight to random tweaks. proceed straight to random tweaks.
Note that you must always have one -M master instance! Note that you must always have one -M main instance!
Note that running multiple -M instances is wasteful, although there is an Note that running multiple -M instances is wasteful, although there is an
experimental support for parallelizing the deterministic checks. To leverage experimental support for parallelizing the deterministic checks. To leverage
that, you need to create -M instances like so: that, you need to create -M instances like so:
``` ```
./afl-fuzz -i testcase_dir -o sync_dir -M masterA:1/3 [...] ./afl-fuzz -i testcase_dir -o sync_dir -M mainA:1/3 [...]
./afl-fuzz -i testcase_dir -o sync_dir -M masterB:2/3 [...] ./afl-fuzz -i testcase_dir -o sync_dir -M mainB:2/3 [...]
./afl-fuzz -i testcase_dir -o sync_dir -M masterC:3/3 [...] ./afl-fuzz -i testcase_dir -o sync_dir -M mainC:3/3 [...]
``` ```
...where the first value after ':' is the sequential ID of a particular master ...where the first value after ':' is the sequential ID of a particular main
instance (starting at 1), and the second value is the total number of fuzzers to instance (starting at 1), and the second value is the total number of fuzzers to
distribute the deterministic fuzzing across. Note that if you boot up fewer distribute the deterministic fuzzing across. Note that if you boot up fewer
fuzzers than indicated by the second number passed to -M, you may end up with fuzzers than indicated by the second number passed to -M, you may end up with
@ -168,7 +168,7 @@ to keep in mind:
This arrangement would allow test interesting cases to propagate across This arrangement would allow test interesting cases to propagate across
the fleet without having to copy every fuzzer queue to every single host. the fleet without having to copy every fuzzer queue to every single host.
- You do not want a "master" instance of afl-fuzz on every system; you should - You do not want a "main" instance of afl-fuzz on every system; you should
run them all with -S, and just designate a single process somewhere within run them all with -S, and just designate a single process somewhere within
the fleet to run with -M. the fleet to run with -M.
@ -185,10 +185,10 @@ also basic machine-readable information always written to the fuzzer_stats file
in the output directory. Locally, that information can be interpreted with in the output directory. Locally, that information can be interpreted with
afl-whatsup. afl-whatsup.
In principle, you can use the status screen of the master (-M) instance to In principle, you can use the status screen of the main (-M) instance to
monitor the overall fuzzing progress and decide when to stop. In this monitor the overall fuzzing progress and decide when to stop. In this
mode, the most important signal is just that no new paths are being found mode, the most important signal is just that no new paths are being found
for a longer while. If you do not have a master instance, just pick any for a longer while. If you do not have a main instance, just pick any
single secondary instance to watch and go by that. single secondary instance to watch and go by that.
You can also rely on that instance's output directory to collect the You can also rely on that instance's output directory to collect the
@ -197,7 +197,7 @@ within the fleet. Secondary (-S) instances do not require any special
monitoring, other than just making sure that they are up. monitoring, other than just making sure that they are up.
Keep in mind that crashing inputs are *not* automatically propagated to the Keep in mind that crashing inputs are *not* automatically propagated to the
master instance, so you may still want to monitor for crashes fleet-wide main instance, so you may still want to monitor for crashes fleet-wide
from within your synchronization or health checking scripts (see afl-whatsup). from within your synchronization or health checking scripts (see afl-whatsup).
## 5) Asymmetric setups ## 5) Asymmetric setups

View File

@ -25,7 +25,7 @@ where *α(i)* is the performance score that AFL uses to compute for the seed inp
More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/). More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/).
PS: In parallel mode (several instances with shared queue), we suggest to run the master using the exploit schedule (-p exploit) and the slaves with a combination of cut-off-exponential (-p coe), exponential (-p fast; default), and explore (-p explore) schedules. In single mode, the default settings will do. **EDIT:** In parallel mode, AFLFast seems to perform poorly because the path probability estimates are incorrect for the imported seeds. Pull requests to fix this issue by syncing the estimates accross instances are appreciated :) PS: In parallel mode (several instances with shared queue), we suggest to run the main node using the exploit schedule (-p exploit) and the secondary nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast; default), and explore (-p explore) schedules. In single mode, the default settings will do. **EDIT:** In parallel mode, AFLFast seems to perform poorly because the path probability estimates are incorrect for the imported seeds. Pull requests to fix this issue by syncing the estimates across instances are appreciated :)
Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved.
Released under terms and conditions of Apache License, Version 2.0. Released under terms and conditions of Apache License, Version 2.0.

View File

@ -33,7 +33,7 @@ The top line shows you which mode afl-fuzz is running in
(normal: "american fuzy lop", crash exploration mode: "peruvian rabbit mode") (normal: "american fuzy lop", crash exploration mode: "peruvian rabbit mode")
and the version of afl++. and the version of afl++.
Next to the version is the banner, which, if not set with -T by hand, will Next to the version is the banner, which, if not set with -T by hand, will
either show the binary name being fuzzed, or the -M/-S master/slave name for either show the binary name being fuzzed, or the -M/-S main/secondary name for
parallel fuzzing. parallel fuzzing.
Finally, the last item is the power schedule mode being run (default: explore). Finally, the last item is the power schedule mode being run (default: explore).
@ -404,7 +404,7 @@ directory. This includes:
- `var_byte_count` - how many edges are non-deterministic - `var_byte_count` - how many edges are non-deterministic
- `afl_banner` - banner text (e.g. the target name) - `afl_banner` - banner text (e.g. the target name)
- `afl_version` - the version of afl used - `afl_version` - the version of afl used
- `target_mode` - default, persistent, qemu, unicorn, dumb - `target_mode` - default, persistent, qemu, unicorn, non-instrumented
- `command_line` - full command line used for the fuzzing session - `command_line` - full command line used for the fuzzing session
Most of these map directly to the UI elements discussed earlier on. Most of these map directly to the UI elements discussed earlier on.

View File

@ -9,7 +9,7 @@ endif
FLAGS=-O3 -funroll-loops FLAGS=-O3 -funroll-loops
all: libAFLDriver.a all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so
aflpp_driver.o: aflpp_driver.cpp aflpp_driver.o: aflpp_driver.cpp
$(LLVM_BINDIR)clang++ $(FLAGS) -stdlib=libc++ -funroll-loops -std=c++11 -c aflpp_driver.cpp $(LLVM_BINDIR)clang++ $(FLAGS) -stdlib=libc++ -funroll-loops -std=c++11 -c aflpp_driver.cpp
@ -17,5 +17,25 @@ aflpp_driver.o: aflpp_driver.cpp
libAFLDriver.a: aflpp_driver.o libAFLDriver.a: aflpp_driver.o
ar ru libAFLDriver.a aflpp_driver.o ar ru libAFLDriver.a aflpp_driver.o
debug:
$(LLVM_BINDIR)clang++ -D_DEBUG=\"1\" $(FLAGS) -stdlib=libc++ -funroll-loops -std=c++11 -c aflpp_driver.cpp
ar ru libAFLDriver.a aflpp_driver.o
aflpp_qemu_driver.o: aflpp_qemu_driver.c
$(LLVM_BINDIR)clang $(FLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
libAFLQemuDriver.a: aflpp_qemu_driver.o
ar ru libAFLQemuDriver.a aflpp_qemu_driver.o
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so
aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c
$(LLVM_BINDIR)clang -fPIC $(FLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c
test: libAFLDriver.a aflpp_driver_test.cpp
afl-clang-fast++ -Wl,--allow-multiple-definition -stdlib=libc++ -funroll-loops -std=c++11 -o aflpp_driver_test aflpp_driver_test.cpp libAFLDriver.a
clean: clean:
rm -f *.o libAFLDriver*.a *~ core rm -f *.o libAFLDriver*.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so *~ core aflpp_driver_test

View File

@ -90,7 +90,7 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both.
#endif #endif
int __afl_sharedmem_fuzzing = 1; int __afl_sharedmem_fuzzing = 1;
extern unsigned int __afl_fuzz_len; extern unsigned int *__afl_fuzz_len;
extern unsigned char *__afl_fuzz_ptr; extern unsigned char *__afl_fuzz_ptr;
// libFuzzer interface is thin, so we don't include any libFuzzer headers. // libFuzzer interface is thin, so we don't include any libFuzzer headers.
@ -246,35 +246,38 @@ int main(int argc, char **argv) {
LLVMFuzzerInitialize(&argc, &argv); LLVMFuzzerInitialize(&argc, &argv);
// Do any other expensive one-time initialization here. // Do any other expensive one-time initialization here.
int N = 1000; uint8_t dummy_input[1] = {0};
int N = 100000;
if (argc == 2 && argv[1][0] == '-') if (argc == 2 && argv[1][0] == '-')
N = atoi(argv[1] + 1); N = atoi(argv[1] + 1);
else if(argc == 2 && (N = atoi(argv[1])) > 0) else if(argc == 2 && (N = atoi(argv[1])) > 0)
Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
else if (argc > 1) { else if (argc > 1) {
if (!getenv("AFL_DRIVER_DONT_DEFER")) { // if (!getenv("AFL_DRIVER_DONT_DEFER")) {
__afl_sharedmem_fuzzing = 0; __afl_sharedmem_fuzzing = 0;
__afl_manual_init(); __afl_manual_init();
} // }
return ExecuteFilesOnyByOne(argc, argv); return ExecuteFilesOnyByOne(argc, argv);
exit(0); exit(0);
} }
assert(N > 0); assert(N > 0);
if (!getenv("AFL_DRIVER_DONT_DEFER")) // if (!getenv("AFL_DRIVER_DONT_DEFER"))
__afl_manual_init(); __afl_manual_init();
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
// on the first execution of LLVMFuzzerTestOneInput is ignored. // on the first execution of LLVMFuzzerTestOneInput is ignored.
uint8_t dummy_input[1] = {0};
LLVMFuzzerTestOneInput(dummy_input, 1); LLVMFuzzerTestOneInput(dummy_input, 1);
int num_runs = 0; int num_runs = 0;
while (__afl_persistent_loop(N)) { while (__afl_persistent_loop(N)) {
if (__afl_fuzz_len > 0) { #ifdef _DEBUG
fprintf(stderr, "len: %u\n", *__afl_fuzz_len);
#endif
if (*__afl_fuzz_len) {
num_runs++; num_runs++;
LLVMFuzzerTestOneInput(__afl_fuzz_ptr, __afl_fuzz_len); LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
} }
} }
Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs); Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);

View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
fprintf(stderr, "Received size %lu\n", Size);
if (Size < 4)
return 0;
if (Data[0] == 'F')
if (Data[1] == 'A')
if (Data[2] == '$')
if (Data[3] == '$')
abort();
return 0;
}

View File

@ -0,0 +1,38 @@
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
static const size_t kMaxAflInputSize = 1 * 1024 * 1024;
static uint8_t AflInputBuf[kMaxAflInputSize];
void __attribute__((noinline)) afl_qemu_driver_stdin_input(void) {
size_t l = read(0, AflInputBuf, kMaxAflInputSize);
LLVMFuzzerTestOneInput(AflInputBuf, l);
}
int main(int argc, char **argv) {
if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv);
// Do any other expensive one-time initialization here.
if (getenv("AFL_QEMU_DRIVER_NO_HOOK")) {
afl_qemu_driver_stdin_input();
} else {
uint8_t dummy_input[1024000] = {0};
LLVMFuzzerTestOneInput(dummy_input, 1);
}
return 0;
}

View File

@ -0,0 +1,22 @@
#include <stdint.h>
#include <string.h>
#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
#define REGS_RDI 7
#define REGS_RSI 6
void afl_persistent_hook(uint64_t *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_len) {
memcpy(g2h(regs[REGS_RDI]), input_buf, input_len);
regs[REGS_RSI] = input_len;
}
int afl_persistent_hook_init(void) {
return 1;
}

View File

@ -1,6 +1,10 @@
all: all:
afl-clang-fast -o persistent_demo persistent_demo.c afl-clang-fast -o persistent_demo persistent_demo.c
afl-clang-fast -o persistent_demo_new persistent_demo_new.c afl-clang-fast -o persistent_demo_new persistent_demo_new.c
AFL_DONT_OPTIMIZE=1 afl-clang-fast -o test-instr test-instr.c
document:
AFL_DONT_OPTIMIZE=1 afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c
clean: clean:
rm -f persistent_demo persistent_demo_new rm -f persistent_demo persistent_demo_new test-instr

View File

@ -41,6 +41,7 @@ int main(int argc, char **argv) {
terminate normally. This limits the impact of accidental memory leaks terminate normally. This limits the impact of accidental memory leaks
and similar hiccups. */ and similar hiccups. */
__AFL_INIT();
while (__AFL_LOOP(1000)) { while (__AFL_LOOP(1000)) {
/*** PLACEHOLDER CODE ***/ /*** PLACEHOLDER CODE ***/

View File

@ -42,9 +42,10 @@ int main(int argc, char **argv) {
terminate normally. This limits the impact of accidental memory leaks terminate normally. This limits the impact of accidental memory leaks
and similar hiccups. */ and similar hiccups. */
__AFL_INIT();
buf = __AFL_FUZZ_TESTCASE_BUF; buf = __AFL_FUZZ_TESTCASE_BUF;
while (__AFL_LOOP(1000)) { while (__AFL_LOOP(1000)) { // increase if you have good stability
len = __AFL_FUZZ_TESTCASE_LEN; len = __AFL_FUZZ_TESTCASE_LEN;

View File

@ -0,0 +1,69 @@
/*
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
__AFL_FUZZ_INIT();
int main(int argc, char **argv) {
__AFL_INIT();
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
while (__AFL_LOOP(2147483647)) { // MAX_INT if you have 100% stability
unsigned int len = __AFL_FUZZ_TESTCASE_LEN;
#ifdef _AFL_DOCUMENT_MUTATIONS
static unsigned int counter = 0;
char fn[32];
sprintf(fn, "%09u:test-instr", counter);
int fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd_doc >= 0) {
if (write(fd_doc, buf, len) != __afl_fuzz_len) {
fprintf(stderr, "write of mutation file failed: %s\n", fn);
unlink(fn);
}
close(fd_doc);
}
counter++;
#endif
// fprintf(stderr, "len: %u\n", len);
if (!len) continue;
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else if (buf[0] == '1')
printf("Pretty sure that is a one!\n");
else
printf("Neither one or zero? How quaint!\n");
}
return 0;
}

View File

@ -1,6 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define g2h(x) ((void *)((unsigned long)(x) + guest_base))
#define h2g(x) ((uint64_t)(x)-guest_base) #define h2g(x) ((uint64_t)(x)-guest_base)
@ -35,16 +36,26 @@ enum {
}; };
void afl_persistent_hook(uint64_t *regs, uint64_t guest_base) { void afl_persistent_hook(uint64_t *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_len) {
// In this example the register RDI is pointing to the memory location // In this example the register RDI is pointing to the memory location
// of the target buffer, and the length of the input is in RSI. // of the target buffer, and the length of the input is in RSI.
// This can be seen with a debugger, e.g. gdb (and "disass main") // This can be seen with a debugger, e.g. gdb (and "disass main")
printf("reading into %p\n", regs[R_EDI]); printf("placing input into %p\n", regs[R_EDI]);
size_t r = read(0, g2h(regs[R_EDI]), 1024);
regs[R_ESI] = r; if (input_len > 1024) input_len = 1024;
printf("read %ld bytes\n", r); memcpy(g2h(regs[R_EDI]), input_buf, input_len);
regs[R_ESI] = input_len;
}
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
} }

View File

@ -71,7 +71,7 @@ reports to <hexcoder-@github.com>.
## 4) Bonus feature #1: deferred initialization ## 4) Bonus feature #1: deferred initialization
AFL tries to optimize performance by executing the targeted binary just once, AFL tries to optimize performance by executing the targeted binary just once,
stopping it just before main(), and then cloning this "master" process to get stopping it just before main(), and then cloning this "main" process to get
a steady supply of targets to fuzz. a steady supply of targets to fuzz.
Although this approach eliminates much of the OS-, linker- and libc-level Although this approach eliminates much of the OS-, linker- and libc-level

View File

@ -192,7 +192,7 @@ static const u8 *main_payload_32 =
#ifdef SKIP_COUNTS #ifdef SKIP_COUNTS
" orb $1, (%edx, %edi, 1)\n" " orb $1, (%edx, %edi, 1)\n"
#else #else
" incb (%edx, %edi, 1)\n" " addb $1, (%edx, %edi, 1)\n"
" adcb $0, (%edx, %edi, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact " adcb $0, (%edx, %edi, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact
#endif /* ^SKIP_COUNTS */ #endif /* ^SKIP_COUNTS */
"\n" "\n"
@ -447,7 +447,7 @@ static const u8 *main_payload_64 =
#ifdef SKIP_COUNTS #ifdef SKIP_COUNTS
" orb $1, (%rdx, %rcx, 1)\n" " orb $1, (%rdx, %rcx, 1)\n"
#else #else
" incb (%rdx, %rcx, 1)\n" " addb $1, (%rdx, %rcx, 1)\n"
" adcb $0, (%rdx, %rcx, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact " adcb $0, (%rdx, %rcx, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact
#endif /* ^SKIP_COUNTS */ #endif /* ^SKIP_COUNTS */
"\n" "\n"

View File

@ -408,8 +408,8 @@ typedef struct afl_state {
debug, /* Debug mode */ debug, /* Debug mode */
custom_only, /* Custom mutator only mode */ custom_only, /* Custom mutator only mode */
python_only, /* Python-only mode */ python_only, /* Python-only mode */
is_master, /* if this is a master */ is_main_node, /* if this is the main node */
is_slave; /* if this is a slave */ is_secondary_node; /* if this is a secondary instance */
u32 stats_update_freq; /* Stats update frequency (execs) */ u32 stats_update_freq; /* Stats update frequency (execs) */
@ -421,7 +421,7 @@ typedef struct afl_state {
u8 skip_deterministic, /* Skip deterministic stages? */ u8 skip_deterministic, /* Skip deterministic stages? */
use_splicing, /* Recombine input files? */ use_splicing, /* Recombine input files? */
dumb_mode, /* Run in non-instrumented mode? */ non_instrumented_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */ score_changed, /* Scoring for favorites changed? */
resuming_fuzz, /* Resuming an older fuzzing job? */ resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */ timeout_given, /* Specific timeout given? */
@ -444,7 +444,8 @@ typedef struct afl_state {
deferred_mode, /* Deferred forkserver mode? */ deferred_mode, /* Deferred forkserver mode? */
fixed_seed, /* do not reseed */ fixed_seed, /* do not reseed */
fast_cal, /* Try to calibrate faster? */ fast_cal, /* Try to calibrate faster? */
disable_trim; /* Never trim in fuzz_one */ disable_trim, /* Never trim in fuzz_one */
shmem_testcase_mode; /* If sharedmem testcases are used */
u8 *virgin_bits, /* Regions yet untouched by fuzzing */ u8 *virgin_bits, /* Regions yet untouched by fuzzing */
*virgin_tmout, /* Bits we haven't seen in tmouts */ *virgin_tmout, /* Bits we haven't seen in tmouts */
@ -502,7 +503,7 @@ typedef struct afl_state {
s32 stage_cur, stage_max; /* Stage progression */ s32 stage_cur, stage_max; /* Stage progression */
s32 splicing_with; /* Splicing with which test case? */ s32 splicing_with; /* Splicing with which test case? */
u32 master_id, master_max; /* Master instance job splitting */ u32 main_node_id, main_node_max; /* Main instance job splitting */
u32 syncing_case; /* Syncing with case #... */ u32 syncing_case; /* Syncing with case #... */
@ -806,6 +807,9 @@ void afl_states_clear_screen(void);
/* Sets the skip flag on all states */ /* Sets the skip flag on all states */
void afl_states_request_skip(void); void afl_states_request_skip(void);
/* Setup shmem for testcase delivery */
void setup_testcase_shmem(afl_state_t *afl);
void read_afl_environment(afl_state_t *, char **); void read_afl_environment(afl_state_t *, char **);
/**** Prototypes ****/ /**** Prototypes ****/
@ -912,7 +916,7 @@ u32 find_start_position(afl_state_t *);
void find_timeout(afl_state_t *); void find_timeout(afl_state_t *);
double get_runnable_processes(void); double get_runnable_processes(void);
void nuke_resume_dir(afl_state_t *); void nuke_resume_dir(afl_state_t *);
int check_master_exists(afl_state_t *); int check_main_node_exists(afl_state_t *);
void setup_dirs_fds(afl_state_t *); void setup_dirs_fds(afl_state_t *);
void setup_cmdline_file(afl_state_t *, char **); void setup_cmdline_file(afl_state_t *, char **);
void setup_stdio_file(afl_state_t *); void setup_stdio_file(afl_state_t *);

View File

@ -107,14 +107,7 @@ u8 *u_stringify_mem_size(u8 *buf, u64 val);
u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms); u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
/* Wrapper for select() and read(), reading exactly len bytes. /* Reads the map size from ENV */
Returns the time passed to read.
stop_soon should point to a variable indicating ctrl+c was pressed.
If the wait times out, returns timeout_ms + 1;
Returns 0 if an error occurred (fd closed, signal, ...); */
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
volatile u8 *stop_soon_p);
u32 get_map_size(void); u32 get_map_size(void);
#endif #endif

View File

@ -73,17 +73,17 @@ typedef struct afl_forkserver {
u8 last_kill_signal; /* Signal that killed the child */ u8 last_kill_signal; /* Signal that killed the child */
u8 use_shdmen_fuzz; /* use shared mem for test cases */ u8 use_shmem_fuzz; /* use shared mem for test cases */
u8 support_shdmen_fuzz; /* set by afl-fuzz */ u8 support_shmem_fuzz; /* set by afl-fuzz */
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
u8 qemu_mode; /* if running in qemu mode or not */ u8 qemu_mode; /* if running in qemu mode or not */
u32 shdmem_fuzz_len; /* length of the fuzzing test case */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */
u8 *shdmem_fuzz; /* allocated memory for fuzzing */ u8 *shmem_fuzz; /* allocated memory for fuzzing */
char *cmplog_binary; /* the name of the cmplog binary */ char *cmplog_binary; /* the name of the cmplog binary */

View File

@ -53,7 +53,7 @@ typedef struct sharedmem {
} sharedmem_t; } sharedmem_t;
u8 * afl_shm_init(sharedmem_t *, size_t, unsigned char dumb_mode); u8 * afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
void afl_shm_deinit(sharedmem_t *); void afl_shm_deinit(sharedmem_t *);
#endif #endif

View File

@ -501,3 +501,30 @@ __attribute__((constructor)) void __dislocator_init(void) {
} }
/* NetBSD fault handler specific api subset */
void (*esetfunc(void (*fn)(int, const char *, ...)))(int, const char *, ...) {
/* Might not be meaningful to implement; upper calls already report errors */
return NULL;
}
void *emalloc(size_t len) {
return malloc(len);
}
void *ecalloc(size_t elem_len, size_t elem_cnt) {
return calloc(elem_len, elem_cnt);
}
void *erealloc(void *ptr, size_t len) {
return realloc(ptr, len);
}

View File

@ -68,7 +68,7 @@ endif
ifeq "$(LLVM_MAJOR)" "11" ifeq "$(LLVM_MAJOR)" "11"
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation) $(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
LLVM_LTO = 1 LLVM_LTO = 1
TEST_MMAP = 1 #TEST_MMAP = 1
endif endif
ifeq "$(LLVM_LTO)" "0" ifeq "$(LLVM_LTO)" "0"
@ -226,13 +226,17 @@ endif
ifeq "$(shell uname)" "OpenBSD" ifeq "$(shell uname)" "OpenBSD"
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
CLANG_CFL += -mno-retpoline
CFLAGS += -mno-retpoline
# Needed for unwind symbols
LDFLAGS += -lc++abi
endif endif
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
SHMAT_OK=1 SHMAT_OK=1
else else
SHMAT_OK=0 SHMAT_OK=0
CFLAGS+=-DUSEMMAP=1 #CFLAGS+=-DUSEMMAP=1
LDFLAGS += -Wno-deprecated-declarations LDFLAGS += -Wno-deprecated-declarations
endif endif
@ -242,7 +246,7 @@ ifeq "$(TEST_MMAP)" "1"
LDFLAGS += -Wno-deprecated-declarations LDFLAGS += -Wno-deprecated-declarations
endif endif
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
# If prerequisites are not given, warn, do not build anything, and exit with code 0 # If prerequisites are not given, warn, do not build anything, and exit with code 0
ifeq "$(LLVMVER)" "" ifeq "$(LLVMVER)" ""
@ -300,7 +304,7 @@ afl-common.o: ../src/afl-common.c
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS) $(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps ../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -Dxxx $(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
ln -sf afl-clang-fast ../afl-clang-fast++ ln -sf afl-clang-fast ../afl-clang-fast++
ifneq "$(AFL_CLANG_FLTO)" "" ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1" ifeq "$(LLVM_LTO)" "1"
@ -326,6 +330,11 @@ ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o $(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
endif endif
../afl-ld-lto: afl-ld-lto.c
ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $< -o $@
endif
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o ../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1" ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
@ -354,16 +363,21 @@ endif
../cmplog-instructions-pass.so: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps ../cmplog-instructions-pass.so: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
document:
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) -Wno-unused-result -m32 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) -Wno-unused-result -m64 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps ../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@ $(CLANG_BIN) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps ../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 32-bit variant of the runtime (-m32)... " @printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CC_SAVE) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi @$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps ../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 64-bit variant of the runtime (-m64)... " @printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC_SAVE) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi @$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
test_build: $(PROGS) test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..." @echo "[*] Testing the CC wrapper and instrumentation output..."
@ -383,6 +397,7 @@ install: all
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-ld-lto ]; then set -e; install -m 755 ../afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi

View File

@ -14,9 +14,11 @@ This version requires a current llvm 11 compiled from the github master.
4. AUTODICTIONARY feature! see below 4. AUTODICTIONARY feature! see below
5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib` also 5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`.
note that if that target uses _init functions or early constructors then Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
also set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise
6. If a target uses _init functions or early constructors then additionally
set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise!
## Introduction and problem description ## Introduction and problem description
@ -61,7 +63,8 @@ AUTODICTIONARY: 11 strings found
## Getting llvm 11 ## Getting llvm 11
### Installing llvm 11 ### Installing llvm 11 from the llvm repository
Installing the llvm snapshot builds is easy and mostly painless: Installing the llvm snapshot builds is easy and mostly painless:
In the follow line change `NAME` for your Debian or Ubuntu release name In the follow line change `NAME` for your Debian or Ubuntu release name
@ -80,7 +83,7 @@ apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
``` ```
### Building llvm 11 ### Building llvm 11 yourself
Building llvm from github takes quite some long time and is not painless: Building llvm from github takes quite some long time and is not painless:
``` ```
@ -117,6 +120,9 @@ export AFL_LLVM_INSTRUMENT=CFG
make make
``` ```
NOTE: some targets also need to set the linker, try both `afl-clang-lto` and
`afl-ld-lto` for this for `LD=` for `configure`.
## AUTODICTIONARY feature ## AUTODICTIONARY feature
Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the
@ -135,6 +141,51 @@ to be dynamic - the original afl way, which is slower).
AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which
is safer but also slower). is safer but also slower).
## Solving difficult targets
Some targets are difficult because the configure script does unusual stuff that
is unexpected for afl. See the next chapter `Potential issues` how to solve
these.
An example of a hard to solve target is ffmpeg. Here is how to successfully
instrument it:
1. Get and extract the current ffmpeg and change to it's directory
2. Running configure with --cc=clang fails and various other items will fail
when compiling, so we have to trick configure:
```
./configure --enable-lto --disable-shared
```
3. Now the configuration is done - and we edit the settings in `./ffbuild/config.mak`
(-: the original line, +: what to change it into):
```
-CC=gcc
+CC=afl-clang-lto
-CXX=g++
+CXX=afl-clang-lto++
-AS=gcc
+AS=llvm-as
-LD=gcc
+LD=afl-clang-lto++
-DEPCC=gcc
+DEPCC=afl-clang-lto
-DEPAS=gcc
+DEPAS=afl-clang-lto++
-AR=ar
+AR=llvm-ar
-AR_CMD=ar
+AR_CMD=llvm-ar
-NM_CMD=nm -g
+NM_CMD=llvm-nm -g
-RANLIB=ranlib -D
+RANLIB=llvm-ranlib -D
```
4. Then type make, wait for a long time and you are done :)
## Potential issues ## Potential issues
### compiling libraries fails ### compiling libraries fails
@ -154,6 +205,16 @@ and on some target you have to to AR=/RANLIB= even for make as the configure scr
Other targets ignore environment variables and need the parameters set via Other targets ignore environment variables and need the parameters set via
`./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!). `./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!).
If you see this message
```
assembler command failed ...
```
then try setting `llvm-as` for configure:
```
AS=llvm-as ...
```
### compiling programs still fail ### compiling programs still fail
afl-clang-lto is still work in progress. afl-clang-lto is still work in progress.
@ -166,11 +227,12 @@ Hence if building a target with afl-clang-lto fails try to build it with llvm11
and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and
`CXXFLAGS=-flto=full`). `CXXFLAGS=-flto=full`).
An example that does not build with llvm 11 and LTO is ffmpeg.
If this succeeeds then there is an issue with afl-clang-lto. Please report at If this succeeeds then there is an issue with afl-clang-lto. Please report at
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226) [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
Even some targets where clang-11 fails can be build if the fail is just in
`./configure`, see `Solving difficult targets` above.
### Target crashes immediately ### Target crashes immediately
If the target is using early constructors (priority values smaller than 6) If the target is using early constructors (priority values smaller than 6)

View File

@ -55,7 +55,7 @@ The speed increase is usually x10 to x20.
## 3) deferred initialization ## 3) deferred initialization
AFL tries to optimize performance by executing the targeted binary just once, AFL tries to optimize performance by executing the targeted binary just once,
stopping it just before main(), and then cloning this "master" process to get stopping it just before main(), and then cloning this "main" process to get
a steady supply of targets to fuzz. a steady supply of targets to fuzz.
Although this approach eliminates much of the OS-, linker- and libc-level Although this approach eliminates much of the OS-, linker- and libc-level

View File

@ -73,3 +73,7 @@ For old LLVM versions this feature might require to be compiled with debug
information (-g), however at least from llvm version 6.0 onwards this is not information (-g), however at least from llvm version 6.0 onwards this is not
required anymore (and might hurt performance and crash detection, so better not required anymore (and might hurt performance and crash detection, so better not
use -g). use -g).
## 4) UNIX-style filename pattern matching
You can add UNIX-style pattern matching in the whitelist entries. See `man
fnmatch` for the syntax. We do not set any of the `fnmatch` flags.

View File

@ -176,7 +176,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
"Using afl-clang-lto is not possible because Makefile magic did not " "Using afl-clang-lto is not possible because Makefile magic did not "
"identify the correct -flto flag"); "identify the correct -flto flag");
if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) { if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++") ||
!strcmp(name, "afl-clang++")) {
u8 *alt_cxx = getenv("AFL_CXX"); u8 *alt_cxx = getenv("AFL_CXX");
if (USE_BINDIR) if (USE_BINDIR)
@ -188,7 +189,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} else if (!strcmp(name, "afl-clang-fast") || } else if (!strcmp(name, "afl-clang-fast") ||
!strcmp(name, "afl-clang-lto")) { !strcmp(name, "afl-clang-lto") || !strcmp(name, "afl-clang")) {
u8 *alt_cc = getenv("AFL_CC"); u8 *alt_cc = getenv("AFL_CC");
if (USE_BINDIR) if (USE_BINDIR)
@ -494,14 +495,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = cc_params[cc_par_cnt++] =
"-D__AFL_FUZZ_INIT()=" "-D__AFL_FUZZ_INIT()="
"int __afl_sharedmem_fuzzing = 1;" "int __afl_sharedmem_fuzzing = 1;"
"extern unsigned int __afl_fuzz_len;" "extern unsigned int *__afl_fuzz_len;"
"extern unsigned char *__afl_fuzz_ptr;" "extern unsigned char *__afl_fuzz_ptr;"
"unsigned char *__afl_fuzz_alt_ptr;"; "unsigned char *__afl_fuzz_alt_ptr;";
cc_params[cc_par_cnt++] = cc_params[cc_par_cnt++] =
"-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : " "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
"(__afl_fuzz_alt_ptr = malloc(1 * 1024 * 1024)))"; "(__afl_fuzz_alt_ptr = malloc(1 * 1024 * 1024)))";
cc_params[cc_par_cnt++] = cc_params[cc_par_cnt++] =
"-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? __afl_fuzz_len : read(0, " "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : read(0, "
"__afl_fuzz_alt_ptr, 1 * 1024 * 1024))"; "__afl_fuzz_alt_ptr, 1 * 1024 * 1024))";
cc_params[cc_par_cnt++] = cc_params[cc_par_cnt++] =

358
llvm_mode/afl-ld-lto.c Normal file
View File

@ -0,0 +1,358 @@
/*
american fuzzy lop++ - wrapper for llvm 11+ lld
-----------------------------------------------
Written by Marc Heuse <mh@mh-sec.de> for afl++
Maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
Andrea Fioraldi <andreafioraldi@gmail.com>
Dominik Maier <domenukk@gmail.com>
Copyright 2019-2020 AFLplusplus Project. 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
The sole purpose of this wrapper is to preprocess clang LTO files when
linking with lld and performing the instrumentation on the whole program.
*/
#define AFL_MAIN
#define _GNU_SOURCE
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <dirent.h>
#define MAX_PARAM_COUNT 4096
static u8 **ld_params; /* Parameters passed to the real 'ld' */
static u8 *afl_path = AFL_PATH;
static u8 *real_ld = AFL_REAL_LD;
static u8 be_quiet, /* Quiet mode (no stderr output) */
debug, /* AFL_DEBUG */
passthrough, /* AFL_LD_PASSTHROUGH - no link+optimize*/
just_version; /* Just show version? */
static u32 ld_param_cnt = 1; /* Number of params to 'ld' */
/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'.
Note that the file name is always the last parameter passed by GCC,
so we exploit this property to keep the code "simple". */
static void edit_params(int argc, char **argv) {
u32 i, instrim = 0, gold_pos = 0, gold_present = 0, rt_present = 0,
rt_lto_present = 0, inst_present = 0;
char *ptr;
ld_params = ck_alloc(4096 * sizeof(u8 *));
ld_params[0] = (u8 *)real_ld;
if (!passthrough) {
for (i = 1; i < argc; i++) {
if (strstr(argv[i], "/afl-llvm-rt-lto.o") != NULL) rt_lto_present = 1;
if (strstr(argv[i], "/afl-llvm-rt.o") != NULL) rt_present = 1;
if (strstr(argv[i], "/afl-llvm-lto-instr") != NULL) inst_present = 1;
}
for (i = 1; i < argc && !gold_pos; i++) {
if (strcmp(argv[i], "-plugin") == 0) {
if (strncmp(argv[i], "-plugin=", strlen("-plugin=")) == 0) {
if (strcasestr(argv[i], "LLVMgold.so") != NULL)
gold_present = gold_pos = i + 1;
} else if (i < argc && strcasestr(argv[i + 1], "LLVMgold.so") != NULL) {
gold_present = gold_pos = i + 2;
}
}
}
if (!gold_pos) {
for (i = 1; i + 1 < argc && !gold_pos; i++) {
if (argv[i][0] != '-') {
if (argv[i - 1][0] == '-') {
switch (argv[i - 1][1]) {
case 'b':
break;
case 'd':
break;
case 'e':
break;
case 'F':
break;
case 'f':
break;
case 'I':
break;
case 'l':
break;
case 'L':
break;
case 'm':
break;
case 'o':
break;
case 'O':
break;
case 'p':
if (index(argv[i - 1], '=') == NULL) gold_pos = i;
break;
case 'R':
break;
case 'T':
break;
case 'u':
break;
case 'y':
break;
case 'z':
break;
case '-': {
if (strcmp(argv[i - 1], "--oformat") == 0) break;
if (strcmp(argv[i - 1], "--output") == 0) break;
if (strncmp(argv[i - 1], "--opt-remarks-", 14) == 0) break;
gold_pos = i;
break;
}
default:
gold_pos = i;
}
} else
gold_pos = i;
}
}
}
if (!gold_pos) gold_pos = 1;
}
if (getenv("AFL_LLVM_INSTRIM"))
instrim = 1;
else if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) &&
(strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))
instrim = 1;
if (debug)
SAYF(cMGN "[D] " cRST
"passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s "
"inst_present=%s rt_present=%s rt_lto_present=%s\n",
passthrough ? "true" : "false", instrim, gold_pos,
gold_present ? "true" : "false", inst_present ? "true" : "false",
rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
for (i = 1; i < argc; i++) {
if (ld_param_cnt >= MAX_PARAM_COUNT)
FATAL(
"Too many command line parameters because of unpacking .a archives, "
"this would need to be done by hand ... sorry! :-(");
if (strcmp(argv[i], "--afl") == 0) {
if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
exit(0);
}
if (i == gold_pos && !passthrough) {
ld_params[ld_param_cnt++] = alloc_printf("-L%s/../lib", LLVM_BINDIR);
if (!gold_present) {
ld_params[ld_param_cnt++] = "-plugin";
ld_params[ld_param_cnt++] =
alloc_printf("%s/../lib/LLVMgold.so", LLVM_BINDIR);
}
ld_params[ld_param_cnt++] = "--allow-multiple-definition";
if (!inst_present) {
if (instrim)
ld_params[ld_param_cnt++] =
alloc_printf("-mllvm=-load=%s/afl-llvm-lto-instrim.so", afl_path);
else
ld_params[ld_param_cnt++] = alloc_printf(
"-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path);
}
if (!rt_present)
ld_params[ld_param_cnt++] = alloc_printf("%s/afl-llvm-rt.o", afl_path);
if (!rt_lto_present)
ld_params[ld_param_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto.o", afl_path);
}
ld_params[ld_param_cnt++] = argv[i];
}
ld_params[ld_param_cnt] = NULL;
}
/* Main entry point */
int main(int argc, char **argv) {
s32 pid, i, status;
u8 * ptr;
char thecwd[PATH_MAX];
if ((ptr = getenv("AFL_LD_CALLER")) != NULL) {
FATAL("ld loop detected! Set AFL_REAL_LD!\n");
}
if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) {
SAYF(cCYA "afl-ld-to" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
} else
be_quiet = 1;
if (getenv("AFL_DEBUG") != NULL) debug = 1;
if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH");
if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
if (!afl_path || !*afl_path) afl_path = "/usr/local/lib/afl";
setenv("AFL_LD_CALLER", "1", 1);
if (debug) {
(void)getcwd(thecwd, sizeof(thecwd));
SAYF(cMGN "[D] " cRST "cd \"%s\";", thecwd);
for (i = 0; i < argc; i++)
SAYF(" \"%s\"", argv[i]);
SAYF("\n");
}
if (argc < 2) {
SAYF(
"\n"
"This is a helper application for afl-clang-lto. It is a wrapper "
"around GNU "
"llvm's 'lld',\n"
"executed by the toolchain whenever using "
"afl-clang-lto/afl-clang-lto++.\n"
"You probably don't want to run this program directly but rather pass "
"it as LD parameter to configure scripts\n\n"
"Environment variables:\n"
" AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n"
" AFL_REAL_LD point to the real llvm 11 lld if necessary\n"
"\nafl-ld-to was compiled with the fixed real 'ld' of %s and the "
"binary path of %s\n\n",
real_ld, LLVM_BINDIR);
exit(1);
}
edit_params(argc, argv); // here most of the magic happens :-)
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", thecwd);
for (i = 0; i < ld_param_cnt; i++)
SAYF(" \"%s\"", ld_params[i]);
SAYF("\n");
}
if (!(pid = fork())) {
if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params);
execvp("ld", (char **)ld_params); // fallback
FATAL("Oops, failed to execute 'ld' - check your PATH");
}
if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status);
if (!just_version) {
if (status == 0) {
if (!be_quiet) OKF("Linker was successful");
} else {
SAYF(cLRD "[-] " cRST
"Linker failed, please investigate and send a bug report. Most "
"likely an 'ld' option is incompatible with %s.\n",
AFL_CLANG_FLTO);
}
}
exit(WEXITSTATUS(status));
}

View File

@ -7,6 +7,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <fnmatch.h>
#include <list> #include <list>
#include <string> #include <string>
@ -152,12 +153,13 @@ bool isInWhitelist(llvm::Function *F) {
/* We don't check for filename equality here because /* We don't check for filename equality here because
* filenames might actually be full paths. Instead we * filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename * check that the actual filename ends in the filename
* specified in the list. */ * specified in the list. We also allow UNIX-style pattern
* matching */
if (instFilename.str().length() >= it->length()) { if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare( if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
instFilename.str().length() - it->length(), it->length(), 0) {
*it) == 0) {
return true; return true;
@ -189,12 +191,13 @@ bool isInWhitelist(llvm::Function *F) {
/* We don't check for filename equality here because /* We don't check for filename equality here because
* filenames might actually be full paths. Instead we * filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename * check that the actual filename ends in the filename
* specified in the list. */ * specified in the list. We also allow UNIX-style pattern
* matching */
if (instFilename.str().length() >= it->length()) { if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare( if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
instFilename.str().length() - it->length(), it->length(), 0) {
*it) == 0) {
return true; return true;

View File

@ -36,6 +36,7 @@
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <sys/time.h> #include <sys/time.h>
#include <fnmatch.h>
#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfo.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
@ -175,9 +176,8 @@ bool AFLwhitelist::runOnModule(Module &M) {
* specified in the list. */ * specified in the list. */
if (instFilename.str().length() >= it->length()) { if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare( if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
instFilename.str().length() - it->length(), it->length(), 0) {
*it) == 0) {
instrumentFunction = true; instrumentFunction = true;
break; break;

View File

@ -77,7 +77,8 @@ u8 __afl_area_initial[MAP_SIZE];
u8 * __afl_area_ptr = __afl_area_initial; u8 * __afl_area_ptr = __afl_area_initial;
u8 * __afl_dictionary; u8 * __afl_dictionary;
u8 * __afl_fuzz_ptr; u8 * __afl_fuzz_ptr;
u32 __afl_fuzz_len; u32 __afl_fuzz_len_dummy;
u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy;
u32 __afl_final_loc; u32 __afl_final_loc;
u32 __afl_map_size = MAP_SIZE; u32 __afl_map_size = MAP_SIZE;
@ -121,6 +122,8 @@ static void __afl_map_shm_fuzz() {
if (id_str) { if (id_str) {
u8 *map = NULL;
#ifdef USEMMAP #ifdef USEMMAP
const char * shm_file_path = id_str; const char * shm_file_path = id_str;
int shm_fd = -1; int shm_fd = -1;
@ -136,27 +139,32 @@ static void __afl_map_shm_fuzz() {
} }
__afl_fuzz_ptr = mmap(0, MAX_FILE, PROT_READ, MAP_SHARED, shm_fd, 0); map = (u8 *)mmap(0, MAX_FILE, PROT_READ, MAP_SHARED, shm_fd, 0);
#else #else
u32 shm_id = atoi(id_str); u32 shm_id = atoi(id_str);
map = (u8 *)shmat(shm_id, NULL, 0);
__afl_fuzz_ptr = shmat(shm_id, NULL, 0);
#endif #endif
/* Whooooops. */ /* Whooooops. */
if (__afl_fuzz_ptr == (void *)-1) { if (!map || map == (void *)-1) {
fprintf(stderr, "Error: could not access fuzzing shared memory\n"); perror("Could not access fuzzign shared memory");
exit(1); exit(1);
} }
if (getenv("AFL_DEBUG")) __afl_fuzz_len = (u32 *)map;
__afl_fuzz_ptr = (u8 *)(map + sizeof(u32));
if (getenv("AFL_DEBUG")) {
fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n"); fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n");
}
} else { } else {
fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n"); fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
@ -308,6 +316,10 @@ static void __afl_map_shm(void) {
id_str = getenv(CMPLOG_SHM_ENV_VAR); id_str = getenv(CMPLOG_SHM_ENV_VAR);
if (getenv("AFL_DEBUG"))
fprintf(stderr, "DEBUG: cmplog id_str %s\n",
id_str == NULL ? "<null>" : id_str);
if (id_str) { if (id_str) {
#ifdef USEMMAP #ifdef USEMMAP
@ -420,7 +432,7 @@ static void __afl_start_snapshots(void) {
} else { } else {
// uh this forkserver master does not understand extended option passing // uh this forkserver does not understand extended option passing
// or does not want the dictionary // or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1; if (!__afl_fuzz_ptr) already_read_first = 1;
@ -443,8 +455,31 @@ static void __afl_start_snapshots(void) {
} }
__afl_fuzz_len = (was_killed >> 8); #ifdef _AFL_DOCUMENT_MUTATIONS
was_killed = (was_killed & 0xff); if (__afl_fuzz_ptr) {
static uint32_t counter = 0;
char fn[32];
sprintf(fn, "%09u:forkserver", counter);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd_doc >= 0) {
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
fprintf(stderr, "write of mutation file failed: %s\n", fn);
unlink(fn);
}
close(fd_doc);
}
counter++;
}
#endif
/* If we stopped the child in persistent mode, but there was a race /* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old condition and afl-fuzz already issued SIGKILL, write off the old
@ -596,7 +631,7 @@ static void __afl_start_forkserver(void) {
} else { } else {
// uh this forkserver master does not understand extended option passing // uh this forkserver does not understand extended option passing
// or does not want the dictionary // or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1; if (!__afl_fuzz_ptr) already_read_first = 1;
@ -620,8 +655,31 @@ static void __afl_start_forkserver(void) {
} }
__afl_fuzz_len = (was_killed >> 8); #ifdef _AFL_DOCUMENT_MUTATIONS
was_killed = (was_killed & 0xff); if (__afl_fuzz_ptr) {
static uint32_t counter = 0;
char fn[32];
sprintf(fn, "%09u:forkserver", counter);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd_doc >= 0) {
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
fprintf(stderr, "write of mutation file failed: %s\n", fn);
unlink(fn);
}
close(fd_doc);
}
counter++;
}
#endif
/* If we stopped the child in persistent mode, but there was a race /* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old condition and afl-fuzz already issued SIGKILL, write off the old

View File

@ -193,6 +193,7 @@ patch -p1 <../patches/tcg-runtime-head.diff || exit 1
patch -p1 <../patches/translator.diff || exit 1 patch -p1 <../patches/translator.diff || exit 1
patch -p1 <../patches/__init__.py.diff || exit 1 patch -p1 <../patches/__init__.py.diff || exit 1
patch -p1 <../patches/make_strncpy_safe.diff || exit 1 patch -p1 <../patches/make_strncpy_safe.diff || exit 1
patch -p1 <../patches/mmap_fixes.diff || exit 1
echo "[+] Patching done." echo "[+] Patching done."

View File

@ -54,7 +54,7 @@
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
#define INC_AFL_AREA(loc) \ #define INC_AFL_AREA(loc) \
asm volatile( \ asm volatile( \
"incb (%0, %1, 1)\n" \ "addb $1, (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \ "adcb $0, (%0, %1, 1)\n" \
: /* no out */ \ : /* no out */ \
: "r"(afl_area_ptr), "r"(loc) \ : "r"(afl_area_ptr), "r"(loc) \
@ -63,7 +63,9 @@
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++ #define INC_AFL_AREA(loc) afl_area_ptr[loc]++
#endif #endif
typedef void (*afl_persistent_hook_fn)(uint64_t *regs, uint64_t guest_base); typedef void (*afl_persistent_hook_fn)(uint64_t *regs, uint64_t guest_base,
uint8_t *input_buf,
uint32_t input_buf_len);
/* Declared in afl-qemu-cpu-inl.h */ /* Declared in afl-qemu-cpu-inl.h */
@ -81,6 +83,10 @@ extern unsigned char persistent_save_gpr;
extern uint64_t persistent_saved_gpr[AFL_REGS_NUM]; extern uint64_t persistent_saved_gpr[AFL_REGS_NUM];
extern int persisent_retaddr_offset; extern int persisent_retaddr_offset;
extern u8 * shared_buf;
extern u32 *shared_buf_len;
extern u8 sharedmem_fuzzing;
extern afl_persistent_hook_fn afl_persistent_hook_ptr; extern afl_persistent_hook_fn afl_persistent_hook_ptr;
extern __thread abi_ulong afl_prev_loc; extern __thread abi_ulong afl_prev_loc;

View File

@ -83,6 +83,10 @@ unsigned char persistent_save_gpr;
uint64_t persistent_saved_gpr[AFL_REGS_NUM]; uint64_t persistent_saved_gpr[AFL_REGS_NUM];
int persisent_retaddr_offset; int persisent_retaddr_offset;
u8 * shared_buf;
u32 *shared_buf_len;
u8 sharedmem_fuzzing;
afl_persistent_hook_fn afl_persistent_hook_ptr; afl_persistent_hook_fn afl_persistent_hook_ptr;
/* Instrumentation ratio: */ /* Instrumentation ratio: */
@ -128,6 +132,7 @@ static inline TranslationBlock *tb_find(CPUState *, TranslationBlock *, int,
static inline void tb_add_jump(TranslationBlock *tb, int n, static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next); TranslationBlock *tb_next);
int open_self_maps(void *cpu_env, int fd); int open_self_maps(void *cpu_env, int fd);
static void afl_map_shm_fuzz(void);
/************************* /*************************
* ACTUAL IMPLEMENTATION * * ACTUAL IMPLEMENTATION *
@ -135,6 +140,42 @@ int open_self_maps(void *cpu_env, int fd);
/* Set up SHM region and initialize other stuff. */ /* Set up SHM region and initialize other stuff. */
static void afl_map_shm_fuzz(void) {
char *id_str = getenv(SHM_FUZZ_ENV_VAR);
if (id_str) {
u32 shm_id = atoi(id_str);
u8 *map = (u8 *)shmat(shm_id, NULL, 0);
/* Whooooops. */
if (!map || map == (void *)-1) {
perror("[AFL] ERROR: could not access fuzzing shared memory");
exit(1);
}
shared_buf_len = (u32 *)map;
shared_buf = map + sizeof(u32);
if (getenv("AFL_DEBUG")) {
fprintf(stderr, "[AFL] DEBUG: successfully got fuzzing shared memory\n");
}
} else {
fprintf(stderr,
"[AFL] ERROR: variable for fuzzing shared memory is not set\n");
exit(1);
}
}
void afl_setup(void) { void afl_setup(void) {
char *id_str = getenv(SHM_ENV_VAR), *inst_r = getenv("AFL_INST_RATIO"); char *id_str = getenv(SHM_ENV_VAR), *inst_r = getenv("AFL_INST_RATIO");
@ -248,6 +289,11 @@ void afl_setup(void) {
} }
int (*afl_persistent_hook_init_ptr)(void) =
dlsym(plib, "afl_persistent_hook_init");
if (afl_persistent_hook_init_ptr)
sharedmem_fuzzing = afl_persistent_hook_init_ptr();
afl_persistent_hook_ptr = dlsym(plib, "afl_persistent_hook"); afl_persistent_hook_ptr = dlsym(plib, "afl_persistent_hook");
if (!afl_persistent_hook_ptr) { if (!afl_persistent_hook_ptr) {
@ -278,7 +324,7 @@ void afl_setup(void) {
void afl_forkserver(CPUState *cpu) { void afl_forkserver(CPUState *cpu) {
u32 map_size = 0; // u32 map_size = 0;
unsigned char tmp[4] = {0}; unsigned char tmp[4] = {0};
if (forkserver_installed == 1) return; if (forkserver_installed == 1) return;
@ -291,15 +337,17 @@ void afl_forkserver(CPUState *cpu) {
pid_t child_pid; pid_t child_pid;
int t_fd[2]; int t_fd[2];
u8 child_stopped = 0; u8 child_stopped = 0;
u32 was_killed;
int status = 0;
// if in the future qemu has non-collding coverage then switch MAP_SIZE
// with the max ID value // with the max ID value
if (MAP_SIZE <= 0x800000) { if (MAP_SIZE <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(MAP_SIZE) | FS_OPT_MAPSIZE);
map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE)); if (sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
memcpy(tmp, &map_size, 4); if (status) status |= (FS_OPT_ENABLED);
if (getenv("AFL_DEBUG"))
} fprintf(stderr, "Debug: Sending status %08x\n", status);
memcpy(tmp, &status, 4);
/* Tell the parent that we're alive. If the parent doesn't want /* Tell the parent that we're alive. If the parent doesn't want
to talk, assume that we're not running in forkserver mode. */ to talk, assume that we're not running in forkserver mode. */
@ -310,13 +358,28 @@ void afl_forkserver(CPUState *cpu) {
int first_run = 1; int first_run = 1;
if (sharedmem_fuzzing) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2);
if ((was_killed & (0xffffffff & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ))) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ))
afl_map_shm_fuzz();
else {
fprintf(stderr,
"[AFL] ERROR: afl-fuzz is old and does not support"
" shmem input");
exit(1);
}
}
/* All right, let's await orders... */ /* All right, let's await orders... */
while (1) { while (1) {
int status;
u32 was_killed;
/* Whoops, parent dead? */ /* Whoops, parent dead? */
if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2); if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2);

View File

@ -161,7 +161,8 @@ static void log_x86_sp_content(void) {
static void callback_to_persistent_hook(void) { static void callback_to_persistent_hook(void) {
afl_persistent_hook_ptr(persistent_saved_gpr, guest_base); afl_persistent_hook_ptr(persistent_saved_gpr, guest_base, shared_buf,
*shared_buf_len);
} }

View File

@ -215,7 +215,7 @@ void HELPER(afl_cmplog_rtn)(CPUArchState *env) {
#else #else
// dumb code to make it compile // stupid code to make it compile
void *ptr1 = NULL; void *ptr1 = NULL;
void *ptr2 = NULL; void *ptr2 = NULL;
return; return;

View File

@ -11,7 +11,37 @@ index 7cccf3eb..195875af 100644
/* from personality.h */ /* from personality.h */
/* /*
@@ -1522,6 +1524,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, @@ -737,9 +739,13 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss);
end_addr = HOST_PAGE_ALIGN(elf_bss);
if (end_addr1 < end_addr) {
- mmap((void *)g2h(end_addr1), end_addr - end_addr1,
+ void *p = mmap((void *)g2h(end_addr1), end_addr - end_addr1,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("padzero: cannot mmap");
+ exit(-1);
+ }
}
}
@@ -979,9 +985,13 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
/* Map the last of the bss segment */
if (last_bss > elf_bss) {
- target_mmap(elf_bss, last_bss-elf_bss,
+ void *p = target_mmap(elf_bss, last_bss-elf_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("load_elf_interp: cannot mmap");
+ exit(-1);
+ }
}
free(elf_phdata);
@@ -1522,6 +1532,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->start_data = start_data; info->start_data = start_data;
info->end_data = end_data; info->end_data = end_data;
info->start_stack = bprm->p; info->start_stack = bprm->p;
@ -20,7 +50,17 @@ index 7cccf3eb..195875af 100644
/* Calling set_brk effectively mmaps the pages that we need for the bss and break /* Calling set_brk effectively mmaps the pages that we need for the bss and break
sections */ sections */
@@ -1549,6 +1553,20 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, @@ -1544,11 +1556,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
and some applications "depend" upon this behavior.
Since we do not have the power to recompile these, we
emulate the SVr4 behavior. Sigh. */
- target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ void *p = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("load_elf_binary: cannot mmap");
+ exit(-1);
+ }
} }
info->entry = elf_entry; info->entry = elf_entry;

View File

@ -0,0 +1,165 @@
diff --git a/exec.c b/exec.c
index df5571e..d484098 100644
--- a/exec.c
+++ b/exec.c
@@ -2457,7 +2457,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, -1, 0);
}
- if (area != vaddr) {
+ if (area == MAP_FAILED || area != vaddr) {
error_report("Could not remap addr: "
RAM_ADDR_FMT "@" RAM_ADDR_FMT "",
length, addr);
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 41e0983..0a8b8e5 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -612,9 +612,13 @@ static void mmap_reserve(abi_ulong start, abi_ulong size)
real_end -= qemu_host_page_size;
}
if (real_start != real_end) {
- mmap(g2h(real_start), real_end - real_start, PROT_NONE,
+ void *p = mmap(g2h(real_start), real_end - real_start, PROT_NONE,
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
-1, 0);
+ if (p == MAP_FAILED) {
+ perror("mmap_reserve: cannot mmap");
+ exit(-1);
+ }
}
}
diff --git a/roms/SLOF/tools/sloffs.c b/roms/SLOF/tools/sloffs.c
index 9a1eace..10366f0 100644
--- a/roms/SLOF/tools/sloffs.c
+++ b/roms/SLOF/tools/sloffs.c
@@ -308,6 +308,10 @@ sloffs_append(const int file, const char *name, const char *dest)
fstat(fd, &stat);
append = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (append == MAP_FAILED) {
+ perror("sloffs_append: cannot mmap for read");
+ exit(1);
+ }
header = sloffs_header(file);
if (!header)
@@ -331,6 +335,10 @@ sloffs_append(const int file, const char *name, const char *dest)
write(out, "", 1);
write_start = mmap(NULL, new_len, PROT_READ | PROT_WRITE,
MAP_SHARED, out, 0);
+ if (write_start == MAP_FAILED) {
+ perror("sloffs_append: cannot mmap for read/write");
+ exit(1);
+ }
memset(write_start, 0, new_len);
memset(&new_file, 0, sizeof(struct sloffs));
diff --git a/roms/skiboot/core/test/run-trace.c b/roms/skiboot/core/test/run-trace.c
index 9801688..236b51d 100644
--- a/roms/skiboot/core/test/run-trace.c
+++ b/roms/skiboot/core/test/run-trace.c
@@ -178,6 +178,10 @@ static void test_parallel(void)
i = (CPUS*len + getpagesize()-1)&~(getpagesize()-1);
p = mmap(NULL, i, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_SHARED, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("test_parallel: cannot mmap");
+ exit(-1);
+ }
for (i = 0; i < CPUS; i++) {
fake_cpus[i].trace = p + i * len;
diff --git a/roms/skiboot/external/ffspart/ffspart.c b/roms/skiboot/external/ffspart/ffspart.c
index 7703477..efbbd5b 100644
--- a/roms/skiboot/external/ffspart/ffspart.c
+++ b/roms/skiboot/external/ffspart/ffspart.c
@@ -379,7 +379,7 @@ int main(int argc, char *argv[])
}
data_ptr = mmap(NULL, pactual, PROT_READ, MAP_SHARED, data_fd, 0);
- if (!data_ptr) {
+ if (data_ptr == MAP_FAILED) {
fprintf(stderr, "Couldn't mmap data file for partition '%s': %s\n",
name, strerror(errno));
rc = -1;
diff --git a/roms/skiboot/extract-gcov.c b/roms/skiboot/extract-gcov.c
index 3d31d1b..ebc03e6 100644
--- a/roms/skiboot/extract-gcov.c
+++ b/roms/skiboot/extract-gcov.c
@@ -229,7 +229,11 @@ int main(int argc, char *argv[])
}
addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- assert(addr != NULL);
+ assert(addr != MAP_FAILED);
+ if (addr == MAP_FAILED) {
+ perror("main: cannot mmap");
+ exit(-1);
+ }
skiboot_dump_size = sb.st_size;
printf("Skiboot memory dump %p - %p\n",
diff --git a/roms/skiboot/libstb/create-container.c b/roms/skiboot/libstb/create-container.c
index 5cf80a0..64699ad 100644
--- a/roms/skiboot/libstb/create-container.c
+++ b/roms/skiboot/libstb/create-container.c
@@ -96,7 +96,11 @@ void getSigRaw(ecc_signature_t *sigraw, char *inFile)
assert(r==0);
infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
- assert(infile);
+ assert(infile != MAP_FAILED);
+ if (infile == MAP_FAILED) {
+ perror("getSigRaw: cannot mmap");
+ exit(-1);
+ }
signature = d2i_ECDSA_SIG(NULL, (const unsigned char **) &infile, 7 + 2*EC_COORDBYTES);
@@ -356,7 +360,11 @@ int main(int argc, char* argv[])
r = fstat(fdin, &s);
assert(r==0);
infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
- assert(infile);
+ assert(infile != MAP_FAILED);
+ if (infile == MAP_FAILED) {
+ perror("main: cannot mmap");
+ exit(-1);
+ }
fdout = open(params.imagefn, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
assert(fdout > 0);
diff --git a/tests/tcg/multiarch/test-mmap.c b/tests/tcg/multiarch/test-mmap.c
index 11d0e77..14f5919 100644
--- a/tests/tcg/multiarch/test-mmap.c
+++ b/tests/tcg/multiarch/test-mmap.c
@@ -203,6 +203,7 @@ void check_aligned_anonymous_fixed_mmaps(void)
p1 = mmap(addr, pagesize, PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-1, 0);
+ fail_unless (p1 != MAP_FAILED);
/* Make sure we get pages aligned with the pagesize.
The target expects this. */
p = (uintptr_t) p1;
@@ -234,6 +235,7 @@ void check_aligned_anonymous_fixed_mmaps_collide_with_host(void)
p1 = mmap(addr, pagesize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-1, 0);
+ fail_unless (p1 != MAP_FAILED);
/* Make sure we get pages aligned with the pagesize.
The target expects this. */
p = (uintptr_t) p1;
@@ -401,6 +403,10 @@ void check_file_fixed_mmaps(void)
p4 = mmap(addr + pagesize * 3, pagesize, PROT_READ,
MAP_PRIVATE | MAP_FIXED,
test_fd, pagesize * 3);
+ fail_unless (p1 != MAP_FAILED);
+ fail_unless (p2 != MAP_FAILED);
+ fail_unless (p3 != MAP_FAILED);
+ fail_unless (p4 != MAP_FAILED);
/* Make sure we get pages aligned with the pagesize.
The target expects this. */

View File

@ -61,8 +61,9 @@ char *afl_environment_variables[] = {
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IMPORT_FIRST", "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IMPORT_FIRST",
"AFL_INST_LIBS", "AFL_INST_RATIO", "AFL_KEEP_TRACES", "AFL_KEEP_ASSEMBLY", "AFL_INST_LIBS", "AFL_INST_RATIO", "AFL_KEEP_TRACES", "AFL_KEEP_ASSEMBLY",
"AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER", "AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER",
"AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LD_PASSTHROUGH", "AFL_REAL_LD", "AFL_LD_PRELOAD", "AFL_LD_VERBOSE",
"AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX",
"AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD",
"AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY", "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY",
"AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK",
"AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
@ -253,7 +254,8 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
"binaries that are\n" "binaries that are\n"
" instrumented at compile time with afl-gcc. It is also possible to " " instrumented at compile time with afl-gcc. It is also possible to "
"use it as a\n" "use it as a\n"
" traditional \"dumb\" fuzzer by specifying '-n' in the command " " traditional non-instrumented fuzzer by specifying '-n' in the "
"command "
"line.\n"); "line.\n");
FATAL("Failed to locate 'afl-qemu-trace'."); FATAL("Failed to locate 'afl-qemu-trace'.");
@ -353,7 +355,8 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
"binaries that are\n" "binaries that are\n"
" instrumented at compile time with afl-gcc. It is also possible to " " instrumented at compile time with afl-gcc. It is also possible to "
"use it as a\n" "use it as a\n"
" traditional \"dumb\" fuzzer by specifying '-n' in the command " " traditional non-instrumented fuzzer by specifying '-n' in the "
"command "
"line.\n", "line.\n",
ncp); ncp);
@ -869,56 +872,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
} }
/* Wrapper for select() and read(), reading exactly len bytes. /* Reads the map size from ENV */
Returns the time passed to read.
If the wait times out, returns timeout_ms + 1;
Returns 0 if an error occurred (fd closed, signal, ...); */
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
volatile u8 *stop_soon_p) {
struct timeval timeout;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = (timeout_ms / 1000);
timeout.tv_usec = (timeout_ms % 1000) * 1000;
size_t read_total = 0;
size_t len_read = 0;
while (len_read < len) {
/* set exceptfds as well to return when a child exited/closed the pipe. */
int sret = select(fd + 1, &readfds, NULL, NULL, &timeout);
if (!sret) {
// printf("Timeout in sret.");
return timeout_ms + 1;
} else if (sret < 0) {
/* Retry select for all signals other than than ctrl+c */
if (errno == EINTR && !*stop_soon_p) { continue; }
return 0;
}
len_read = read(fd, ((u8 *)buf) + len_read, len - len_read);
if (!len_read) { return 0; }
read_total += len_read;
}
s32 exec_ms =
MIN(timeout_ms,
((u64)timeout_ms - (timeout.tv_sec * 1000 + timeout.tv_usec / 1000)));
return exec_ms > 0 ? exec_ms
: 1; // at least 1 milli must have passed (0 is an error)
}
u32 get_map_size(void) { u32 get_map_size(void) {
uint32_t map_size = MAP_SIZE; uint32_t map_size = MAP_SIZE;

View File

@ -101,6 +101,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->exec_tmout = from->exec_tmout; fsrv_to->exec_tmout = from->exec_tmout;
fsrv_to->mem_limit = from->mem_limit; fsrv_to->mem_limit = from->mem_limit;
fsrv_to->map_size = from->map_size; fsrv_to->map_size = from->map_size;
fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz;
#ifndef HAVE_ARC4RANDOM #ifndef HAVE_ARC4RANDOM
fsrv_to->dev_urandom_fd = from->dev_urandom_fd; fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
@ -119,7 +120,57 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
} }
/* Internal forkserver for dumb_mode=1 and non-forkserver mode runs. /* Wrapper for select() and read(), reading a 32 bit var.
Returns the time passed to read.
If the wait times out, returns timeout_ms + 1;
Returns 0 if an error occurred (fd closed, signal, ...); */
static u32 read_s32_timed(s32 fd, s32 *buf, u32 timeout_ms,
volatile u8 *stop_soon_p) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
struct timeval timeout;
size_t len = 4;
timeout.tv_sec = (timeout_ms / 1000);
timeout.tv_usec = (timeout_ms % 1000) * 1000;
#if !defined(__linux__)
u64 read_start = get_cur_time_us();
#endif
/* set exceptfds as well to return when a child exited/closed the pipe. */
int sret = select(fd + 1, &readfds, NULL, NULL, &timeout);
if (!sret) {
*buf = -1;
return timeout_ms + 1;
} else if (sret < 0) {
*buf = -1;
return 0;
}
ssize_t len_read = read(fd, ((u8 *)buf), len);
if (len_read < len) { return 0; }
#if defined(__linux__)
u32 exec_ms =
MIN(timeout_ms,
((u64)timeout_ms - (timeout.tv_sec * 1000 + timeout.tv_usec / 1000)));
#else
u32 exec_ms = MIN(timeout_ms, get_cur_time_us() - read_start);
#endif
// ensure to report 1 ms has passed (0 is an error)
return exec_ms > 0 ? exec_ms : 1;
}
/* Internal forkserver for non_instrumented_mode=1 and non-forkserver mode runs.
It execvs for each fork, forwarding exit codes and child pids to afl. */ It execvs for each fork, forwarding exit codes and child pids to afl. */
static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
@ -228,8 +279,8 @@ static void report_error_and_exit(int error) {
break; break;
case FS_ERROR_MMAP: case FS_ERROR_MMAP:
FATAL( FATAL(
"the fuzzing target reports that the mmap() call to the share memory " "the fuzzing target reports that the mmap() call to the shared "
"failed."); "memory failed.");
break; break;
default: default:
FATAL("unknown error code %u from fuzzing target!", error); FATAL("unknown error code %u from fuzzing target!", error);
@ -238,7 +289,7 @@ static void report_error_and_exit(int error) {
} }
/* Spins up fork server (instrumented mode only). The idea is explained here: /* Spins up fork server. The idea is explained here:
http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html
@ -250,14 +301,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output) { volatile u8 *stop_soon_p, u8 debug_child_output) {
int st_pipe[2], ctl_pipe[2]; int st_pipe[2], ctl_pipe[2];
int status; s32 status;
s32 rlen; s32 rlen;
if (!be_quiet) { ACTF("Spinning up the fork server..."); } if (!be_quiet) { ACTF("Spinning up the fork server..."); }
if (fsrv->use_fauxsrv) { if (fsrv->use_fauxsrv) {
/* TODO: Come up with sone nice way to initalize this all */ /* TODO: Come up with sone nice way to initialize this all */
if (fsrv->init_child_func != fsrv_exec_child) { if (fsrv->init_child_func != fsrv_exec_child) {
@ -387,6 +438,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
falling through. */ falling through. */
*(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG; *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
fprintf(stderr, "Error: execv to target failed\n");
exit(0); exit(0);
} }
@ -406,14 +458,15 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
rlen = 0; rlen = 0;
if (fsrv->exec_tmout) { if (fsrv->exec_tmout) {
u32 time = read_timed(fsrv->fsrv_st_fd, &status, 4, u32 time_ms =
read_s32_timed(fsrv->fsrv_st_fd, &status,
fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p); fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p);
if (!time) { if (!time_ms) {
kill(fsrv->fsrv_pid, SIGKILL); kill(fsrv->fsrv_pid, SIGKILL);
} else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) { } else if (time_ms > fsrv->exec_tmout * FORK_WAIT_MULT) {
fsrv->last_run_timed_out = 1; fsrv->last_run_timed_out = 1;
kill(fsrv->fsrv_pid, SIGKILL); kill(fsrv->fsrv_pid, SIGKILL);
@ -437,17 +490,17 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!be_quiet) { OKF("All right - fork server is up."); } if (!be_quiet) { OKF("All right - fork server is up."); }
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
if (getenv("AFL_DEBUG")) { if (getenv("AFL_DEBUG")) {
ACTF("Extended forkserver functions received (%08x).", status); ACTF("Extended forkserver functions received (%08x).", status);
} }
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
fsrv->snapshot = 1; fsrv->snapshot = 1;
@ -457,9 +510,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) { if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
if (fsrv->support_shdmen_fuzz) { if (fsrv->support_shmem_fuzz) {
fsrv->use_shdmen_fuzz = 1; fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
if ((status & FS_OPT_AUTODICT) == 0) { if ((status & FS_OPT_AUTODICT) == 0) {
@ -473,6 +526,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} }
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
} }
} }
@ -512,7 +571,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) {
// this is not afl-fuzz - we deny and return // this is not afl-fuzz - we deny and return
if (fsrv->use_shdmen_fuzz) if (fsrv->use_shmem_fuzz)
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
else else
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
@ -774,10 +833,12 @@ static void afl_fsrv_kill(afl_forkserver_t *fsrv) {
void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
if (fsrv->shdmem_fuzz) { if (fsrv->shmem_fuzz) {
memcpy(fsrv->shdmem_fuzz, buf, len); *fsrv->shmem_fuzz_len = len;
fsrv->shdmem_fuzz_len = len; memcpy(fsrv->shmem_fuzz, buf, len);
// printf("test case len: %u [0]:0x%02x\n", *fsrv->shmem_fuzz_len, buf[0]);
// fflush(stdout);
} else { } else {
@ -839,8 +900,6 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
MEM_BARRIER(); MEM_BARRIER();
if (fsrv->shdmem_fuzz_len) write_value += (fsrv->shdmem_fuzz_len << 8);
/* we have the fork server (or faux server) up and running /* we have the fork server (or faux server) up and running
First, tell it if the previous run timed out. */ First, tell it if the previous run timed out. */
@ -862,7 +921,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (fsrv->child_pid <= 0) { FATAL("Fork server is misbehaving (OOM?)"); } if (fsrv->child_pid <= 0) { FATAL("Fork server is misbehaving (OOM?)"); }
exec_ms = read_timed(fsrv->fsrv_st_fd, &fsrv->child_status, 4, timeout, exec_ms = read_s32_timed(fsrv->fsrv_st_fd, &fsrv->child_status, timeout,
stop_soon_p); stop_soon_p);
if (exec_ms > timeout) { if (exec_ms > timeout) {

View File

@ -623,14 +623,14 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* Timeouts are not very interesting, but we're still obliged to keep /* Timeouts are not very interesting, but we're still obliged to keep
a handful of samples. We use the presence of new bits in the a handful of samples. We use the presence of new bits in the
hang-specific bitmap as a signal of uniqueness. In "dumb" mode, we hang-specific bitmap as a signal of uniqueness. In "non-instrumented"
just keep everything. */ mode, we just keep everything. */
++afl->total_tmouts; ++afl->total_tmouts;
if (afl->unique_hangs >= KEEP_UNIQUE_HANG) { return keeping; } if (afl->unique_hangs >= KEEP_UNIQUE_HANG) { return keeping; }
if (likely(!afl->dumb_mode)) { if (likely(!afl->non_instrumented_mode)) {
#ifdef WORD_SIZE_64 #ifdef WORD_SIZE_64
simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); simplify_trace(afl, (u64 *)afl->fsrv.trace_bits);
@ -698,7 +698,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (afl->unique_crashes >= KEEP_UNIQUE_CRASH) { return keeping; } if (afl->unique_crashes >= KEEP_UNIQUE_CRASH) { return keeping; }
if (likely(!afl->dumb_mode)) { if (likely(!afl->non_instrumented_mode)) {
#ifdef WORD_SIZE_64 #ifdef WORD_SIZE_64
simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); simplify_trace(afl, (u64 *)afl->fsrv.trace_bits);

View File

@ -1315,10 +1315,10 @@ dir_cleanup_failed:
} }
/* If this is a -S slave, ensure a -M master is running, if a master is /* If this is a -S secondary node, ensure a -M main node is running,
running when another master is started then warn */ if a main node is running when another main is started, then warn */
int check_master_exists(afl_state_t *afl) { int check_main_node_exists(afl_state_t *afl) {
DIR * sd; DIR * sd;
struct dirent *sd_ent; struct dirent *sd_ent;
@ -1337,7 +1337,7 @@ int check_master_exists(afl_state_t *afl) {
} }
fn = alloc_printf("%s/%s/is_master", afl->sync_dir, sd_ent->d_name); fn = alloc_printf("%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name);
int res = access(fn, F_OK); int res = access(fn, F_OK);
free(fn); free(fn);
if (res == 0) return 1; if (res == 0) return 1;
@ -1392,9 +1392,9 @@ void setup_dirs_fds(afl_state_t *afl) {
} }
if (afl->is_master) { if (afl->is_main_node) {
u8 *x = alloc_printf("%s/is_master", afl->out_dir); u8 *x = alloc_printf("%s/is_main_node", afl->out_dir);
int fd = open(x, O_CREAT | O_RDWR, 0644); int fd = open(x, O_CREAT | O_RDWR, 0644);
if (fd < 0) FATAL("cannot create %s", x); if (fd < 0) FATAL("cannot create %s", x);
free(x); free(x);
@ -1859,7 +1859,11 @@ void fix_up_sync(afl_state_t *afl) {
u8 *x = afl->sync_id; u8 *x = afl->sync_id;
if (afl->dumb_mode) { FATAL("-S / -M and -n are mutually exclusive"); } if (afl->non_instrumented_mode) {
FATAL("-S / -M and -n are mutually exclusive");
}
while (*x) { while (*x) {
@ -1949,6 +1953,30 @@ static void handle_skipreq(int sig) {
} }
/* Setup shared map for fuzzing with input via sharedmem */
void setup_testcase_shmem(afl_state_t *afl) {
afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t));
// we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR
u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
#else
u8 *shm_str = alloc_printf("%d", afl->shm_fuzz->shm_id);
setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
ck_free(shm_str);
#endif
afl->fsrv.support_shmem_fuzz = 1;
afl->fsrv.shmem_fuzz_len = (u32 *)map;
afl->fsrv.shmem_fuzz = map + sizeof(u32);
}
/* Do a PATH search and find target binary to see that it exists and /* Do a PATH search and find target binary to see that it exists and
isn't a shell script - a common and painful mistake. We also check for isn't a shell script - a common and painful mistake. We also check for
a valid ELF header and for evidence of AFL instrumentation. */ a valid ELF header and for evidence of AFL instrumentation. */
@ -2098,7 +2126,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
#endif /* ^!__APPLE__ */ #endif /* ^!__APPLE__ */
if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->dumb_mode && if (!afl->fsrv.qemu_mode && !afl->unicorn_mode &&
!afl->non_instrumented_mode &&
!memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST SAYF("\n" cLRD "[-] " cRST
@ -2115,8 +2144,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
" mode support. Consult the README.md for tips on how to enable " " mode support. Consult the README.md for tips on how to enable "
"this.\n" "this.\n"
" (It is also possible to use afl-fuzz as a traditional, \"dumb\" " " (It is also possible to use afl-fuzz as a traditional, "
"fuzzer.\n" "non-instrumented fuzzer.\n"
" For that, you can use the -n option - but expect much worse " " For that, you can use the -n option - but expect much worse "
"results.)\n", "results.)\n",
doc_path); doc_path);
@ -2153,30 +2182,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
OKF(cPIN "Persistent mode binary detected."); OKF(cPIN "Persistent mode binary detected.");
setenv(PERSIST_ENV_VAR, "1", 1); setenv(PERSIST_ENV_VAR, "1", 1);
afl->persistent_mode = 1; afl->persistent_mode = 1;
// do not fail if we can not get the fuzzing shared mem
if ((afl->shm_fuzz = calloc(1, sizeof(sharedmem_t)))) {
// we need to set the dumb mode to not overwrite the SHM_ENV_VAR afl->shmem_testcase_mode = 1;
if ((afl->fsrv.shdmem_fuzz = afl_shm_init(afl->shm_fuzz, MAX_FILE, 1))) {
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
#else
u8 *shm_str;
shm_str = alloc_printf("%d", afl->shm_fuzz->shm_id);
setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
ck_free(shm_str);
#endif
afl->fsrv.support_shdmen_fuzz = 1;
} else {
free(afl->shm_fuzz);
afl->shm_fuzz = NULL;
}
}
} else if (getenv("AFL_PERSISTENT")) { } else if (getenv("AFL_PERSISTENT")) {

View File

@ -415,7 +415,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
} }
} else if (!afl->dumb_mode && !afl->queue_cur->favored && } else if (!afl->non_instrumented_mode && !afl->queue_cur->favored &&
afl->queued_paths > 10) { afl->queued_paths > 10) {
@ -512,7 +512,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
* TRIMMING * * TRIMMING *
************/ ************/
if (!afl->dumb_mode && !afl->queue_cur->trim_done && !afl->disable_trim) { if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
!afl->disable_trim) {
u8 res = trim_case(afl, afl->queue_cur, in_buf); u8 res = trim_case(afl, afl->queue_cur, in_buf);
@ -577,10 +578,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
} }
/* Skip deterministic fuzzing if exec path checksum puts this out of scope /* Skip deterministic fuzzing if exec path checksum puts this out of scope
for this master instance. */ for this main instance. */
if (afl->master_max && if (afl->main_node_max && (afl->queue_cur->exec_cksum % afl->main_node_max) !=
(afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1) { afl->main_node_id - 1) {
goto custom_mutator_stage; goto custom_mutator_stage;
@ -650,7 +651,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
*/ */
if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { if (!afl->non_instrumented_mode && (afl->stage_cur & 7) == 7) {
u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@ -822,10 +823,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
u32 cksum; u32 cksum;
/* If in dumb mode or if the file is very short, just flag everything /* If in non-instrumented mode or if the file is very short, just flag
without wasting time on checksums. */ everything without wasting time on checksums. */
if (!afl->dumb_mode && len >= EFF_MIN_LEN) { if (!afl->non_instrumented_mode && len >= EFF_MIN_LEN) {
cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@ -2568,7 +2569,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
} }
} else if (!afl->dumb_mode && !afl->queue_cur->favored && } else if (!afl->non_instrumented_mode && !afl->queue_cur->favored &&
afl->queued_paths > 10) { afl->queued_paths > 10) {
@ -2660,7 +2661,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
* TRIMMING * * TRIMMING *
************/ ************/
if (!afl->dumb_mode && !afl->queue_cur->trim_done) { if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done) {
u8 res = trim_case(afl, afl->queue_cur, in_buf); u8 res = trim_case(afl, afl->queue_cur, in_buf);
@ -2730,10 +2731,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
} }
/* Skip deterministic fuzzing if exec path checksum puts this out of scope /* Skip deterministic fuzzing if exec path checksum puts this out of scope
for this master instance. */ for this main instance. */
if (afl->master_max && if (afl->main_node_max && (afl->queue_cur->exec_cksum % afl->main_node_max) !=
(afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1) { afl->main_node_id - 1) {
goto havoc_stage; goto havoc_stage;
@ -2803,7 +2804,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
*/ */
if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { if (!afl->non_instrumented_mode && (afl->stage_cur & 7) == 7) {
u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@ -2975,10 +2976,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
u32 cksum; u32 cksum;
/* If in dumb mode or if the file is very short, just flag everything /* If in non-instrumented mode or if the file is very short, just flag
without wasting time on checksums. */ everything without wasting time on checksums. */
if (!afl->dumb_mode && len >= EFF_MIN_LEN) { if (!afl->non_instrumented_mode && len >= EFF_MIN_LEN) {
cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);

View File

@ -303,7 +303,7 @@ void cull_queue(afl_state_t *afl) {
u32 i; u32 i;
u8 * temp_v = afl->map_tmp_buf; u8 * temp_v = afl->map_tmp_buf;
if (afl->dumb_mode || !afl->score_changed) { return; } if (afl->non_instrumented_mode || !afl->score_changed) { return; }
afl->score_changed = 0; afl->score_changed = 0;

View File

@ -27,6 +27,7 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include <sys/time.h> #include <sys/time.h>
#include <signal.h> #include <signal.h>
#include <limits.h>
#include "cmplog.h" #include "cmplog.h"
@ -231,13 +232,13 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child_output); afl->afl_env.afl_debug_child_output);
if (afl->fsrv.support_shdmen_fuzz && !afl->fsrv.use_shdmen_fuzz) { if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) {
afl_shm_deinit(afl->shm_fuzz); afl_shm_deinit(afl->shm_fuzz);
free(afl->shm_fuzz); ck_free(afl->shm_fuzz);
afl->shm_fuzz = NULL; afl->shm_fuzz = NULL;
afl->fsrv.support_shdmen_fuzz = 0; afl->fsrv.support_shmem_fuzz = 0;
afl->fsrv.shdmem_fuzz = NULL; afl->fsrv.shmem_fuzz = NULL;
} }
@ -272,7 +273,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; } if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
if (!afl->dumb_mode && !afl->stage_cur && if (!afl->non_instrumented_mode && !afl->stage_cur &&
!count_bytes(afl, afl->fsrv.trace_bits)) { !count_bytes(afl, afl->fsrv.trace_bits)) {
fault = FSRV_RUN_NOINST; fault = FSRV_RUN_NOINST;
@ -337,7 +338,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
parent. This is a non-critical problem, but something to warn the user parent. This is a non-critical problem, but something to warn the user
about. */ about. */
if (!afl->dumb_mode && first_run && !fault && !new_bits) { if (!afl->non_instrumented_mode && first_run && !fault && !new_bits) {
fault = FSRV_RUN_NOBITS; fault = FSRV_RUN_NOBITS;
@ -412,17 +413,17 @@ void sync_fuzzers(afl_state_t *afl) {
entries++; entries++;
// a slave only syncs from a master, a master syncs from everyone // secondary nodes only syncs from main, the main node syncs from everyone
if (likely(afl->is_slave)) { if (likely(afl->is_secondary_node)) {
sprintf(qd_path, "%s/%s/is_master", afl->sync_dir, sd_ent->d_name); sprintf(qd_path, "%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name);
int res = access(qd_path, F_OK); int res = access(qd_path, F_OK);
if (unlikely(afl->is_master)) { // an elected temporary master if (unlikely(afl->is_main_node)) { // an elected temporary main node
if (likely(res == 0)) { // there is another master? downgrade. if (likely(res == 0)) { // there is another main node? downgrade.
afl->is_master = 0; afl->is_main_node = 0;
sprintf(qd_path, "%s/is_master", afl->out_dir); sprintf(qd_path, "%s/is_main_node", afl->out_dir);
unlink(qd_path); unlink(qd_path);
} }
@ -561,16 +562,17 @@ void sync_fuzzers(afl_state_t *afl) {
closedir(sd); closedir(sd);
// If we are a slave and no master was found to sync then become the master // If we are a secondary and no main was found to sync then become the main
if (unlikely(synced == 0) && likely(entries) && likely(afl->is_slave)) { if (unlikely(synced == 0) && likely(entries) &&
likely(afl->is_secondary_node)) {
// there is a small race condition here that another slave runs at the same // there is a small race condition here that another secondary runs at the
// time. If so, the first temporary master running again will demote // same time. If so, the first temporary main node running again will demote
// themselves so this is not an issue // themselves so this is not an issue
u8 path[PATH_MAX]; u8 path[PATH_MAX];
afl->is_master = 1; afl->is_main_node = 1;
sprintf(path, "%s/is_master", afl->out_dir); sprintf(path, "%s/is_main_node", afl->out_dir);
int fd = open(path, O_CREAT | O_RDWR, 0644); int fd = open(path, O_CREAT | O_RDWR, 0644);
if (fd >= 0) { close(fd); } if (fd >= 0) { close(fd); }

View File

@ -98,12 +98,13 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
"exec_timeout : %u\n" "exec_timeout : %u\n"
"slowest_exec_ms : %u\n" "slowest_exec_ms : %u\n"
"peak_rss_mb : %lu\n" "peak_rss_mb : %lu\n"
"cpu_affinity : %d\n"
"edges_found : %u\n" "edges_found : %u\n"
"var_byte_count : %u\n" "var_byte_count : %u\n"
"afl_banner : %s\n" "afl_banner : %s\n"
"afl_version : " VERSION "afl_version : " VERSION
"\n" "\n"
"target_mode : %s%s%s%s%s%s%s%s\n" "target_mode : %s%s%s%s%s%s%s%s%s\n"
"command_line : %s\n", "command_line : %s\n",
afl->start_time / 1000, cur_time / 1000, afl->start_time / 1000, cur_time / 1000,
(cur_time - afl->start_time) / 1000, (u32)getpid(), (cur_time - afl->start_time) / 1000, (u32)getpid(),
@ -123,13 +124,14 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
#else #else
(unsigned long int)(rus.ru_maxrss >> 10), (unsigned long int)(rus.ru_maxrss >> 10),
#endif #endif
t_bytes, afl->var_byte_count, afl->use_banner, afl->cpu_aff, t_bytes, afl->var_byte_count, afl->use_banner,
afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
afl->dumb_mode ? " dumb " : "", afl->no_forkserver ? "no_fsrv " : "", afl->non_instrumented_mode ? " non_instrumented " : "",
afl->crash_mode ? "crash " : "", afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
afl->persistent_mode ? "persistent " : "", afl->persistent_mode ? "persistent " : "",
afl->shmem_testcase_mode ? "shmem_testcase " : "",
afl->deferred_mode ? "deferred " : "", afl->deferred_mode ? "deferred " : "",
(afl->unicorn_mode || afl->fsrv.qemu_mode || afl->dumb_mode || (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->non_instrumented_mode ||
afl->no_forkserver || afl->crash_mode || afl->persistent_mode || afl->no_forkserver || afl->crash_mode || afl->persistent_mode ||
afl->deferred_mode) afl->deferred_mode)
? "" ? ""
@ -137,6 +139,32 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
afl->orig_cmdline); afl->orig_cmdline);
/* ignore errors */ /* ignore errors */
if (afl->debug) {
uint32_t i = 0;
fprintf(f, "virgin_bytes :");
for (i = 0; i < afl->fsrv.map_size; i++) {
if (afl->virgin_bits[i] != 0xff) {
fprintf(f, " %d[%02x]", i, afl->virgin_bits[i]);
}
}
fprintf(f, "\n");
fprintf(f, "var_bytes :");
for (i = 0; i < afl->fsrv.map_size; i++) {
if (afl->var_bytes[i]) { fprintf(f, " %d", i); }
}
fprintf(f, "\n");
}
fclose(f); fclose(f);
} }
@ -326,7 +354,7 @@ void show_stats(afl_state_t *afl) {
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */ /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
if (!afl->dumb_mode && afl->cycles_wo_finds > 100 && if (!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
!afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done) { !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done) {
afl->stop_soon = 2; afl->stop_soon = 2;
@ -414,7 +442,7 @@ void show_stats(afl_state_t *afl) {
" process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
" overall results " bSTG bH2 bH2 bRT "\n"); " overall results " bSTG bH2 bH2 bRT "\n");
if (afl->dumb_mode) { if (afl->non_instrumented_mode) {
strcpy(tmp, cRST); strcpy(tmp, cRST);
@ -460,7 +488,7 @@ void show_stats(afl_state_t *afl) {
/* We want to warn people about not seeing new paths after a full cycle, /* We want to warn people about not seeing new paths after a full cycle,
except when resuming fuzzing or running in non-instrumented mode. */ except when resuming fuzzing or running in non-instrumented mode. */
if (!afl->dumb_mode && if (!afl->non_instrumented_mode &&
(afl->last_path_time || afl->resuming_fuzz || afl->queue_cycle == 1 || (afl->last_path_time || afl->resuming_fuzz || afl->queue_cycle == 1 ||
afl->in_bitmap || afl->crash_mode)) { afl->in_bitmap || afl->crash_mode)) {
@ -469,7 +497,7 @@ void show_stats(afl_state_t *afl) {
} else { } else {
if (afl->dumb_mode) { if (afl->non_instrumented_mode) {
SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST
" (non-instrumented mode) "); " (non-instrumented mode) ");
@ -524,8 +552,9 @@ void show_stats(afl_state_t *afl) {
t_byte_ratio); t_byte_ratio);
SAYF(" map density : %s%-21s" bSTG bV "\n", SAYF(" map density : %s%-21s" bSTG bV "\n",
t_byte_ratio > 70 ? cLRD t_byte_ratio > 70
: ((t_bytes < 200 && !afl->dumb_mode) ? cPIN : cRST), ? cLRD
: ((t_bytes < 200 && !afl->non_instrumented_mode) ? cPIN : cRST),
tmp); tmp);
sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_paths), sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_paths),
@ -1020,10 +1049,11 @@ void show_init_stats(afl_state_t *afl) {
} }
/* In dumb mode, re-running every timing out test case with a generous time /* In non-instrumented mode, re-running every timing out test case with a
generous time
limit is very expensive, so let's select a more conservative default. */ limit is very expensive, so let's select a more conservative default. */
if (afl->dumb_mode && !(afl->afl_env.afl_hang_tmout)) { if (afl->non_instrumented_mode && !(afl->afl_env.afl_hang_tmout)) {
afl->hang_tmout = MIN(EXEC_TIMEOUT, afl->fsrv.exec_tmout * 2 + 100); afl->hang_tmout = MIN(EXEC_TIMEOUT, afl->fsrv.exec_tmout * 2 + 100);

View File

@ -130,7 +130,7 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
" -N - do not unlink the fuzzing input file (only for " " -N - do not unlink the fuzzing input file (only for "
"devices etc.!)\n" "devices etc.!)\n"
" -d - quick & dirty mode (skips deterministic steps)\n" " -d - quick & dirty mode (skips deterministic steps)\n"
" -n - fuzz without instrumentation (dumb mode)\n" " -n - fuzz without instrumentation (non-instrumented mode)\n"
" -x dir - optional fuzzer dictionary (see README.md, its really " " -x dir - optional fuzzer dictionary (see README.md, its really "
"good!)\n\n" "good!)\n\n"
@ -246,7 +246,7 @@ int main(int argc, char **argv_orig, char **envp) {
u64 prev_queued = 0; u64 prev_queued = 0;
u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE; u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE;
u8 * extras_dir = 0; u8 * extras_dir = 0;
u8 mem_limit_given = 0, exit_1 = 0; u8 mem_limit_given = 0, exit_1 = 0, debug = 0;
char **use_argv; char **use_argv;
struct timeval tv; struct timeval tv;
@ -257,10 +257,11 @@ int main(int argc, char **argv_orig, char **envp) {
afl_state_t *afl = calloc(1, sizeof(afl_state_t)); afl_state_t *afl = calloc(1, sizeof(afl_state_t));
if (!afl) { FATAL("Could not create afl state"); } if (!afl) { FATAL("Could not create afl state"); }
if (get_afl_env("AFL_DEBUG")) { afl->debug = 1; } if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; }
map_size = get_map_size(); map_size = get_map_size();
afl_state_init(afl, map_size); afl_state_init(afl, map_size);
afl->debug = debug;
afl_fsrv_init(&afl->fsrv); afl_fsrv_init(&afl->fsrv);
read_afl_environment(afl, envp); read_afl_environment(afl, envp);
@ -379,17 +380,19 @@ int main(int argc, char **argv_orig, char **envp) {
*c = 0; *c = 0;
if (sscanf(c + 1, "%u/%u", &afl->master_id, &afl->master_max) != 2 || if (sscanf(c + 1, "%u/%u", &afl->main_node_id, &afl->main_node_max) !=
!afl->master_id || !afl->master_max || 2 ||
afl->master_id > afl->master_max || afl->master_max > 1000000) { !afl->main_node_id || !afl->main_node_max ||
afl->main_node_id > afl->main_node_max ||
afl->main_node_max > 1000000) {
FATAL("Bogus master ID passed to -M"); FATAL("Bogus main node ID passed to -M");
} }
} }
afl->is_master = 1; afl->is_main_node = 1;
} }
@ -399,7 +402,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); } if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
afl->sync_id = ck_strdup(optarg); afl->sync_id = ck_strdup(optarg);
afl->is_slave = 1; afl->is_secondary_node = 1;
afl->skip_deterministic = 1; afl->skip_deterministic = 1;
afl->use_splicing = 1; afl->use_splicing = 1;
break; break;
@ -533,14 +536,19 @@ int main(int argc, char **argv_orig, char **envp) {
case 'n': /* dumb mode */ case 'n': /* dumb mode */
if (afl->dumb_mode) { FATAL("Multiple -n options not supported"); } if (afl->non_instrumented_mode) {
FATAL("Multiple -n options not supported");
}
if (afl->afl_env.afl_dumb_forksrv) { if (afl->afl_env.afl_dumb_forksrv) {
afl->dumb_mode = 2; afl->non_instrumented_mode = 2;
} else { } else {
afl->dumb_mode = 1; afl->non_instrumented_mode = 1;
} }
@ -556,6 +564,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); } if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
afl->fsrv.qemu_mode = 1; afl->fsrv.qemu_mode = 1;
afl->shmem_testcase_mode = 1;
if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; } if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
@ -572,6 +581,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); } if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
afl->unicorn_mode = 1; afl->unicorn_mode = 1;
afl->shmem_testcase_mode = 1;
if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; } if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; }
@ -582,6 +592,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->use_wine) { FATAL("Multiple -W options not supported"); } if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
afl->fsrv.qemu_mode = 1; afl->fsrv.qemu_mode = 1;
afl->use_wine = 1; afl->use_wine = 1;
afl->shmem_testcase_mode = 1;
if (!mem_limit_given) { afl->fsrv.mem_limit = 0; } if (!mem_limit_given) { afl->fsrv.mem_limit = 0; }
@ -781,6 +792,8 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" " OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
"Eißfeldt, Andrea Fioraldi and Dominik Maier"); "Eißfeldt, Andrea Fioraldi and Dominik Maier");
OKF("afl++ is open source, get it at " OKF("afl++ is open source, get it at "
@ -790,10 +803,12 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("afl-tmin fork server patch from github.com/nccgroup/TriforceAFL"); OKF("afl-tmin fork server patch from github.com/nccgroup/TriforceAFL");
OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
if (afl->sync_id && afl->is_master && afl->afl_env.afl_custom_mutator_only) { if (afl->sync_id && afl->is_main_node &&
afl->afl_env.afl_custom_mutator_only) {
WARNF( WARNF(
"Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will " "Using -M main node with the AFL_CUSTOM_MUTATOR_ONLY mutator options "
"will "
"result in no deterministic mutations being done!"); "result in no deterministic mutations being done!");
} }
@ -841,7 +856,7 @@ int main(int argc, char **argv_orig, char **envp) {
} }
/* randamsa_init installs some signal hadlers, call it before /* radamsa_init installs some signal handlers, call it before
setup_signal_handlers so that AFL++ can then replace those signal setup_signal_handlers so that AFL++ can then replace those signal
handlers */ handlers */
radamsa_init_ptr(); radamsa_init_ptr();
@ -871,7 +886,7 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (afl->dumb_mode) { if (afl->non_instrumented_mode) {
if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); } if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); } if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
@ -954,13 +969,13 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (afl->dumb_mode == 2 && afl->no_forkserver) { if (afl->non_instrumented_mode == 2 && afl->no_forkserver) {
FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");
} }
afl->fsrv.use_fauxsrv = afl->dumb_mode == 1 || afl->no_forkserver; afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
if (getenv("LD_PRELOAD")) { if (getenv("LD_PRELOAD")) {
@ -1057,7 +1072,7 @@ int main(int argc, char **argv_orig, char **envp) {
check_cpu_governor(afl); check_cpu_governor(afl);
afl->fsrv.trace_bits = afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->dumb_mode); afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
if (!afl->in_bitmap) { memset(afl->virgin_bits, 255, afl->fsrv.map_size); } if (!afl->in_bitmap) { memset(afl->virgin_bits, 255, afl->fsrv.map_size); }
memset(afl->virgin_tmout, 255, afl->fsrv.map_size); memset(afl->virgin_tmout, 255, afl->fsrv.map_size);
@ -1065,7 +1080,7 @@ int main(int argc, char **argv_orig, char **envp) {
init_count_class16(); init_count_class16();
if (afl->is_master && check_master_exists(afl) == 1) { if (afl->is_main_node && check_main_node_exists(afl) == 1) {
WARNF("it is wasteful to run more than one master!"); WARNF("it is wasteful to run more than one master!");
sleep(1); sleep(1);
@ -1074,9 +1089,9 @@ int main(int argc, char **argv_orig, char **envp) {
setup_dirs_fds(afl); setup_dirs_fds(afl);
if (afl->is_slave && check_master_exists(afl) == 0) { if (afl->is_secondary_node && check_main_node_exists(afl) == 0) {
WARNF("no -M master found. You need to run one master!"); WARNF("no -M main node found. You need to run one main instance!");
sleep(5); sleep(5);
} }
@ -1178,6 +1193,8 @@ int main(int argc, char **argv_orig, char **envp) {
check_binary(afl, argv[optind]); check_binary(afl, argv[optind]);
if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
afl->start_time = get_cur_time(); afl->start_time = get_cur_time();
if (afl->fsrv.qemu_mode) { if (afl->fsrv.qemu_mode) {
@ -1213,6 +1230,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->cmplog_fsrv.init_child_func = cmplog_exec_child; afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child_output); afl->afl_env.afl_debug_child_output);
OKF("Cmplog forkserver successfully started");
} }
@ -1366,10 +1384,10 @@ stop_fuzzing:
time_spent_working / afl->fsrv.total_execs); time_spent_working / afl->fsrv.total_execs);
#endif #endif
if (afl->is_master) { if (afl->is_main_node) {
u8 path[PATH_MAX]; u8 path[PATH_MAX];
sprintf(path, "%s/is_master", afl->out_dir); sprintf(path, "%s/is_main_node", afl->out_dir);
unlink(path); unlink(path);
} }
@ -1383,7 +1401,7 @@ stop_fuzzing:
if (afl->shm_fuzz) { if (afl->shm_fuzz) {
afl_shm_deinit(afl->shm_fuzz); afl_shm_deinit(afl->shm_fuzz);
free(afl->shm_fuzz); ck_free(afl->shm_fuzz);
} }

View File

@ -96,7 +96,8 @@ void afl_shm_deinit(sharedmem_t *shm) {
Returns a pointer to shm->map for ease of use. Returns a pointer to shm->map for ease of use.
*/ */
u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) { u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
unsigned char non_instrumented_mode) {
shm->map_size = map_size; shm->map_size = map_size;
@ -137,12 +138,12 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
} }
/* If somebody is asking us to fuzz instrumented binaries in dumb mode, /* If somebody is asking us to fuzz instrumented binaries in non-instrumented
we don't want them to detect instrumentation, since we won't be sending mode, we don't want them to detect instrumentation, since we won't be
fork server commands. This should be replaced with better auto-detection sending fork server commands. This should be replaced with better
later on, perhaps? */ auto-detection later on, perhaps? */
if (!dumb_mode) setenv(SHM_ENV_VAR, shm->g_shm_file_path, 1); if (!non_instrumented_mode) setenv(SHM_ENV_VAR, shm->g_shm_file_path, 1);
if (shm->map == -1 || !shm->map) PFATAL("mmap() failed"); if (shm->map == -1 || !shm->map) PFATAL("mmap() failed");
@ -164,12 +165,12 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
shm_str = alloc_printf("%d", shm->shm_id); shm_str = alloc_printf("%d", shm->shm_id);
/* If somebody is asking us to fuzz instrumented binaries in dumb mode, /* If somebody is asking us to fuzz instrumented binaries in non-instrumented
we don't want them to detect instrumentation, since we won't be sending mode, we don't want them to detect instrumentation, since we won't be
fork server commands. This should be replaced with better auto-detection sending fork server commands. This should be replaced with better
later on, perhaps? */ auto-detection later on, perhaps? */
if (!dumb_mode) { setenv(SHM_ENV_VAR, shm_str, 1); } if (!non_instrumented_mode) { setenv(SHM_ENV_VAR, shm_str, 1); }
ck_free(shm_str); ck_free(shm_str);
@ -177,7 +178,7 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
shm_str = alloc_printf("%d", shm->cmplog_shm_id); shm_str = alloc_printf("%d", shm->cmplog_shm_id);
if (!dumb_mode) { setenv(CMPLOG_SHM_ENV_VAR, shm_str, 1); } if (!non_instrumented_mode) { setenv(CMPLOG_SHM_ENV_VAR, shm_str, 1); }
ck_free(shm_str); ck_free(shm_str);

View File

@ -923,17 +923,36 @@ test -d ../unicorn_mode/unicornafl && {
fi fi
cd ../unicorn_mode/samples/persistent
make >>errors 2>&1
$ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds"
AFL_DEBUG_CHILD_OUTPUT=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
test -n "$( ls out/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)"
} || {
echo CUT------------------------------------------------------------------CUT
cat errors
echo CUT------------------------------------------------------------------CUT
$ECHO "$RED[!] afl-fuzz is not working correctly with unicorn_mode (persistent)"
CODE=1
}
rm -rf out errors >/dev/null
make clean >/dev/null
cd ../../../test
# travis workaround # travis workaround
test "$PY" = "/opt/pyenv/shims/python" -a -x /usr/bin/python && PY=/usr/bin/python test "$PY" = "/opt/pyenv/shims/python" -a -x /usr/bin/python && PY=/usr/bin/python
mkdir -p in mkdir -p in
echo 0 > in/in echo 0 > in/in
$ECHO "$GREY[*] Using python binary $PY" $ECHO "$GREY[*] Using python binary $PY"
if ! $PY -c 'import unicornafl' 2>/dev/null ; then if ! $PY -c 'import unicornafl' 2>/dev/null ; then
$ECHO "$YELLOW[-] we cannot test unicorn_mode because it is not present" $ECHO "$YELLOW[-] we cannot test unicorn_mode for python because it is not present"
INCOMPLETE=1 INCOMPLETE=1
else else
{ {
$ECHO "$GREY[*] running afl-fuzz for unicorn_mode, this will take approx 25 seconds" $ECHO "$GREY[*] running afl-fuzz for unicorn_mode in python, this will take approx 25 seconds"
{ {
../afl-fuzz -m ${MEM_LIMIT} -V25 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/simple/simple_test_harness.py @@ >>errors 2>&1 ../afl-fuzz -m ${MEM_LIMIT} -V25 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/simple/simple_test_harness.py @@ >>errors 2>&1
} >>errors 2>&1 } >>errors 2>&1

View File

@ -1 +1 @@
5833117 a6e943c

View File

@ -198,11 +198,11 @@ echo "[*] Unicornafl bindings installed successfully."
# Compile the sample, run it, verify that it works! # Compile the sample, run it, verify that it works!
echo "[*] Testing unicornafl python functionality by running a sample test harness" echo "[*] Testing unicornafl python functionality by running a sample test harness"
cd ../samples/simple || exit 1 cd ../samples/simple || echo "Cannot cd"
# Run afl-showmap on the sample application. If anything comes out then it must have worked! # Run afl-showmap on the sample application. If anything comes out then it must have worked!
unset AFL_INST_RATIO unset AFL_INST_RATIO
echo 0 | ../../../afl-showmap -U -m none -t 2000 -q -o ./.test-instr0 -- $PYTHONBIN ./simple_test_harness.py ./sample_inputs/sample1.bin || exit 1 echo 0 | ../../../afl-showmap -U -m none -t 2000 -q -o ./.test-instr0 -- $PYTHONBIN ./simple_test_harness.py ./sample_inputs/sample1.bin || echo "Showmap"
if [ -s ./.test-instr0 ] if [ -s ./.test-instr0 ]
then then

View File

@ -184,7 +184,7 @@ int main(int argc, char **argv, char **envp) {
// Map memory. // Map memory.
mem_map_checked(uc, BASE_ADDRESS, len, UC_PROT_ALL); mem_map_checked(uc, BASE_ADDRESS, len, UC_PROT_ALL);
printf("Len: %lx", len); printf("Len: %lx\n", len);
fflush(stdout); fflush(stdout);
// write machine code to be emulated to memory // write machine code to be emulated to memory

View File

@ -11,7 +11,7 @@
Run under AFL as follows: Run under AFL as follows:
$ cd <afl_path>/unicorn_mode/samples/simple/ $ cd <afl_path>/unicorn_mode/samples/simple/
$ ../../../afl-fuzz -U -m none -i ./sample_inputs -o ./output -- python compcov_test_harness.py @@ $ AFL_COMPCOV_LEVEL=2 ../../../afl-fuzz -U -m none -i ./sample_inputs -o ./output -- python compcov_test_harness.py @@
""" """
import argparse import argparse

View File

@ -38,13 +38,13 @@ harness.o: harness.c ../../unicornafl/include/unicorn/*.h
${MYCC} ${CFLAGS} -O3 -c harness.c ${MYCC} ${CFLAGS} -O3 -c harness.c
harness-debug.o: harness.c ../../unicornafl/include/unicorn/*.h harness-debug.o: harness.c ../../unicornafl/include/unicorn/*.h
${MYCC} ${CFLAGS} -g -c harness.c -o $@ ${MYCC} ${CFLAGS} -DAFL_DEBUG=1 -g -c harness.c -o $@
harness: harness.o harness: harness.o
${MYCC} -L${LIBDIR} harness.o ../../unicornafl/libunicornafl.a $(LDFLAGS) -o $@ ${MYCC} -L${LIBDIR} harness.o ../../unicornafl/libunicornafl.a $(LDFLAGS) -o $@
debug: harness-debug.o debug: harness-debug.o
${MYCC} -L${LIBDIR} harness.o ../../unicornafl/libunicornafl.a $(LDFLAGS) -o harness-debug ${MYCC} -L${LIBDIR} harness-debug.o ../../unicornafl/libunicornafl.a $(LDFLAGS) -o harness-debug
fuzz: harness fuzz: harness
../../../afl-fuzz -m none -i sample_inputs -o out -- ./harness @@ ../../../afl-fuzz -m none -i sample_inputs -o out -- ./harness @@

View File

@ -68,7 +68,7 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user
/* /*
The sample uses strlen, since we don't have a loader or libc, we'll fake it. The sample uses strlen, since we don't have a loader or libc, we'll fake it.
We know the strlen will return the lenght of argv[1] that we just planted. We know the strlen will return the length of argv[1] that we just planted.
It will be a lot faster than an actual strlen for this specific purpose. It will be a lot faster than an actual strlen for this specific purpose.
*/ */
static void hook_strlen(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { static void hook_strlen(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
@ -129,6 +129,16 @@ static bool place_input_callback(
return false; return false;
} }
#if defined(AFL_DEBUG)
printf("[d] harness: input len=%ld, [ ", input_len);
int i = 0;
for (i = 0; i < input_len && i < 16; i++) {
printf("0x%02x ", (unsigned char) input[i]);
}
if (input_len > 16) printf("... ");
printf("]\n");
#endif
// For persistent mode, we have to set up stack and memory each time. // For persistent mode, we have to set up stack and memory each time.
uc_reg_write(uc, UC_X86_REG_RIP, &CODE_ADDRESS); // Set the instruction pointer back uc_reg_write(uc, UC_X86_REG_RIP, &CODE_ADDRESS); // Set the instruction pointer back
// Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly) // Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly)
@ -194,7 +204,7 @@ int main(int argc, char **argv, char **envp) {
// Map memory. // Map memory.
mem_map_checked(uc, BASE_ADDRESS, len, UC_PROT_ALL); mem_map_checked(uc, BASE_ADDRESS, len, UC_PROT_ALL);
printf("Len: %lx", len); printf("Len: %lx\n", len);
fflush(stdout); fflush(stdout);
// write machine code to be emulated to memory // write machine code to be emulated to memory
@ -219,7 +229,7 @@ int main(int argc, char **argv, char **envp) {
// reserve some space for our input data // reserve some space for our input data
mem_map_checked(uc, INPUT_LOCATION, INPUT_SIZE_MAX, UC_PROT_READ); mem_map_checked(uc, INPUT_LOCATION, INPUT_SIZE_MAX, UC_PROT_READ);
// build a "dummy" argv with lenth 2 at 0x10000: // build a "dummy" argv with length 2 at 0x10000:
// 0x10000 argv[0] NULL // 0x10000 argv[0] NULL
// 0x10008 argv[1] (char *)0x10016 --. points to the next offset. // 0x10008 argv[1] (char *)0x10016 --. points to the next offset.
// 0x10016 argv[1][0], ... <-^ contains the acutal input data. (INPUT_LOCATION + INPUT_OFFSET) // 0x10016 argv[1][0], ... <-^ contains the acutal input data. (INPUT_LOCATION + INPUT_OFFSET)

@ -1 +1 @@
Subproject commit 5833117abf55d54c4191ead81312764df03a48bc Subproject commit a6e943c683ecb3aba1baaddc7a02eefd2c5a5ad9