Compare commits

..

133 Commits

Author SHA1 Message Date
16cc444ae5 Merge pull request #2460 from AFLplusplus/dev
update frida
2025-05-30 18:14:52 +02:00
a9900f02cb Merge pull request #2459 from WorksButNotTested/update-frida
Update FRIDA again
2025-05-29 22:36:07 +02:00
e82de006a7 Update FRIDA again 2025-05-29 17:33:39 +01:00
4a923e59fd Update FRIDA (#2458) 2025-05-28 22:52:27 +02:00
20348a63bd Merge pull request #2455 from AFLplusplus/dev
enable llvm 21
2025-05-27 15:11:16 +02:00
cafcb343b1 enable llvm 21 2025-05-27 13:35:04 +02:00
588dda3e84 Merge pull request #2453 from AFLplusplus/dev
push to stable
2025-05-26 11:20:25 +02:00
a17d1daab8 deepwiki 2025-05-26 11:19:04 +02:00
affe7cf5b4 set errno=0 when no afl-fuzz present 2025-05-25 11:38:05 +02:00
fa1ac051eb Merge pull request #2451 from kcwu/revise-map-resize
Revise map resize
2025-05-25 11:08:05 +02:00
f21cc2da58 nit 2025-05-25 11:05:01 +02:00
8c1ab19ebe add libaflppdesock 2025-05-25 11:04:00 +02:00
2e7f191f3b extract function to resize map buffers 2025-05-25 09:33:34 +08:00
8090c82c63 fix resize afl->top_rated 2025-05-24 23:36:54 +08:00
f610f53838 remove redundent code
these field are already copied in afl_fsrv_init_dup
2025-05-24 22:28:26 +08:00
0012f710d8 Merge pull request #2450 from AFLplusplus/dev
push to stable
2025-05-24 13:24:03 +02:00
be00ea9f00 Merge pull request #2446 from kcwu/fix-save_if_interesting
fix save_if_interesting
2025-05-24 12:43:26 +02:00
d0df78f07a use functions instead of macros 2025-05-24 16:39:31 +08:00
7e1dc85450 nit 2025-05-23 09:19:42 +02:00
8152def40e changelog 2025-05-23 09:18:55 +02:00
e6ed31d550 Merge pull request #2449 from AFLplusplus/hidden
instrument all hidden edges
2025-05-23 09:16:17 +02:00
77758a1343 nits in calibrate_case 2025-05-23 08:50:37 +02:00
ea1fbb75b3 Merge pull request #2448 from kcwu/setup-ld-preload
Refactor and simplify handling of AFL_PRELOAD
2025-05-23 08:22:03 +02:00
d62a885f0f simplify code 2025-05-23 10:48:56 +08:00
55d534cd6d extract function afl_fsrv_setup_preload 2025-05-23 10:39:03 +08:00
cee764689c fix save_if_interesting
The value of `classified`, `bits_new`, and `cksum`, were not always
correctly maintained.
 1. In the past, `afl->queue_top->exec_cksum` was always assigned when
    `add_to_queue`, however it became conditional since cd57641705.
    This doesn't change correctness because calibrate_case() will
    calculate the checksum. However, this mean one calibration run is
    wasted.

 2. Sometimes `classified` is set incorrectly.
    For example, this code snippet
    ```
    new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
    classified = 1;
    ```
    should be changed to
    ```
    new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
    if (new_bits) classified = 1;
    ```

This commit fixed above issues and use macros to make the code easier to
understand. This should prevent to forget to set classified in the
future (like the bug fixed by 30c93d1321).

The macros also defers the calculations to where the values are really
needed. This could save cpu if the code returns earlier. For example,
if a case is timeout first and not timeout the second time, the current
code does classify_counts, which is not always needed.
2025-05-22 23:14:40 +08:00
d02390e62e add desock option 2025-05-22 17:08:12 +02:00
1f878f1b7c Merge pull request #2438 from AFLplusplus/dev
push to stable
2025-05-22 12:00:37 +02:00
ff1e0580b0 changelog 2025-05-22 12:00:10 +02:00
4730fa4226 Merge pull request #2444 from AFLplusplus/better_sync
Better sync
2025-05-22 11:55:53 +02:00
50fb923691 nit 2025-05-22 11:55:39 +02:00
300fc1f002 fix startup check 2025-05-21 11:52:57 +02:00
4ff40ee6fd add comment 2025-05-20 17:09:52 +02:00
c3d5f3f471 skip entried synced from us if we have not restarted 2025-05-20 17:07:30 +02:00
45a7d65207 Merge pull request #2433 from kcwu/not-sync-known-case
skip known case if the file is actually coming from us
2025-05-20 16:09:14 +02:00
b8d1f16979 Merge pull request #2441 from abhisen7/fix/afl-cmin
Execute ASan targets without leak checks to read AFL_MAP_SIZE
2025-05-19 14:11:00 +02:00
c699aa252d reduce overhead 2025-05-19 18:53:22 +08:00
7c27fc7cfe skip known case if the file is actually coming from us
Assume we have one main node and N secondary nodes in a parallel
fuzzing campaign. Every time the main node found a new case, the case
will be synced to all secondary nodes. Later when the main node sync,
the main node need to run the file again to see if the file is
interesting because they are "new" cases on the secondary nodes.

In other words, for one new case, the main node has to run the redundent
test N times. This is wasteful and slowed down the progress of main
node.

The wasteful issue on secondary nodes is acceptable because we can run
more secondary nodes to mitigate the inefficiency. OTOH, increasing the
number of secondary nodes slow down the main node further.
2025-05-19 18:50:22 +08:00
46b9efbf7d Execute ASan targets without leak checks to read AFL_MAP_SIZE 2025-05-19 11:52:40 +02:00
92d1a60096 print deubg on before missed instrumented instructions 2025-05-19 10:23:22 +02:00
f90fafc07a Merge pull request #2440 from AFLplusplus/dev
push to hidden
2025-05-19 10:02:12 +02:00
59c2198532 Merge pull request #2437 from AFLplusplus/fixsync
Fix sync for restarted instances
2025-05-18 17:30:30 +02:00
c7654c028d nit 2025-05-18 17:26:57 +02:00
ccc7ab5944 use goto and free glob 2025-05-18 17:23:53 +02:00
06afa48e02 code format 2025-05-18 14:07:03 +02:00
816334000a Merge branch 'stable' into dev 2025-05-18 14:06:09 +02:00
2573ccb66e flush stdout for AFL_DUMP_MAP_SIZE 2025-05-18 14:02:58 +02:00
767b990af6 fix syncing to restarted instances 2025-05-18 11:03:40 +02:00
1631e5988f nit 2025-05-17 13:57:24 +02:00
3ee3b5c384 code format 2025-05-17 00:05:31 +02:00
7f7d5ff29b Merge pull request #2427 from kcwu/dev
avoid duplicated code
2025-05-16 18:05:48 +02:00
6dcd0aa089 Add env variable SHM_FUZZ_MAP_SIZE (#2430)
* Add env variable SHM_FUZZ_PAGE_SIZE to tell the forkserver about the max shm input size

* fix

* PAGE_SIZE->MAP_SIZE

* fix more nits

* More cleanup
2025-05-16 12:14:58 +02:00
c47221db7c Fix aflpp_driver compilation on MacOS (#2431) (#2432)
* Fix aflpp_driver compilation on MacOS

* less newline
2025-05-15 19:43:30 +02:00
d6bb210410 Fix aflpp_driver compilation on MacOS (#2431)
* Fix aflpp_driver compilation on MacOS

* less newline
2025-05-15 19:05:20 +02:00
c2a026f68f Merge pull request #2428 from AFLplusplus/dev
push to stable
2025-05-15 14:12:44 +02:00
2a97350754 Merge pull request #2426 from AFLplusplus/fix_resume
Fix resume for syncing
2025-05-15 14:09:09 +02:00
9004be20b8 update changelog 2025-05-15 14:08:49 +02:00
dffd6537ae avoid duplicated code 2025-05-15 18:44:25 +08:00
25d7d65216 workaround for compiler asan+lto issues 2025-05-15 11:46:39 +02:00
7a32331c99 better solution 2025-05-15 11:05:02 +02:00
b27e861a51 fix resume for syncing 2025-05-15 10:47:36 +02:00
875c3902f0 Merge pull request #2425 from AFLplusplus/dev
push to stable
2025-05-15 10:20:25 +02:00
bedb38e216 fix UAF in -F 2025-05-14 21:05:38 +02:00
ef0c236427 update fuzzing_in_depth 2025-05-14 16:45:23 +02:00
b6d1247e7d fix incorrect allocation size for top_rated_candidates (#2424) 2025-05-14 10:31:31 +02:00
62e63d1125 Merge pull request #2423 from kcwu/more-stats-sync-foreign
show stats more frequently when sync foreign
2025-05-13 10:54:44 +02:00
9e4449bad2 code format 2025-05-13 10:51:56 +02:00
6d4a56e481 Merge pull request #2421 from wtdcode/rename-afl-san-no-inst
Rename `AFL_SAN_NO_INST` to `AFL_FSRV_ONLY`
2025-05-13 10:51:08 +02:00
221439fc7a fix foreign sync naming 2025-05-13 10:42:26 +02:00
mio
fca39a6ec3 implement AFL_GCC_ONLY_FSRV 2025-05-13 16:15:11 +08:00
mio
9476204da0 rename to AFL_LLVM_ONLY_FSRV 2025-05-13 15:45:33 +08:00
919108ee57 show stats more frequently when sync foreign
otherwise, the stats might have no updates for hours for large foreign directory
2025-05-13 15:22:50 +08:00
mio
8204bf6915 Allow afl-cmin.py for pre-3.12 by backport from more-itertools 2025-05-13 00:12:18 +08:00
b9e361df46 cmplog: ignore loop icmp 2025-05-12 12:24:52 +02:00
mio
19fc27a3f7 update docs 2025-05-12 14:55:20 +08:00
mio
2357daebe0 update SAND docs accordingly 2025-05-12 14:46:29 +08:00
mio
f3995d5225 rename AFL_SAN_NO_INST to AFL_FSRV_ONLY 2025-05-12 14:43:08 +08:00
ea6d182b4a print skipped bb 2025-05-11 19:52:55 +02:00
adeaa714ce do not instrument icmp/fcmp if result is used in select 2025-05-11 19:27:23 +02:00
231a4b1937 fix fcmp 2025-05-09 17:14:44 +02:00
977e08cda1 fix fcmp + icmp for vectors 2025-05-09 17:07:54 +02:00
6b1d6a9055 Merge pull request #2418 from Evian-Zhang/memmem-no-nul
Do not include NUL when memmem
2025-05-09 09:22:24 +02:00
4d9d8aaf16 afl-cmin.py nits 2025-05-09 09:12:37 +02:00
c150d8e17d Merge pull request #2413 from kcwu/afm-cmin
add afl-cmin.py
2025-05-09 09:09:08 +02:00
61e97a8ceb Do not match NUL when memmem 2025-05-09 09:46:05 +08:00
3f2e03aaf9 call afl-cmin.py if it can be executed successfully 2025-05-08 21:52:12 +08:00
406e4880c7 remove phi instrumentation 2025-05-08 09:36:05 +02:00
22b7d370bc try different intrumentation strategy 2025-05-07 19:01:51 +02:00
ec27e96486 reformat by black 2025-05-06 23:45:42 +08:00
fcca917f4f better variable following 2025-05-06 17:22:10 +02:00
5bf01afd6b fix 2025-05-06 14:40:08 +02:00
0a9916deab instrument hidden selects 2025-05-06 14:16:50 +02:00
b1730d99b6 new LLVM defaults! 2025-05-05 17:46:01 +02:00
6d45b286f8 nits 2025-05-05 14:35:52 +02:00
673463ff1c Merge pull request #2412 from alexandredoyen29/environment_forkserver
Environment variable to discriminate the target and the forkserver
2025-05-05 14:30:40 +02:00
f580fefc5f Doc 2025-05-05 11:12:51 +02:00
320d4b7ef8 Requested changes 2025-05-05 11:03:26 +02:00
19bd2984d5 Writing style mistaske 2025-05-05 10:52:27 +02:00
7d29418db5 Auxiliary variable for afl-forkserver.c too 2025-05-05 10:50:13 +02:00
4d984d6e2b getenv() call at the beginning of __afl_start_forkserver() 2025-05-05 10:44:34 +02:00
421b6492d3 Merge pull request #2414 from kcwu/refactor
Minor refactor and clean up
2025-05-05 10:42:03 +02:00
062f883160 add splice_optout_py prototype 2025-05-05 16:16:42 +08:00
a76ff5e798 Specific environment variable to choose if we want to be able to discriminate or not forkserver in preloaded libraries 2025-05-05 09:54:53 +02:00
e9f49527e9 We check before if the AFL_PRELOAD env variable is set 2025-05-05 09:49:56 +02:00
6f4767ea81 AFL_I_AM_THE_FORKSERVER becomes AFL_FORKSERVER_PARENT 2025-05-05 09:42:33 +02:00
d28b1418a2 Merge pull request #2410 from jwpconsulting/test-persistent-exit
Add test case for AFL_QEMU_PERSISTENT_EXITS
2025-05-05 09:37:53 +02:00
d10b85421d update qemuafl 2025-05-05 09:36:23 +02:00
6876ab7901 remove dead prototype 2025-05-05 08:46:49 +08:00
b1649f2fdb nyx nit 2025-05-05 08:44:26 +08:00
701299eefd remove dead code; we no longer use murmurhash 2025-05-05 08:44:26 +08:00
90e929ea17 only reinit shm map when make sense 2025-05-05 08:44:26 +08:00
24dc7b569c nit: simplify code
"!target_hash" already cover "afl->fsrv.nyx_mode && target_hash == 0"
2025-05-05 08:44:26 +08:00
7cb8ccc960 mention afl-cmin.py in afl-cmin 2025-05-04 19:35:55 +08:00
0c4f8934c7 add afl-cmin.py 2025-05-04 19:06:55 +08:00
cd0cb1e731 Setting the AFL_I_AM_THE_FORKSERVER environment variable in the begining of the forkserver child process, and unsetting it when the target is launched 2025-05-04 11:36:01 +02:00
52631d925d Merge pull request #2411 from Scott-Guest/gcc-sand
Disable GCC instrumentation for AFL_SAN_NO_INST
2025-05-03 09:38:39 +02:00
d40f935b4e Disable GCC instrumentation for AFL_SAN_NO_INST 2025-05-02 17:25:16 -07:00
b418a87340 Add test case for AFL_QEMU_PERSISTENT_EXITS
Add a test case to `test/test-qemu-mode.sh` and make sure that
AFL_QEMU_PERSISTENT_EXITS loops correctly.

This works only on platforms for which `afl-qemu-trace` detects exit
signals and resets the program counter.

This commit updates `test-instr.c` to optionally call `exit(n)` instead of
returning n to the operating system. This option can be activated using
the `EXIT_AT_END` flag. This way, we can test the
QEMU persistent exit mode without having to add a new test file.

You can compile and run `test-instr.c` with the exit mode like so:

```bash
gcc -o exit -DEXIT_AT_END test-instr.c
AFL_QEMU_DEBUG_MAPS= \
    AFL_DEBUG= \
    AFL_QEMU_PERSISTENT_ADDR=$(readelf -a exit | grep 'main$' | awk '{ printf "0x%s", $2 }') \
    AFL_QEMU_PERSISTENT_GPR=1 \
    AFL_QEMU_PERSISTENT_EXITS=1 \
    ./afl-qemu-trace exit
```

Press enter repeatedly and you will see an output like this:

```
...
Debug: Sending status 0xc201ffff

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!

test-instr:

Neither one or zero? How quaint!
```

To make sure that persistent exits are detected correctly on x86_64, I've made
the following changes to qemuafl:

```
 linux-user/i386/cpu_loop.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 4509f46b95..46bdbaf94a 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -235,7 +235,7 @@ void cpu_loop(CPUX86State *env)
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
             /* linux syscall from syscall instruction */
-            if (afl_fork_child && persistent_exits &&
+            if (persistent_exits &&
                 env->regs[R_EAX] == TARGET_NR_exit_group) {
               env->eip = afl_persistent_addr;
               continue;
```
2025-05-02 15:13:08 +09:00
04f2a2dd09 ignore unnecessary warnings for tools 2025-04-29 15:55:14 +02:00
aa1c58a077 Merge pull request #2408 from smoelius/color-no-ui-output
Color `AFL_NO_UI` output
2025-04-29 10:38:52 +02:00
cca5538747 Merge pull request #2409 from Scott-Guest/libdislocator-cflags
Add missing override directive for CFLAGS+= in libdislocator
2025-04-29 10:37:41 +02:00
c4be2ec32f utils/libdislocator/Makefile: Add missing override directive to CFLAGS+= 2025-04-28 20:52:15 -07:00
83a2a8aa14 Color AFL_NO_UI output 2025-04-28 20:29:10 -04:00
6c70d68783 update make flags 2025-04-28 22:09:58 +02:00
6d5784e955 lower values for fuzzing state assessment 2025-04-28 19:30:07 +02:00
5f7009d6e9 code format 2025-04-28 14:23:17 +02:00
48bce88050 Merge pull request #2406 from maribu/config/64-bit
Define WORD_SIZE_64 for more 64-bit arches
2025-04-28 14:22:53 +02:00
f43116d9e0 more classified count fixes 2025-04-28 14:22:37 +02:00
876a528156 Merge pull request #2403 from kcwu/fix-aflfast
fix power schedules
2025-04-28 14:12:22 +02:00
8a0e9c8915 minimum llvm 14 in docs 2025-04-28 14:03:12 +02:00
b083016304 Define WORD_SIZE_64 for more 64-bit arches
This enables 64-bit detection for the following additional systems:

- [PowerPC64 (little endian)](https://en.wikipedia.org/wiki/Ppc64)
- [S390x](https://en.wikipedia.org/wiki/S390x)
- [LoongArch64](https://en.wikipedia.org/wiki/LoongArch64)
2025-04-28 07:58:09 +02:00
30c93d1321 fix power schedules
AFLFast power schedules regressed since v4.31c
2025-04-27 00:07:06 +08:00
e30a17be91 v4.33a init 2025-04-26 15:57:30 +02:00
60 changed files with 2553 additions and 1024 deletions

View File

@ -31,7 +31,7 @@ PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
ASAN_OPTIONS=detect_leaks=0
@ -76,14 +76,16 @@ ifdef IS_IOS
endif
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifndef ASAN_BUILD
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=full
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto
endif
endif
endif
endif
@ -313,8 +315,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
endif
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD -fno-lto
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -fno-lto
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) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"

View File

@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
$(PASSES): instrumentation/afl-gcc-common.h
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
ln -sf afl-cc afl-gcc-fast
ln -sf afl-cc afl-g++-fast
ln -sf afl-cc.8 afl-gcc-fast.8

View File

@ -32,8 +32,8 @@ VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -
SYS = $(shell uname -s)
override LLVM_TOO_NEW_DEFAULT := 19
override LLVM_TOO_OLD_DEFAULT := 13
override LLVM_TOO_NEW_DEFAULT := 21
override LLVM_TOO_OLD_DEFAULT := 14
ifeq "$(SYS)" "OpenBSD"
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
@ -69,7 +69,7 @@ endif
LLVM_STDCXX := gnu++11
LLVM_LTO := 0
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[1-9]\.' && echo 1 || echo 0)
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-9]\.' && echo 1 || echo 0)
# Uncomment to see the values assigned above
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
@ -470,7 +470,7 @@ endif
./afl-ld-lto: src/afl-ld-lto.c
ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif

View File

@ -4,7 +4,7 @@
Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.32c
GitHub version: 4.33a
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -230,7 +230,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
fuzzah @intrigus-lgtm
Yaakov Saxon Sergej Schumilo
Ziqiao Kong Ryan Berger
Sangjun Park
Sangjun Park Scott Guest
```
</details>
@ -259,3 +259,5 @@ presented at WOOT'20:
```
</details>
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/AFLplusplus/AFLplusplus)

View File

@ -1,12 +1,19 @@
#!/usr/bin/env sh
THISPATH=`dirname ${0}`
# call afl-cmin.py if it can be executed successfully.
if $THISPATH/afl-cmin.py --help > /dev/null 2>&1; then
exec $THISPATH/afl-cmin.py "$@"
fi
SYS=$(uname -s)
test "$SYS" = "Darwin" && {
echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead.
exit 1
}
export AFL_QUIET=1
export ASAN_OPTIONS=detect_leaks=0
THISPATH=`dirname ${0}`
export PATH="${THISPATH}:$PATH"
awk -f - -- ${@+"$@"} <<'EOF'
#!/usr/bin/awk -f

760
afl-cmin.py Executable file
View File

@ -0,0 +1,760 @@
#!/usr/bin/env python3
# Copyright 2016-2025 Google Inc.
# Copyright 2025 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import array
import base64
import collections
import glob
import hashlib
import itertools
import logging
import multiprocessing
import os
import shutil
import subprocess
import sys
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
from sys import hexversion
def _batched(iterable, n, *, strict=False):
"""Batch data into tuples of length *n*. If the number of items in
*iterable* is not divisible by *n*:
* The last batch will be shorter if *strict* is ``False``.
* :exc:`ValueError` will be raised if *strict* is ``True``.
>>> list(batched('ABCDEFG', 3))
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
"""
if n < 1:
raise ValueError('n must be at least one')
iterator = iter(iterable)
while batch := tuple(itertools.islice(iterator, n)):
if strict and len(batch) != n:
raise ValueError('batched(): incomplete batch')
yield batch
if hexversion >= 0x30D00A2: # pragma: no cover
from itertools import batched as itertools_batched
def batched(iterable, n, *, strict=False):
return itertools_batched(iterable, n, strict=strict)
else:
batched = _batched
batched.__doc__ = _batched.__doc__
try:
from tqdm import tqdm
except ImportError:
print('Hint: install python module "tqdm" to show progress bar')
class tqdm:
def __init__(self, data=None, *args, **argd):
self.data = data
def __iter__(self):
yield from self.data
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def update(self, *args):
pass
parser = argparse.ArgumentParser()
cpu_count = multiprocessing.cpu_count()
group = parser.add_argument_group("Required parameters")
group.add_argument(
"-i",
dest="input",
action="append",
metavar="dir",
required=True,
help="input directory with the starting corpus",
)
group.add_argument(
"-o",
dest="output",
metavar="dir",
required=True,
help="output directory for minimized files",
)
group = parser.add_argument_group("Execution control settings")
group.add_argument(
"-f",
dest="stdin_file",
metavar="file",
help="location read by the fuzzed program (stdin)",
)
group.add_argument(
"-m",
dest="memory_limit",
default="none",
metavar="megs",
type=lambda x: x if x == "none" else int(x),
help="memory limit for child process (default: %(default)s)",
)
group.add_argument(
"-t",
dest="time_limit",
default=5000,
metavar="msec",
type=lambda x: x if x == "none" else int(x),
help="timeout for each run (default: %(default)s)",
)
group.add_argument(
"-O",
dest="frida_mode",
action="store_true",
default=False,
help="use binary-only instrumentation (FRIDA mode)",
)
group.add_argument(
"-Q",
dest="qemu_mode",
action="store_true",
default=False,
help="use binary-only instrumentation (QEMU mode)",
)
group.add_argument(
"-U",
dest="unicorn_mode",
action="store_true",
default=False,
help="use unicorn-based instrumentation (Unicorn mode)",
)
group.add_argument(
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
)
group = parser.add_argument_group("Minimization settings")
group.add_argument(
"--crash-dir",
dest="crash_dir",
metavar="dir",
default=None,
help="move crashes to a separate dir, always deduplicated",
)
group.add_argument(
"-A",
dest="allow_any",
action="store_true",
help="allow crashes and timeouts (not recommended)",
)
group.add_argument(
"-C",
dest="crash_only",
action="store_true",
help="keep crashing inputs, reject everything else",
)
group.add_argument(
"-e",
dest="edge_mode",
action="store_true",
default=False,
help="solve for edge coverage only, ignore hit counts",
)
group = parser.add_argument_group("Misc")
group.add_argument(
"-T",
dest="workers",
type=lambda x: cpu_count if x == "all" else int(x),
default=1,
help="number of concurrent worker (default: %(default)d)",
)
group.add_argument(
"--as_queue",
action="store_true",
help='output file name like "id:000000,hash:value"',
)
group.add_argument(
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
)
group.add_argument("--debug", action="store_true")
parser.add_argument("exe", metavar="/path/to/target_app")
parser.add_argument("args", nargs="*")
args = parser.parse_args()
logger = None
afl_showmap_bin = None
tuple_index_type_code = "I"
file_index_type_code = None
def init():
global logger
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
if args.stdin_file and args.workers > 1:
logger.error("-f is only supported with one worker (-T 1)")
sys.exit(1)
if args.memory_limit != "none" and args.memory_limit < 5:
logger.error("dangerously low memory limit")
sys.exit(1)
if args.time_limit != "none" and args.time_limit < 10:
logger.error("dangerously low timeout")
sys.exit(1)
if not os.path.isfile(args.exe):
logger.error('binary "%s" not found or not regular file', args.exe)
sys.exit(1)
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
):
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
sys.exit(1)
for dn in args.input:
if not os.path.isdir(dn) and not glob.glob(dn):
logger.error('directory "%s" not found', dn)
sys.exit(1)
global afl_showmap_bin
searches = [
None,
os.path.dirname(__file__),
os.getcwd(),
]
if os.environ.get("AFL_PATH"):
searches.append(os.environ["AFL_PATH"])
for search in searches:
afl_showmap_bin = shutil.which("afl-showmap", path=search)
if afl_showmap_bin:
break
if not afl_showmap_bin:
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
sys.exit(1)
trace_dir = os.path.join(args.output, ".traces")
shutil.rmtree(trace_dir, ignore_errors=True)
try:
os.rmdir(args.output)
except OSError:
pass
if os.path.exists(args.output):
logger.error(
'directory "%s" exists and is not empty - delete it first', args.output
)
sys.exit(1)
if args.crash_dir and not os.path.exists(args.crash_dir):
os.makedirs(args.crash_dir)
os.makedirs(trace_dir)
logger.info("use %d workers (-T)", args.workers)
def detect_type_code(size):
for type_code in ["B", "H", "I", "L", "Q"]:
if 256 ** array.array(type_code).itemsize > size:
return type_code
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
assert input_path or batch
# yapf: disable
cmd = [
afl_showmap_bin,
'-m', str(args.memory_limit),
'-t', str(args.time_limit),
'-Z', # cmin mode
]
# yapf: enable
found_atat = False
for arg in args.args:
if "@@" in arg:
found_atat = True
if args.stdin_file:
assert args.workers == 1
input_from_file = True
stdin_file = args.stdin_file
cmd += ["-H", stdin_file]
elif found_atat:
input_from_file = True
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
cmd += ["-H", stdin_file]
else:
input_from_file = False
if batch:
input_from_file = True
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
with open(filelist, "w") as f:
for _, path in batch:
f.write(path + "\n")
cmd += ["-I", filelist]
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
cmd += ["-o", output_path]
else:
if input_from_file:
shutil.copy(input_path, stdin_file)
cmd += ["-o", "-"]
if args.frida_mode:
cmd += ["-O"]
if args.qemu_mode:
cmd += ["-Q"]
if args.unicorn_mode:
cmd += ["-U"]
if args.nyx_mode:
cmd += ["-X"]
if args.edge_mode:
cmd += ["-e"]
cmd += ["--", args.exe] + args.args
env = os.environ.copy()
env["AFL_QUIET"] = "1"
env["ASAN_OPTIONS"] = "detect_leaks=0"
if first:
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
env["AFL_CMIN_ALLOW_ANY"] = "1"
if afl_map_size:
env["AFL_MAP_SIZE"] = str(afl_map_size)
if args.crash_only:
env["AFL_CMIN_CRASHES_ONLY"] = "1"
if args.allow_any:
env["AFL_CMIN_ALLOW_ANY"] = "1"
if input_from_file:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
else:
p = subprocess.Popen(
cmd,
stdin=open(input_path, "rb"),
stdout=subprocess.PIPE,
env=env,
bufsize=1048576,
)
out = p.stdout.read()
p.wait()
if batch:
result = []
for idx, input_path in batch:
basename = os.path.basename(input_path)
values = []
try:
trace_file = os.path.join(output_path, basename)
with open(trace_file, "r") as f:
values = list(map(int, f))
crashed = len(values) == 0
os.unlink(trace_file)
except FileNotFoundError:
a = None
crashed = True
values = [(t // 1000) * 9 + t % 1000 for t in values]
a = array.array(tuple_index_type_code, values)
result.append((idx, a, crashed))
os.unlink(filelist)
os.rmdir(output_path)
return result
else:
values = []
for line in out.split():
if not line.isdigit():
continue
values.append(int(line))
values = [(t // 1000) * 9 + t % 1000 for t in values]
a = array.array(tuple_index_type_code, values)
crashed = p.returncode in [2, 3]
if input_from_file and stdin_file != args.stdin_file:
os.unlink(stdin_file)
return a, crashed
class JobDispatcher(multiprocessing.Process):
def __init__(self, job_queue, jobs):
super().__init__()
self.job_queue = job_queue
self.jobs = jobs
def run(self):
for job in self.jobs:
self.job_queue.put(job)
self.job_queue.close()
class Worker(multiprocessing.Process):
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
super().__init__()
self.idx = idx
self.afl_map_size = afl_map_size
self.q_in = q_in
self.p_out = p_out
self.r_out = r_out
def run(self):
map_size = self.afl_map_size or 65536
max_tuple = map_size * 9
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
counter = collections.Counter()
crashes = []
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
pack_pos = 0
with open(pack_name, "wb") as trace_pack:
while True:
batch = self.q_in.get()
if batch is None:
break
for idx, r, crash in afl_showmap(
batch=batch, afl_map_size=self.afl_map_size
):
counter.update(r)
used = False
if crash:
crashes.append(idx)
# If we aren't saving crashes to a separate dir, handle them
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
# afl_showmap will not return any coverage for crashes so they will
# never be retained.
if not crash or not args.crash_dir:
for t in r:
if idx < m[t]:
m[t] = idx
used = True
if used:
tuple_count = len(r)
r.tofile(trace_pack)
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
pack_pos += tuple_count * r.itemsize
else:
self.p_out.put(None)
self.r_out.put((self.idx, m, counter, crashes))
class CombineTraceWorker(multiprocessing.Process):
def __init__(self, pack_name, jobs, r_out):
super().__init__()
self.pack_name = pack_name
self.jobs = jobs
self.r_out = r_out
def run(self):
already_have = set()
with open(self.pack_name, "rb") as f:
for pos, tuple_count in self.jobs:
f.seek(pos)
result = array.array(tuple_index_type_code)
result.fromfile(f, tuple_count)
already_have.update(result)
self.r_out.put(already_have)
def hash_file(path):
m = hashlib.sha1()
with open(path, "rb") as f:
m.update(f.read())
return m.digest()
def dedup(files):
with multiprocessing.Pool(args.workers) as pool:
seen_hash = set()
result = []
hash_list = []
# use large chunksize to reduce multiprocessing overhead
chunksize = max(1, min(256, len(files) // args.workers))
for i, h in enumerate(
tqdm(
pool.imap(hash_file, files, chunksize),
desc="dedup",
total=len(files),
ncols=0,
leave=(len(files) > 100000),
)
):
if h in seen_hash:
continue
seen_hash.add(h)
result.append(files[i])
hash_list.append(h)
return result, hash_list
def is_afl_dir(dirnames, filenames):
return (
"queue" in dirnames
and "hangs" in dirnames
and "crashes" in dirnames
and "fuzzer_setup" in filenames
)
def collect_files(input_paths):
paths = []
for s in input_paths:
paths += glob.glob(s)
files = []
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
for path in paths:
for root, dirnames, filenames in os.walk(path, followlinks=True):
for dirname in dirnames:
if dirname.startswith("."):
dirnames.remove(dirname)
if not args.crash_only and is_afl_dir(dirnames, filenames):
continue
for filename in filenames:
if filename.startswith("."):
continue
pbar.update(1)
files.append(os.path.join(root, filename))
return files
def main():
init()
files = collect_files(args.input)
if len(files) == 0:
logger.error("no inputs in the target directory - nothing to be done")
sys.exit(1)
logger.info("Found %d input files in %d directories", len(files), len(args.input))
if not args.no_dedup:
files, hash_list = dedup(files)
logger.info("Remain %d files after dedup", len(files))
else:
logger.info("Skipping file deduplication.")
global file_index_type_code
file_index_type_code = detect_type_code(len(files))
logger.info("Sorting files.")
with multiprocessing.Pool(args.workers) as pool:
chunksize = max(1, min(512, len(files) // args.workers))
size_list = list(pool.map(os.path.getsize, files, chunksize))
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
files = [files[idx] for idx in idxes]
hash_list = [hash_list[idx] for idx in idxes]
afl_map_size = None
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
output = subprocess.run(
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
).stdout
afl_map_size = int(output)
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
global tuple_index_type_code
tuple_index_type_code = detect_type_code(afl_map_size * 9)
logger.info("Testing the target binary")
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
if tuples:
logger.info("ok, %d tuples recorded", len(tuples))
else:
logger.error("no instrumentation output detected")
sys.exit(1)
job_queue = multiprocessing.Queue()
progress_queue = multiprocessing.Queue()
result_queue = multiprocessing.Queue()
workers = []
for i in range(args.workers):
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
p.start()
workers.append(p)
chunk = max(1, min(128, len(files) // args.workers))
jobs = list(batched(enumerate(files), chunk))
jobs += [None] * args.workers # sentinel
dispatcher = JobDispatcher(job_queue, jobs)
dispatcher.start()
logger.info("Processing traces")
effective = 0
trace_info = {}
for _ in tqdm(files, ncols=0, smoothing=0.01):
r = progress_queue.get()
if r is not None:
idx, worker_idx, pos, tuple_count = r
trace_info[idx] = worker_idx, pos, tuple_count
effective += 1
dispatcher.join()
logger.info("Obtaining trace results")
ms = []
crashes = []
counter = collections.Counter()
for _ in tqdm(range(args.workers), ncols=0):
idx, m, c, crs = result_queue.get()
ms.append(m)
counter.update(c)
crashes.extend(crs)
workers[idx].join()
best_idxes = list(map(min, zip(*ms)))
if not args.crash_dir:
logger.info(
"Found %d unique tuples across %d files (%d effective)",
len(counter),
len(files),
effective,
)
else:
logger.info(
"Found %d unique tuples across %d files (%d effective, %d crashes)",
len(counter),
len(files),
effective,
len(crashes),
)
all_unique = counter.most_common()
logger.info("Processing candidates and writing output")
already_have = set()
count = 0
def save_file(idx):
input_path = files[idx]
fn = (
base64.b16encode(hash_list[idx]).decode("utf8").lower()
if not args.no_dedup
else os.path.basename(input_path)
)
if args.as_queue:
if args.no_dedup:
fn = "id:%06d,orig:%s" % (count, fn)
else:
fn = "id:%06d,hash:%s" % (count, fn)
output_path = os.path.join(args.output, fn)
try:
os.link(input_path, output_path)
except OSError:
shutil.copy(input_path, output_path)
jobs = [[] for i in range(args.workers)]
saved = set()
for t, c in all_unique:
if c != 1:
continue
idx = best_idxes[t]
if idx in saved:
continue
save_file(idx)
saved.add(idx)
count += 1
worker_idx, pos, tuple_count = trace_info[idx]
job = (pos, tuple_count)
jobs[worker_idx].append(job)
trace_packs = []
workers = []
for i in range(args.workers):
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
trace_f = open(pack_name, "rb")
trace_packs.append(trace_f)
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
p.start()
workers.append(p)
for _ in range(args.workers):
result = result_queue.get()
already_have.update(result)
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
if t in already_have:
continue
idx = best_idxes[t]
save_file(idx)
count += 1
worker_idx, pos, tuple_count = trace_info[idx]
trace_pack = trace_packs[worker_idx]
trace_pack.seek(pos)
result = array.array(tuple_index_type_code)
result.fromfile(trace_pack, tuple_count)
already_have.update(result)
for f in trace_packs:
f.close()
if args.crash_dir:
logger.info("Saving crashes to %s", args.crash_dir)
crash_files = [files[c] for c in crashes]
if args.no_dedup:
# Unless we deduped previously, we have to dedup the crash files
# now.
crash_files, hash_list = dedup(crash_files)
for idx, crash_path in enumerate(crash_files):
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
output_path = os.path.join(args.crash_dir, fn)
try:
os.link(crash_path, output_path)
except OSError:
try:
shutil.copy(crash_path, output_path)
except shutil.Error:
# This error happens when src and dest are hardlinks of the
# same file. We have nothing to do in this case, but handle
# it gracefully.
pass
if count == 1:
logger.warning("all test cases had the same traces, check syntax!")
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
if not os.environ.get("AFL_KEEP_TRACES"):
logger.info("Deleting trace files")
trace_dir = os.path.join(args.output, ".traces")
shutil.rmtree(trace_dir, ignore_errors=True)
if __name__ == "__main__":
main()

View File

@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
all: aflpp-standalone
aflpp-standalone: aflpp-standalone.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
$(CC) $(CFLAGS) -w -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
clean:
rm -f *.o *~ aflpp-standalone core

View File

@ -1,19 +1,20 @@
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-implicit-function-declaration
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
all: autotokens-standalone
autotokens.o: ../autotokens.cpp
$(CXX) $(CXXFLAGS) -I../../../include -I. -I../.. -c ../autotokens.cpp
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
autotokens-standalone: autotokens-standalone.c autotokens.o
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
$(CXX) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
$(CXX) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
@rm -f ../../../src/afl-common.o ../../../src/afl-fuzz-queue.o ../../../src/afl-fuzz-extras.o ../../../src/afl-performance.o
clean:
rm -f *.o *~ autotokens-standalone core

View File

@ -1,15 +1,28 @@
#include "afl-fuzz.h"
#include "afl-mutations.h"
#include "forkserver.h"
#include <unistd.h>
#include <getopt.h>
static int max_havoc = 16, verbose;
static unsigned char *dict, *mh = "16";
static char _mh[4] = "16";
static char *dict, *mh = _mh;
extern int module_disabled;
void *afl_custom_init(afl_state_t *, unsigned int);
u8 afl_custom_queue_get(void *data, const u8 *filename);
size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
u8 *add_buf, size_t add_buf_size, size_t max_size);
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
return 0;
}
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
u32 i) {
return FSRV_RUN_OK;
}
int main(int argc, char *argv[]) {
@ -144,7 +157,7 @@ int main(int argc, char *argv[]) {
if (dict) {
load_extras(afl, dict);
load_extras(afl, (u8*)dict);
if (verbose)
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
afl->extras_cnt);

View File

@ -3,6 +3,34 @@
This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual.
### Version ++4.33a (dev)
- afl-fuzz:
- Use `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT` if you use AFL_PRELOAD
to disable fork, see docs (thanks to @alexandredoyen29)
- Fix for FAST power schedules (introduced in 4.32c) (thanks to @kcwu)
- Colors for NO_UI output (thanks to @smoelius)
- Fix potential sync issues when resuming sessions and when instances in a
campaign are restarted and skip entries that were synced from itself
(thanks to @kcwu for raising the issues and providing support!)
- more 64 bit archicture support by @maribu
- afl-cc:
- Added instrumenting hidden edges (approx 5% edges were not instrumented,
LLVM sancov overall misses 8% of edges compared to our implementation)
Note that is is currently only implemented for our PCGUARD plugin, not
LTO, CLASSIC, etc.!
- Fix to make AFL_SAN_NO_INST work with gcc_plugin
- MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation)
- Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues
- qemuafl:
- Better MIPS persistent mode support
- afl-cmin:
- New afl-cmin.py which is much faster, will be executed by default via
afl-cmin if it executes successfully (thanks to @kcwu!)
- New desocketing library: utils/libaflppdesock
- Likely works when all other desocketing options fail
### Version ++4.32c (release)
- Fixed a bug where after a fast restart of a full fuzzed corpus afl-fuzz
terminates with "need at least one valid input seed that does not crash"
@ -22,7 +50,6 @@
- frida_mode:
- fixes for new MacOS + M4 hardware
### Version ++4.31c (release)
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
(thanks to @wtdcode !)

View File

@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
AFL++ is a superior fork to Google's AFL - more speed, more and better
mutations, more and better instrumentation, custom module support, etc.
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting
American Fuzzy Lop (AFL) was developed by Michal "lcamtuf" Zalewski starting
in 2013/2014, and when he left Google end of 2017 he stopped developing it.
At the end of 2019, the Google fuzzing team took over maintenance of AFL,
@ -284,14 +284,14 @@ If you find an interesting or important question missing, submit it via
afl-cc/afl-clang-fast/afl-clang-lto:
```
/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
clang-13: error: unable to execute command: No such file or directory
clang-13: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
/prg/tmp/llvm-project/build/bin/clang-18: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
clang-18: error: unable to execute command: No such file or directory
clang-18: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 18.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /prg/tmp/llvm-project/build/bin
clang-13: note: diagnostic msg:
clang-18: note: diagnostic msg:
********************
```

View File

@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
is to build and install everything:
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
whatever llvm version is available. We recommend llvm 13 or newer.
whatever llvm version is available. We recommend llvm 14 or newer.
```shell
sudo apt-get update

View File

@ -21,7 +21,7 @@ For a normal fuzzing workflow, we have:
For SAND fuzzing workflow, this is slightly different:
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
2. Build target project with AFL_USE_ASAN=1 AFL_SAN_NO_INST=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
2. Build target project with AFL_USE_ASAN=1 AFL_LLVM_ONLY_FSRV=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
Then you get:
@ -44,11 +44,11 @@ Just like the normal building process, except using `afl-clang-fast`
2. Build the sanitizers-enabled binaries.
```bash
AFL_SAN_NO_INST=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
AFL_SAN_NO_INST=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
AFL_LLVM_ONLY_FSRV=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
AFL_LLVM_ONLY_FSRV=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
```
Do note `AFL_SAN_NO_INST=1` is crucial, this enables forkservers but disables pc instrumentation. Do not reuse sanitizers-enabled binaries built _without_ `AFL_SAN_NO_INST=1`. This will mess up SAND execution pattern.
Do note `AFL_LLVM_ONLY_FSRV=1` is crucial, this enables forkservers but disables pc instrumentation. You are allowed to reuse sanitizers-enabled binaries, i.e. binaries built _without_ `AFL_LLVM_ONLY_FSRV=1`, at a cost of reduced speed.
3. Start fuzzing

View File

@ -111,6 +111,10 @@ fairly broad use of environment variables instead:
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
- `AFL_LLVM_ONLY_FSRV`/`AFL_GCC_ONLY_FSRV` will inject forkserver but not pc instrumentation. Please note this is different compared to `AFL_LLVM_DISABLE_INSTRUMENTATION`, which will totally disable forkserver implementation. This env is pretty useful in two cases:
- [SAND](./SAND.md). In this case, the binaries built in this way will serve as extra oracles. Check the corresponding documents for details.
- Compatible with LibAFL ForkserverExecutor implementation and thus faster to repeatedly run, compared to simple CommandExecutor.
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
the tool defaults to /tmp.
@ -664,6 +668,24 @@ checks or alter some of the more exotic semantics of the tool:
Note that will not be exact and with slow targets it can take seconds
until there is a slice for the time test.
- When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
the target, the forkserver becomes unable to fork.
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
permits to be able to check in the preloaded library if the environment
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
`fork()` in the forkserver, and the placeholder in the target.
Here is a POC :
```C
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
pid_t fork(void)
{
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
return 0; // We are in the target
else
return real_fork(); // We are in the forkserver
}
```
## 6) Settings for afl-qemu-trace
The QEMU wrapper used to instrument binary-only code supports several settings:

View File

@ -45,7 +45,7 @@ E. CmpLog is our enhanced
implementation, see
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
for all llvm versions and all our compile modes, only instrument what should
be instrumented, for more speed, directed fuzzing and less instability; see
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)

View File

@ -132,11 +132,15 @@ options are available:
locations. This technique is very fast and good - if the target does not
transform input data before comparison. Therefore, this technique is called
`input to state` or `redqueen`. If you want to use this technique, then you
have to compile the target twice, once specifically with/for this mode by
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
parameter. Note that you can compile also just a cmplog binary and use that
for both, however, there will be a performance penalty. You can read more
about this in
have to compile the target with `AFL_LLVM_CMPLOG=1`.
You could use the resulting binary for both normal fuzzing and `-c` CMPLOG
mode (with `-c 0`), however this will result in a performance loss of about
20%.
It is therefore better to compile a specific CMPLOG target with
`AFL_LLVM_ONLY_FSRV=1 AFL_LLVM_CMPLOG=1` and pass this binary name via
`-c cmplog-fuzzing-target` and compile target again normally with `afl-cc`
and use this is the fuzzing target as usual.
You can read more about this in
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
If you use LTO, LLVM, or GCC_PLUGIN mode
@ -865,10 +869,13 @@ Here are some of the most important caveats for AFL++:
- There is no direct support for fuzzing network services, background daemons,
or interactive apps that require UI interaction to work. You may need to make
simple code changes to make them behave in a more traditional way. Preeny or
libdesock may offer a relatively simple option, too - see:
simple code changes to make them behave in a more traditional way. Preeny,
libdesock or desockmulti may offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
If these fail then try our own which might be a bit slower but is more
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
Some useful tips for modifying network-based services can be also found at:
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)

View File

@ -15,6 +15,7 @@ JS_OBJ:=$(BUILD_DIR)api.o
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
XTOOLS_HOST?=x86_64-linux-gnu
TARGET_CC?=$(CC)
TARGET_CXX?=$(CXX)
HOST_CC?=$(CC)
@ -186,39 +187,13 @@ ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=16.1.11
GUM_DEVKIT_VERSION=17.0.7
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
ifeq ($(OS),macos)
# Extract the major version
GUM_VERSION_MAJOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/\..*//')
# Extract the minor version (assumes format "MAJOR.MINOR[.PATCH...]")
GUM_VERSION_MINOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/^[^.]*\.//; s/\..*//')
# Evaluate the version condition in a separate shell call
IS_GUM_16_6_PLUS := $(shell \
if (( $(GUM_VERSION_MAJOR) > 16 || ( $(GUM_VERSION_MAJOR) == 16 && $(GUM_VERSION_MINOR) >= 6 ) )); then \
echo 1; \
fi)
else
IS_GUM_16_6_PLUS := $(shell VERSION="$(GUM_DEVKIT_VERSION)"; \
MAJOR=$${VERSION%%.*}; \
MINOR=$${VERSION#*.}; MINOR=$${MINOR%%.*}; \
if [ $$MAJOR -gt 16 ] || { [ $$MAJOR -eq 16 ] && [ $$MINOR -ge 6 ]; }; then \
echo 1; \
fi)
endif
CFLAGS += $(if $(IS_GUM_16_6_PLUS),-DGUM_16_6_PLUS)
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
ifdef FRIDA_SOURCE
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
else
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
endif
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
FRIDA_DIR:=$(PWD)build/frida-source/
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
@ -252,13 +227,13 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
arm:
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
XTOOLS_HOST=arm-linux-gnueabihf CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
arm64:
ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
@ -271,114 +246,29 @@ $(OBJ_DIR): | $(BUILD_DIR)
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
mkdir -p $@
#TODO Set architecture
ifdef FRIDA_SOURCE
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
git clone https://github.com/frida/frida-gum.git $(FRIDA_DIR)
cd $(FRIDA_DIR) && \
./configure \
--host=$(XTOOLS_HOST) \
--enable-tests \
--enable-gumpp \
--enable-gumjs \
--with-devkits=gum,gumjs
.PHONY: $(GUM_DEVIT_LIBRARY)
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
echo "#include <stdio.h>" > $@
echo "#include <unistd.h>" >> $@
echo "#include <gum/gumreturnaddress.h>" >> $@
echo "#include <gum/gumbacktracer.h>" >> $@
echo "#include <gum/gumsymbolutil.h>" >> $@
echo "#include <gum/gumstalker.h>" >> $@
echo "#include <gum/gumlibc.h>" >> $@
echo "#include <gumjs/gumscriptbackend.h>" >> $@
ifeq "$(OS)" "macos"
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
else ifeq "$(ARCH)" "arm64"
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
echo $(GUM_DEVIT_LIBRARY) $(FRIDA_MAKEFILE) $(FRIDA_BUILD_DIR)
cd $(FRIDA_DIR) && make FRIDA_V8=disabled
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/frida-gumjs.h $(GUM_DEVIT_HEADER)
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/libfrida-gumjs.a $(GUM_DEVIT_LIBRARY)
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
endif
else
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
else
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)

View File

@ -27,7 +27,6 @@ void asan_init(void) {
}
#ifdef GUM_16_6_PLUS
static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
gchar *symbol_name = (gchar *)user_data;
@ -47,32 +46,6 @@ static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
}
#else
static gboolean asan_exclude_module(const GumModuleDetails *details,
gpointer user_data) {
gchar *symbol_name = (gchar *)user_data;
GumAddress address;
address = gum_module_find_export_by_name(details->name, symbol_name);
if (address == 0) { return TRUE; }
/* If the reported address of the symbol is outside of the range of the module
* then ignore it */
if (address < details->range->base_address) { return TRUE; }
if (address > (details->range->base_address + details->range->size)) {
return TRUE;
}
ranges_add_exclude((GumMemoryRange *)details->range);
return FALSE;
}
#endif
void asan_exclude_module_by_symbol(gchar *symbol_name) {
gum_process_enumerate_modules(asan_exclude_module, symbol_name);

View File

@ -382,5 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
Afl.jsApiWrite = new NativeFunction(
/* tslint:disable-next-line:no-null-keyword */
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);

View File

@ -39,7 +39,6 @@ typedef struct {
static guint64 text_base = 0;
static guint64 text_limit = 0;
#ifdef GUM_16_6_PLUS
static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
lib_details_t *lib_details = (lib_details_t *)user_data;
@ -57,24 +56,6 @@ static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
}
#else
static gboolean lib_find_exe(const GumModuleDetails *details,
gpointer user_data) {
lib_details_t *lib_details = (lib_details_t *)user_data;
strncpy(lib_details->name, details->name, PATH_MAX);
strncpy(lib_details->path, details->path, PATH_MAX);
lib_details->name[PATH_MAX] = '\0';
lib_details->path[PATH_MAX] = '\0';
lib_details->base_address = details->range->base_address;
lib_details->size = details->range->size;
return FALSE;
}
#endif
static void lib_validate_hdr(Elf_Ehdr *hdr) {
if (hdr->e_ident[0] != ELFMAG0) FFATAL("Invalid e_ident[0]");

View File

@ -12,7 +12,6 @@ extern void gum_darwin_enumerate_modules(mach_port_t task,
static guint64 text_base = 0;
static guint64 text_limit = 0;
#ifdef GUM_16_6_PLUS
static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
GumDarwinModule **ret = (GumDarwinModule **)user_data;
@ -30,25 +29,6 @@ static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
}
#else
static gboolean lib_get_main_module(const GumModuleDetails *details,
gpointer user_data) {
GumDarwinModule **ret = (GumDarwinModule **)user_data;
GumDarwinModule *module = gum_darwin_module_new_from_memory(
details->path, mach_task_self(), details->range->base_address,
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
FVERBOSE("Found main module: %s", module->name);
*ret = module;
return FALSE;
}
#endif
gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
gpointer user_data) {

View File

@ -46,6 +46,7 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
static int on_dlclose(void *handle) {
GArray *ranges = NULL;
GumModule *module = NULL;
struct link_map *lm = NULL;
gum_range_t *range = NULL;
GumAddress base;
@ -61,8 +62,12 @@ static int on_dlclose(void *handle) {
FVERBOSE("on_dlclose: %s", lm->l_name);
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
ranges);
module = gum_process_find_module_by_name(lm->l_name);
if (module == NULL) { FATAL("Failed to find module: %s", lm->l_name); }
gum_module_enumerate_ranges(module, GUM_PAGE_EXECUTE, found_range, ranges);
int ret = dlclose(handle);
if (ret != 0) {

View File

@ -263,13 +263,8 @@ static int prefetch_on_fork(void) {
static void prefetch_hook_fork(void) {
#ifdef GUM_16_6_PLUS
void *fork_addr =
GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
#else
void *fork_addr =
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
#endif
intercept_hook(fork_addr, prefetch_on_fork, NULL);
}

View File

@ -116,7 +116,6 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) {
}
#ifdef GUM_16_6_PLUS
static gboolean convert_name_token_for_module(GumModule *module,
gpointer user_data) {
@ -138,28 +137,6 @@ static gboolean convert_name_token_for_module(GumModule *module,
}
#else
static gboolean convert_name_token_for_module(const GumModuleDetails *details,
gpointer user_data) {
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
if (details->path == NULL) { return true; };
if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
FVERBOSE("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
"x-0x%016" G_GINT64_MODIFIER "x %s",
ctx->suffix, details->range->base_address,
details->range->base_address + details->range->size, details->path);
*ctx->range = *details->range;
ctx->done = true;
return false;
}
#endif
static void convert_name_token(gchar *token, GumMemoryRange *range) {
gchar *suffix = g_strconcat("/", token, NULL);

View File

@ -770,6 +770,7 @@ typedef struct afl_state {
#define FOREIGN_SYNCS_MAX 32U
u8 foreign_sync_cnt;
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
char *foreign_file;
#ifdef _AFL_DOCUMENT_MUTATIONS
u8 do_document;
@ -1139,6 +1140,7 @@ struct custom_mutator {
void afl_state_init(afl_state_t *, uint32_t map_size);
void afl_state_deinit(afl_state_t *);
void afl_resize_map_buffers(afl_state_t *, u32 old_size, u32 new_size);
/* Set stop_soon flag on all children, kill all children */
void afl_states_stop(void);
@ -1180,7 +1182,7 @@ u8 havoc_mutation_probability_py(void *);
u8 queue_get_py(void *, const u8 *);
const char *introspection_py(void *);
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
void splice_optout(void *);
void splice_optout_py(void *);
void deinit_py(void *);
#endif
@ -1215,7 +1217,6 @@ u8 *describe_op(afl_state_t *, u8, size_t);
#endif
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
u8 has_new_bits(afl_state_t *, u8 *);
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
#ifndef AFL_SHOWMAP
void classify_counts(afl_forkserver_t *);
#endif
@ -1258,6 +1259,7 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
/* Run */
void check_sync_fuzzers(afl_state_t *);
void sync_fuzzers(afl_state_t *);
u32 write_to_testcase(afl_state_t *, void **, u32, u32);
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
@ -1278,7 +1280,6 @@ u8 fuzz_one(afl_state_t *);
#ifdef HAVE_AFFINITY
void bind_to_free_cpu(afl_state_t *);
#endif
void setup_post(afl_state_t *);
void read_testcases(afl_state_t *, u8 *);
void perform_dry_run(afl_state_t *);
void pivot_inputs(afl_state_t *);

View File

@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++4.32c"
#define VERSION "++4.33a"
/******************************************************
* *
@ -171,8 +171,9 @@
#define EXEC_TM_ROUND 20U
/* 64bit arch MACRO */
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
(defined(__riscv) && __riscv_xlen == 64))
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
(defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \
defined(__s390x__) || defined(__loongarch64))
#define WORD_SIZE_64 1
#endif
@ -338,6 +339,10 @@
#define AVG_SMOOTHING 16
/* Max length of sync id (the id after -M and -S) */
#define SYNC_ID_MAX_LEN 50
/* Sync interval (every n havoc cycles): */
#define SYNC_INTERVAL 8
@ -423,9 +428,15 @@
#define SHM_ENV_VAR "__AFL_SHM_ID"
/* Environment variable used to pass SHM FUZZ ID to the called program. */
/* Environment variable used to pass shared memory fuzz map id
and the mapping size to the called program. */
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
#define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE"
/* Default size of the shared memory fuzz map.
We add 4 byte for one u32 length field. */
#define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4)
/* Other less interesting, internal-only variables. */

View File

@ -10,6 +10,7 @@ static char *afl_environment_deprecated[] = {
"AFL_DEFER_FORKSRV",
"AFL_POST_LIBRARY",
"AFL_PERSISTENT",
"AFL_SAN_NO_INST",
NULL
};
@ -118,7 +119,8 @@ static char *afl_environment_variables[] = {
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME",
"AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", NULL};
"AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV",
"AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", NULL};
extern char *afl_environment_variables[];

View File

@ -159,6 +159,8 @@ typedef struct afl_forkserver {
u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */
bool setenv; /* setenv() to discriminate the forkserver? */
bool debug; /* debug mode? */
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented?
@ -240,6 +242,7 @@ typedef enum fsrv_run_result {
void afl_fsrv_init(afl_forkserver_t *fsrv);
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0);
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output);
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,

View File

@ -2,18 +2,6 @@
american fuzzy lop++ - hashing function
---------------------------------------
The hash32() function is a variant of MurmurHash3, a good
non-cryptosafe hashing function developed by Austin Appleby.
For simplicity, this variant does *NOT* accept buffer lengths
that are not divisible by 8 bytes. The 32-bit version is otherwise
similar to the original; the 64-bit one is a custom hack with
mostly-unproven properties.
Austin's original code is public domain.
Other code written by Michal Zalewski
Copyright 2016 Google Inc. All rights reserved.
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
@ -33,82 +21,5 @@
u32 hash32(u8 *key, u32 len, u32 seed);
u64 hash64(u8 *key, u32 len, u64 seed);
#if 0
The following code is disabled because xxh3 is 30% faster
#ifdef __x86_64__
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
static inline u32 hash32(u8 *key, u32 len, u32 seed) {
const u64 *data = (u64 *)key;
u64 h1 = seed ^ len;
len >>= 3;
while (len--) {
u64 k1 = *data++;
k1 *= 0x87c37b91114253d5ULL;
k1 = ROL64(k1, 31);
k1 *= 0x4cf5ad432745937fULL;
h1 ^= k1;
h1 = ROL64(h1, 27);
h1 = h1 * 5 + 0x52dce729;
}
h1 ^= h1 >> 33;
h1 *= 0xff51afd7ed558ccdULL;
h1 ^= h1 >> 33;
h1 *= 0xc4ceb9fe1a85ec53ULL;
h1 ^= h1 >> 33;
return h1;
}
#else
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
static inline u32 hash32(const void *key, u32 len, u32 seed) {
const u32 *data = (u32 *)key;
u32 h1 = seed ^ len;
len >>= 2;
while (len--) {
u32 k1 = *data++;
k1 *= 0xcc9e2d51;
k1 = ROL32(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = ROL32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1;
}
#endif /* ^__x86_64__ */
#endif
#endif /* !_HAVE_HASH_H */

View File

@ -327,13 +327,13 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
};
if (!getenv("AFL_SAN_NO_INST")) {
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
} else {
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
return false;
}
@ -389,14 +389,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
};
if (!getenv("AFL_SAN_NO_INST")) {
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none();
} else {
if (debug) { DEBUGF("Instrument disabled\n"); }
if (debug) { DEBUGF("Instrumentation disabled\n"); }
}

View File

@ -13,6 +13,7 @@
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
// #include "llvm/IR/Verifier.h"
#if LLVM_VERSION_MAJOR >= 15
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
@ -76,9 +77,9 @@
#else
#include "llvm/Transforms/Utils/Instrumentation.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "config.h"
#include "debug.h"
@ -206,7 +207,8 @@ class ModuleSanitizerCoverageAFL
SanitizerCoverageOptions Options;
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0,
dump_cc = 0;
GlobalVariable *AFLMapPtr = NULL;
ConstantInt *One = NULL;
ConstantInt *Zero = NULL;
@ -272,14 +274,14 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
// TODO: Support LTO or llvm classic?
// Note we still need afl-compiler-rt so we just disable the instrumentation
// here.
if (!getenv("AFL_SAN_NO_INST")) {
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none();
} else {
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
}
@ -505,9 +507,16 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
getenv("AFL_USE_TSAN") ? ", TSAN" : "",
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
char buf[32] = "";
if (skippedbb) {
snprintf(buf, sizeof(buf), " %u instrumentations saved.", skippedbb);
}
OKF("Instrumented %u locations with no collisions (%s mode) of which are "
"%u handled and %u unhandled selects.",
instr, modeline, selects, unhandled);
"%u handled and %u unhandled special instructions.%s",
instr, modeline, selects + hidden, unhandled, buf);
}
@ -781,11 +790,14 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (AllBlocks.empty()) return false;
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0,
cnt_hidden_sel_inc = 0, skip_blocks = 0;
static uint32_t first = 1;
for (auto &BB : F) {
bool block_is_instrumented = false;
for (auto &IN : BB) {
CallInst *callInst = nullptr;
@ -799,11 +811,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (!FuncName.compare(StringRef("dlopen")) ||
!FuncName.compare(StringRef("_dlopen"))) {
fprintf(stderr,
"WARNING: dlopen() detected. To have coverage for a library "
"that your target dlopen()'s this must either happen before "
"__AFL_INIT() or you must use AFL_PRELOAD to preload all "
"dlopen()'ed libraries!\n");
WARNF(
"dlopen() detected. To have coverage for a library that your "
"target dlopen()'s this must either happen before __AFL_INIT() "
"or you must use AFL_PRELOAD to preload all dlopen()'ed "
"libraries!\n");
continue;
}
@ -811,53 +823,183 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
cnt_cov++;
block_is_instrumented = true;
}
}
SelectInst *selectInst = nullptr;
bool instrumentInst = false;
ICmpInst *icmp;
FCmpInst *fcmp;
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
Value *c = selectInst->getCondition();
auto t = c->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
// || isa<PHINode>(&IN)
cnt_sel++;
cnt_sel_inc += 2;
bool usedInBranch = false, usedInSelectDecision = false;
}
for (auto *U : IN.users()) {
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
if (isa<BranchInst>(U)) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
usedInBranch = true;
break;
cnt_sel++;
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
}
if (auto *sel = dyn_cast<SelectInst>(U)) {
if (icmp && sel->getCondition() == icmp) {
usedInSelectDecision = true;
} else if (fcmp && sel->getCondition() == fcmp) {
usedInSelectDecision = true;
}
}
}
if (!usedInBranch && !usedInSelectDecision) {
// errs() << "Instrument! " << *(&IN) << "\n";
instrumentInst = true;
}
}
if (instrumentInst) {
block_is_instrumented = true;
SelectInst *selectInst;
ICmpInst *icmp;
FCmpInst *fcmp;
// PHINode *phiInst;
// errs() << "IN: " << *(&IN) << "\n";
/* if ((phiInst = dyn_cast<PHINode>(&IN))) {
cnt_hidden_sel++;
cnt_hidden_sel_inc += phiInst->getNumIncomingValues();
} else*/
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
if (icmp->getType()->isIntegerTy(1)) {
cnt_sel++;
cnt_sel_inc += 2;
} else {
unhandled++;
}
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
if (fcmp->getType()->isIntegerTy(1)) {
cnt_sel++;
cnt_sel_inc += 2;
} else {
unhandled++;
}
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
Value *c = selectInst->getCondition();
auto t = c->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
cnt_sel++;
cnt_sel_inc += 2;
} else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
cnt_sel++;
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
}
} else {
if (!be_quiet) {
WARNF("unknown select ID type: %u\n", t->getTypeID());
}
}
} /*else {
cnt_hidden_sel++;
cnt_hidden_sel_inc += 2;
}*/
}
}
if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock() &&
llvm::is_contained(AllBlocks, &BB)) {
Instruction *instr = &*BB.begin();
LLVMContext &Ctx = BB.getContext();
MDNode *md = MDNode::get(Ctx, MDString::get(Ctx, "skipinstrument"));
instr->setMetadata("tag", md);
skip_blocks++;
}
}
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
uint32_t xtra = 0;
if (skip_blocks < first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc) {
xtra = first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc - skip_blocks;
}
CreateFunctionLocalArrays(F, AllBlocks, xtra);
if (!FunctionGuardArray) {
WARNF(
"SANCOV: FunctionGuardArray is NULL, failed to emit instrumentation.");
return false;
}
if (first) { first = 0; }
selects += cnt_sel;
hidden += cnt_hidden_sel;
uint32_t special = 0, local_selects = 0, skip_next = 0;
uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0;
// uint32_t skip_phi = 0;
for (auto &BB : F) {
// errs() << *(&BB) << "\n";
for (auto &IN : BB) {
// errs() << *(&IN) << "\n";
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
@ -875,15 +1017,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
IRBuilder<> IRB(callInst);
#endif
if (!FunctionGuardArray) {
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
}
Value *GuardPtr = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
@ -897,132 +1030,324 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
SelectInst *selectInst = nullptr;
bool instrumentInst = false;
ICmpInst *icmp;
FCmpInst *fcmp;
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
uint32_t vector_cnt = 0;
Value *condition = selectInst->getCondition();
Value *result;
auto t = condition->getType();
IRBuilder<> IRB(selectInst->getNextNode());
// || isa<PHINode>(&IN)
if (t->getTypeID() == llvm::Type::IntegerTyID) {
bool usedInBranch = false, usedInSelectDecision = false;
if (!FunctionGuardArray) {
for (auto *U : IN.users()) {
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
if (isa<BranchInst>(U)) {
usedInBranch = true;
break;
}
auto GuardPtr1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
if (auto *sel = dyn_cast<SelectInst>(U)) {
auto GuardPtr2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
if (icmp && sel->getCondition() == icmp) {
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
usedInSelectDecision = true;
break;
} else
} else if (fcmp && sel->getCondition() == fcmp) {
#if LLVM_VERSION_MAJOR >= 14
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
uint32_t elements = tt->getElementCount().getFixedValue();
vector_cnt = elements;
if (elements) {
FixedVectorType *GuardPtr1 =
FixedVectorType::get(Int32PtrTy, elements);
FixedVectorType *GuardPtr2 =
FixedVectorType::get(Int32PtrTy, elements);
Value *x, *y;
if (!FunctionGuardArray) {
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
}
Value *val1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
Value *val2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
for (uint64_t i = 1; i < elements; i++) {
val1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()) *
4)),
Int32PtrTy);
x = IRB.CreateInsertElement(x, val1, i);
val2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()) *
4)),
Int32PtrTy);
y = IRB.CreateInsertElement(y, val2, i);
}
result = IRB.CreateSelect(condition, x, y);
usedInSelectDecision = true;
break;
}
}
} else
}
if (!usedInBranch && !usedInSelectDecision) {
// errs() << "Instrument! " << *(&IN) << "\n";
instrumentInst = true;
}
}
if (instrumentInst) {
Value *result = nullptr;
uint32_t vector_cnt = 0;
SelectInst *selectInst;
// PHINode *phi = nullptr, *newPhi = nullptr;
IRBuilder<> IRB(IN.getNextNode());
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
if (!icmp->getType()->isIntegerTy(1)) { continue; }
if (skip_icmp) {
skip_icmp--;
continue;
}
if (debug) {
if (DILocation *Loc = IN.getDebugLoc()) {
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
<< Loc->getLine() << ":";
std::string path =
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
std::ifstream sourceFile(path);
std::string lineContent;
for (unsigned line = 1; line <= Loc->getLine(); ++line)
std::getline(sourceFile, lineContent);
llvm::errs() << lineContent << "\n";
}
errs() << *(&IN) << "\n";
}
auto res = icmp;
auto GuardPtr1 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
auto GuardPtr2 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
skip_select = 1;
// fprintf(stderr, "Icmp!\n");
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
if (!fcmp->getType()->isIntegerTy(1)) { continue; }
if (debug) {
if (DILocation *Loc = IN.getDebugLoc()) {
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
<< Loc->getLine() << ":";
std::string path =
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
std::ifstream sourceFile(path);
std::string lineContent;
for (unsigned line = 1; line <= Loc->getLine(); ++line)
std::getline(sourceFile, lineContent);
llvm::errs() << lineContent << "\n";
}
errs() << *(&IN) << "\n";
}
auto res = fcmp;
auto GuardPtr1 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
auto GuardPtr2 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
skip_select = 1;
// fprintf(stderr, "Fcmp!\n");
/*} else if ((phi = dyn_cast<PHINode>(&IN))) {
if (skip_phi) {
skip_phi = 0;
// errs() << "SKIP: " << *(&IN) << "\n";
continue;
}
// errs() << "-->PHI: " << *(&IN) << "\n";
// continue;
Instruction *insertBefore =
&*phi->getParent()->getFirstInsertionPt(); newPhi =
PHINode::Create(Int32PtrTy, 0, "", insertBefore); BasicBlock
*phiBlock = phi->getParent();
for (BasicBlock *pred : predecessors(phiBlock)) {
IRBuilder<> predBuilder(pred->getTerminator());
Value *ptr = predBuilder.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
ConstantInt::get(
IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()))); newPhi->addIncoming(ptr, pred);
}
result = newPhi;
skip_phi = 1;
// fprintf(stderr, "Phi!\n");
*/
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
if (skip_select) {
skip_select = 0;
continue;
} else {
// fprintf(stderr, "Select!\n");
}
Value *condition = selectInst->getCondition();
auto t = condition->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
auto GuardPtr1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
auto GuardPtr2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
skip_select = 1;
} else
#if LLVM_VERSION_MAJOR >= 14
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
uint32_t elements = tt->getElementCount().getFixedValue();
vector_cnt = elements;
if (elements) {
FixedVectorType *GuardPtr1 =
FixedVectorType::get(Int32PtrTy, elements);
FixedVectorType *GuardPtr2 =
FixedVectorType::get(Int32PtrTy, elements);
Value *x, *y;
Value *val1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()) *
4)),
Int32PtrTy);
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
Value *val2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()) *
4)),
Int32PtrTy);
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
for (uint64_t i = 1; i < elements; i++) {
val1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) *
4)),
Int32PtrTy);
x = IRB.CreateInsertElement(x, val1, i);
val2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) *
4)),
Int32PtrTy);
y = IRB.CreateInsertElement(y, val2, i);
}
result = IRB.CreateSelect(condition, x, y);
skip_select = 1;
}
}
} else
#endif
{
{
// fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID());
unhandled++;
continue;
if (!be_quiet) {
WARNF("Warning: Unhandled ID type: %u\n", t->getTypeID());
}
unhandled++;
continue;
}
}
uint32_t vector_cur = 0;
/* Load SHM pointer */
/*
if (newPhi) {
auto *inst = dyn_cast<Instruction>(result);
PHINode *nphi;
while ((nphi = dyn_cast<PHINode>(inst))) {
// fprintf(stderr, "NEXT!\n");
inst = inst->getNextNode();
}
IRB.SetInsertPoint(inst);
}
*/
LoadInst *MapPtr =
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
@ -1073,6 +1398,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
skip_icmp++;
}
@ -1094,13 +1420,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
skip_next = 1;
instr += vector_cnt;
} else {
skip_next = 0;
}
}
@ -1109,9 +1430,40 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (AllBlocks.empty() && !special && !local_selects) return false;
if (!AllBlocks.empty())
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
uint32_t skipped = 0;
if (!AllBlocks.empty()) {
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
auto instr = AllBlocks[i]->begin();
if (instr->getMetadata("skipinstrument")) {
skipped++;
// fprintf(stderr, "Skipped!\n");
} else {
InjectCoverageAtBlock(F, *AllBlocks[i], i - skipped, IsLeafFunc);
}
}
}
skippedbb += skipped;
/*
if (verifyFunction(F, &errs())) {
errs() << "Broken function after instrumentation\n";
F.print(errs(), nullptr);
report_fatal_error("Invalid IR");
}
*/
return true;

View File

@ -119,6 +119,8 @@ u64 __afl_map_addr;
u32 __afl_first_final_loc;
u32 __afl_old_forkserver;
u8 __afl_forkserver_setenv = 0;
#ifdef __AFL_CODE_COVERAGE
typedef struct afl_module_info_t afl_module_info_t;
@ -292,6 +294,25 @@ static void __afl_map_shm_fuzz() {
u8 *map = NULL;
#ifdef USEMMAP
// Newer afl-fuzz versions will set a shm_fuzz page size env, else fall back
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
char *map_size_env = getenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
if (map_size_env != NULL) {
char *endptr;
errno = 0;
shm_fuzz_map_size = (size_t)strtoul(map_size_env, &endptr, 10);
if (errno != 0 || shm_fuzz_map_size == 0) {
perror("shm_fuzz mapping size parsing");
send_forkserver_error(FS_ERROR_SHM_OPEN);
_exit(1);
}
}
const char *shm_file_path = id_str;
int shm_fd = -1;
@ -305,8 +326,7 @@ static void __afl_map_shm_fuzz() {
}
map =
(u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
map = (u8 *)mmap(0, shm_fuzz_map_size, PROT_READ, MAP_SHARED, shm_fd, 0);
#else
u32 shm_id = atoi(id_str);
@ -362,6 +382,7 @@ static void __afl_map_shm(void) {
if (getenv("AFL_DUMP_MAP_SIZE")) {
printf("%u\n", __afl_map_size);
fflush(stdout);
exit(-1);
}
@ -888,6 +909,12 @@ static void __afl_start_forkserver(void) {
}
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
__afl_forkserver_setenv = 1;
}
/* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */
@ -913,7 +940,12 @@ static void __afl_start_forkserver(void) {
}
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
if (write(FORKSRV_FD + 1, msg, 4) != 4) {
errno = 0;
_exit(1);
}
// Now send the parameters for the set options, increasing by option number
@ -1054,6 +1086,13 @@ static void __afl_start_forkserver(void) {
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
if (unlikely(__afl_forkserver_setenv)) {
unsetenv("AFL_FORKSERVER_PARENT");
}
return;
}
@ -1226,6 +1265,15 @@ void __afl_manual_init(void) {
}
if (getenv("AFL_LLVM_ONLY_FSRV") || getenv("AFL_GCC_ONLY_FRSV")) {
fprintf(stderr,
"DEBUG: Overwrite area_ptr to dummy due to "
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FRSV\n");
__afl_area_ptr = __afl_area_ptr_dummy;
}
if (!init_done) {
__afl_start_forkserver();

View File

@ -462,6 +462,7 @@ static struct plugin_info afl_plugin = {
.help = G_("AFL gcc plugin\n\
\n\
Set AFL_QUIET in the environment to silence it.\n\
Set AFL_GCC_ONLY_FRSV in the environment to disable instrumentation.\n\
\n\
Set AFL_INST_RATIO in the environment to a number from 0 to 100\n\
to control how likely a block will be chosen for instrumentation.\n\
@ -502,9 +503,10 @@ int plugin_init(struct plugin_name_args *info,
case it was specified in the command line's -frandom-seed for
reproducible instrumentation. */
srandom(get_random_seed(false));
bool fsrv_only = !!getenv("AFL_GCC_ONLY_FRSV");
const char *name = info->base_name;
register_callback(name, PLUGIN_INFO, NULL, &afl_plugin);
if (!fsrv_only) { register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); }
afl_pass *aflp = new afl_pass(quiet, inst_ratio);
struct register_pass_info pass_info = {
@ -516,14 +518,20 @@ int plugin_init(struct plugin_name_args *info,
};
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
pass_info.pass);
if (!fsrv_only) {
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
pass_info.pass);
}
if (!quiet)
ACTF(G_("%s instrumentation at ratio of %u%% in %s mode."),
aflp->out_of_line ? G_("Call-based") : G_("Inline"), inst_ratio,
getenv("AFL_HARDEN") ? G_("hardened") : G_("non-hardened"));
else if (fsrv_only)
ACTF("Instrumentation disabled due to AFL_GCC_ONLY_FRSV");
return 0;

View File

@ -225,17 +225,17 @@ bool AFLCoverage::runOnModule(Module &M) {
if (getenv("AFL_DEBUG")) debug = 1;
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
if (getenv("AFL_SAN_NO_INST")) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
return PreservedAnalyses::all();
}
#else
if (getenv("AFL_SAN_NO_INST")) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
return true;
}

View File

@ -64,6 +64,8 @@ using namespace llvm;
namespace {
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
#if LLVM_MAJOR >= 11 /* use new pass manager */
class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
@ -92,6 +94,8 @@ class CmpLogInstructions : public ModulePass {
#else
bool runOnModule(Module &M) override;
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT);
#if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override {
@ -106,7 +110,7 @@ class CmpLogInstructions : public ModulePass {
#endif
private:
bool hookInstrs(Module &M);
bool hookInstrs(Module &M, DomTreeCallback DTCallback);
};
@ -158,7 +162,16 @@ Iterator Unique(Iterator first, Iterator last) {
}
bool CmpLogInstructions::hookInstrs(Module &M) {
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
if (DT->dominates(To, From)) return true;
if (auto Next = To->getUniqueSuccessor())
if (DT->dominates(Next, From)) return true;
return false;
}
bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
std::vector<Instruction *> icomps;
LLVMContext &C = M.getContext();
@ -296,6 +309,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
for (auto &F : M) {
if (!isInInstrumentList(&F, MNAME)) continue;
const DominatorTree *DT = DTCallback(F);
for (auto &BB : F) {
@ -304,6 +318,12 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
CmpInst *selectcmpInst = nullptr;
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
// skip loop comparisons
if (selectcmpInst->hasOneUse())
if (auto BR = dyn_cast<BranchInst>(selectcmpInst->user_back()))
for (BasicBlock *B : BR->successors())
if (IsBackEdge(BR->getParent(), B, DT)) continue;
icomps.push_back(selectcmpInst);
}
@ -681,11 +701,19 @@ bool CmpLogInstructions::runOnModule(Module &M) {
#endif
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
return &FAM.getResult<DominatorTreeAnalysis>(F);
};
if (getenv("AFL_QUIET") == NULL)
printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n");
else
be_quiet = 1;
bool ret = hookInstrs(M);
bool ret = hookInstrs(M, DTCallback);
verifyModule(M);
#if LLVM_MAJOR >= 11 /* use new pass manager */

View File

@ -1 +1 @@
ef1cd9a8cb
c43dd6e036

View File

@ -75,7 +75,6 @@ static bool edges_only, /* Ignore hit counts? */
static volatile u8 stop_soon; /* Ctrl-C pressed? */
static u8 *target_path;
static u8 frida_mode;
static u8 qemu_mode;
static u8 cs_mode;
static u32 map_size = MAP_SIZE;
@ -628,9 +627,7 @@ static void handle_stop_sig(int sig) {
static void set_up_environment(char **argv) {
u8 *x;
char *afl_preload;
char *frida_afl_preload = NULL;
u8 *x;
fsrv.dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@ -672,57 +669,7 @@ static void set_up_environment(char **argv) {
}
set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
if (qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
#endif
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
#endif
}
} else if (frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
#endif
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
afl_fsrv_setup_preload(&fsrv, argv[0]);
}
@ -936,10 +883,9 @@ int main(int argc, char **argv_orig, char **envp) {
case 'O': /* FRIDA mode */
if (frida_mode) { FATAL("Multiple -O options not supported"); }
if (fsrv.frida_mode) { FATAL("Multiple -O options not supported"); }
frida_mode = 1;
fsrv.frida_mode = frida_mode;
fsrv.frida_mode = true;
setenv("AFL_FRIDA_INST_SEED", "1", 1);
break;

View File

@ -244,7 +244,7 @@ static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
/* Insert params into the new argv, make clang load the pass. */
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
if (getenv("AFL_SAN_NO_INST")) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
@ -2097,7 +2097,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
* anyway.
*/
if (aflcc->have_rust_asanrt) { return; }
if (getenv("AFL_SAN_NO_INST")) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
@ -2138,7 +2138,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
*/
void add_optimized_pcguard(aflcc_state_t *aflcc) {
if (getenv("AFL_SAN_NO_INST")) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
@ -2600,6 +2600,13 @@ void add_assembler(aflcc_state_t *aflcc) {
/* Add params to launch the gcc plugins for instrumentation. */
void add_gcc_plugin(aflcc_state_t *aflcc) {
if (getenv("AFL_GCC_ONLY_FSRV")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
}
if (aflcc->cmplog_mode) {
insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);

View File

@ -179,7 +179,7 @@ u32 check_binary_signatures(u8 *fn) {
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
close(fd);
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
setenv(PERSIST_ENV_VAR, "1", 1);
@ -204,7 +204,7 @@ u32 check_binary_signatures(u8 *fn) {
}
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
setenv(DEFER_ENV_VAR, "1", 1);
@ -819,7 +819,21 @@ void check_environment_vars(char **envp) {
WARNF("AFL environment variable %s is deprecated!",
afl_environment_deprecated[i]);
issue_detected = 1;
if (strncmp(afl_environment_deprecated[i], "AFL_SAN_NO_INST",
strlen(afl_environment_deprecated[i])) == 0) {
WARNF(
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FSRV is induced and set "
"instead.");
setenv("AFL_GCC_ONLY_FSRV", "1", 0);
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
} else {
issue_detected = 1;
}
} else {

View File

@ -140,7 +140,7 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
plugin->nyx_config_free = dlsym(handle, "nyx_config_free");
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
if (plugin->nyx_config_free == NULL) { goto fail; }
OKF("libnyx plugin is ready!");
return plugin;
@ -250,6 +250,16 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->child_kill_signal = SIGKILL;
fsrv->max_length = MAX_FILE;
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
fsrv->setenv = 1;
} else {
fsrv->setenv = 0;
}
/* exec related stuff */
fsrv->child_pid = -1;
fsrv->map_size = get_map_size();
@ -310,6 +320,38 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
}
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
if (fsrv->qemu_mode) return;
u8 *afl_preload = getenv("AFL_PRELOAD");
u8 *preload_path = NULL;
u8 *frida_binary = NULL;
if (fsrv->frida_mode)
frida_binary = find_afl_binary(argv0, "afl-frida-trace.so");
if (afl_preload && frida_binary)
preload_path = alloc_printf("%s:%s", afl_preload, frida_binary);
else if (afl_preload)
preload_path = ck_strdup(afl_preload);
else if (frida_binary)
preload_path = ck_strdup(frida_binary);
ck_free(frida_binary);
if (preload_path) {
setenv("LD_PRELOAD", preload_path, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", preload_path, 1);
#endif
ck_free(preload_path);
}
}
/* 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;
@ -878,6 +920,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* CHILD PROCESS */
if (unlikely(fsrv->setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); }
// enable terminating on sigpipe in the children
struct sigaction sa;
memset((char *)&sa, 0, sizeof(sa));

View File

@ -255,7 +255,8 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
* on rare cases it fall backs to the slow path: classify_counts() first, then
* return has_new_bits(). */
inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
bool *classified) {
/* Handle the hot path first: no new coverage */
u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size;
@ -272,6 +273,7 @@ inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
#endif /* ^WORD_SIZE_64 */
classify_counts(&afl->fsrv);
*classified = true;
return has_new_bits(afl, virgin_map);
}
@ -317,7 +319,15 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
if (unlikely(afl->syncing_party)) {
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
if (unlikely(afl->foreign_file)) {
sprintf(ret, "sync:%s,src:%.20s", afl->syncing_party, afl->foreign_file);
} else {
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
}
} else {
@ -462,6 +472,46 @@ void write_crash_readme(afl_state_t *afl) {
}
static inline void classify_if_necessary(afl_state_t *afl, bool *classified) {
if (*classified) return;
classify_counts(&afl->fsrv);
*classified = true;
}
static inline void calculate_cksum_if_necessary(afl_state_t *afl, u64 *cksum,
bool *cksumed,
bool *classified) {
if (*cksumed) return;
classify_if_necessary(afl, classified);
*cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
*cksumed = true;
}
static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
u8 *new_bits,
bool *bits_counted,
bool *classified) {
if (*bits_counted) return;
if (*classified) {
*new_bits = has_new_bits(afl, afl->virgin_bits);
} else {
*new_bits = has_new_bits_unclassified(afl, afl->virgin_bits, classified);
}
*bits_counted = true;
}
/* Check if the result of an execve() during routine fuzzing is interesting,
save or queue the input test case for further analysis if so. Returns 1 if
entry is saved, 0 otherwise. */
@ -469,8 +519,6 @@ void write_crash_readme(afl_state_t *afl) {
u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
u32 len, u8 fault) {
u8 classified = 0;
if (unlikely(len == 0)) { return 0; }
if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
@ -479,7 +527,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
classify_counts(&afl->fsrv);
u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
classified = 1;
// Saturated increment
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
@ -493,13 +540,14 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
u8 fn[PATH_MAX];
u8 *queue_fn = "";
u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1;
u8 keeping = 0, res, is_timeout = 0;
u8 san_fault = 0, san_idx = 0, feed_san = 0;
s32 fd;
u64 cksum = 0;
u32 cksum_simplified = 0, cksum_unique = 0;
u8 san_fault = 0;
u8 san_idx = 0;
u8 feed_san = 0;
bool classified = false, bits_counted = false, cksumed = false;
u8 new_bits = 0; /* valid if bits_counted is true */
u64 cksum = 0; /* valid if cksumed is true */
afl->san_case_status = 0;
@ -509,10 +557,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
only be used for special schedules */
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
classify_counts(&afl->fsrv);
need_hash = 0;
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
/* Saturated increment */
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
@ -547,7 +592,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
unlikely(afl->san_abstraction == COVERAGE_INCREASE)) {
/* Check if the input increase the coverage */
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted,
&classified);
if (unlikely(new_bits)) { feed_san = 1; }
@ -556,15 +602,9 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
if (unlikely(afl->san_binary_length) &&
likely(afl->san_abstraction == UNIQUE_TRACE)) {
// If schedule is not FAST..RARE, we need to classify counts here
// Note: SAND was evaluated under FAST schedule but should also work
// with other scedules.
if (!classified) {
classify_counts(&afl->fsrv);
classified = 1;
}
classify_if_necessary(afl, &classified);
cksum_unique =
hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@ -624,22 +664,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
/* Keep only if there are new bits in the map, add to queue for
future fuzzing, etc. */
if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) {
/* If we are in coverage increasing abstraction and have fed input to
sanitizers, we are sure it has new bits.*/
if (classified) {
/* We could have classified the bits in SAND with UNIQUE_TRACE */
new_bits = has_new_bits(afl, afl->virgin_bits);
} else {
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
}
}
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
if (likely(!new_bits)) {
@ -662,6 +687,11 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
save_to_queue:
/* these calculations are necessary because some code flow may jump here via
goto */
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
#ifndef SIMPLE_FILES
if (!afl->afl_env.afl_sha1_filenames) {
@ -743,6 +773,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
#endif
afl->queue_top->exec_cksum = cksum;
if (new_bits == 2) {
afl->queue_top->has_new_cov = 1;
@ -750,17 +782,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
}
if (unlikely(need_hash && new_bits)) {
/* due to classify counts we have to recalculate the checksum */
afl->queue_top->exec_cksum =
hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
need_hash = 0;
}
/* For AFLFast schedules we update the new queue entry */
if (likely(cksum)) {
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
@ -859,7 +882,9 @@ may_save_fault:
}
new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
classify_counts(&afl->fsrv);
classified = false;
bits_counted = false;
cksumed = false;
/* A corner case that one user reported bumping into: increasing the
timeout actually uncovers a crash. Make sure we don't discard it if

View File

@ -589,8 +589,6 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
u8 *fn2 =
alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
free(nl[i]); /* not tracked */
if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
if (first) PFATAL("Unable to access '%s'", fn2);
@ -653,17 +651,14 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
afl->syncing_party = foreign_name;
afl->foreign_file = nl[i]->d_name;
afl->queued_imported += save_if_interesting(afl, mem, len, fault);
afl->syncing_party = 0;
munmap(mem, st.st_size);
close(fd);
if (st.st_mtime > mtime_max) {
mtime_max = st.st_mtime;
show_stats(afl);
}
if (st.st_mtime > mtime_max) { mtime_max = st.st_mtime; }
show_stats(afl);
}
@ -673,12 +668,21 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
}
for (i = 0; i < (u32)nl_cnt; ++i) {
free(nl[i]); /* not tracked */
}
free(nl); /* not tracked */
}
}
afl->foreign_file = NULL;
afl->syncing_party = 0;
if (first) {
afl->last_find_time = 0;
@ -756,21 +760,10 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
if (nl_cnt) {
u32 done = 0;
if (unlikely(afl->in_place_resume)) {
i = nl_cnt;
} else {
i = 0;
}
i = 0;
do {
if (unlikely(afl->in_place_resume)) { --i; }
struct stat st;
u8 dfn[PATH_MAX];
snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
@ -850,22 +843,12 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
next_entry:
if (unlikely(afl->in_place_resume)) {
if (unlikely(i == 0)) { done = 1; }
} else {
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
}
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
} while (!done);
}
// if (getenv("MYTEST")) afl->in_place_resume = 0;
free(nl); /* not tracked */
if (!afl->queued_items && directory == NULL) {
@ -909,9 +892,21 @@ void perform_dry_run(afl_state_t *afl) {
struct queue_entry *q;
u32 cal_failures = 0, idx;
u8 *use_mem;
u8 *use_mem, done = 0;
for (idx = 0; idx < afl->queued_items; idx++) {
if (afl->in_place_resume) {
idx = afl->queued_items;
} else {
idx = 0;
}
do {
if (afl->in_place_resume) { --idx; }
q = afl->queue_buf[idx];
if (unlikely(!q || q->disabled)) { continue; }
@ -1378,7 +1373,17 @@ void perform_dry_run(afl_state_t *afl) {
}
}
if (!afl->in_place_resume) {
if (++idx >= afl->queued_items) { done = 1; }
} else {
if (idx == 0) { done = 1; }
}
} while (!done);
if (cal_failures) {
@ -1407,67 +1412,51 @@ void perform_dry_run(afl_state_t *afl) {
q = afl->queue_buf[idx];
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
u32 done = 0;
for (i = idx + 1;
likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) {
for (i = idx + 1; likely(i < afl->queued_items && afl->queue_buf[i]); ++i) {
struct queue_entry *p = afl->queue_buf[i];
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
if (p->exec_cksum != q->exec_cksum) continue;
if (p->exec_cksum == q->exec_cksum) {
duplicates = 1;
duplicates = 1;
// we keep the shorter file
struct queue_entry *to_disable, *to_keep;
if (p->len >= q->len) {
// we keep the shorter file
if (p->len >= q->len) {
to_disable = p;
to_keep = q;
if (!p->was_fuzzed) {
} else {
p->was_fuzzed = 1;
afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
p->disabled = 1;
p->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
q->fname, p->fname);
}
} else {
if (!q->was_fuzzed) {
q->was_fuzzed = 1;
afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
q->disabled = 1;
q->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
p->fname, q->fname);
}
done = 1; // end inner loop because outer loop entry is disabled now
}
to_disable = q;
to_keep = p;
}
if (!to_disable->was_fuzzed) {
to_disable->was_fuzzed = 1;
afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
to_disable->disabled = 1;
to_disable->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
to_keep->fname, to_disable->fname);
}
// end inner loop because outer loop entry is disabled now
if (to_disable == q) break;
}
}
@ -1557,8 +1546,9 @@ void pivot_inputs(afl_state_t *afl) {
ID matches the one we'd assign, just use the original file name.
This is valuable for resuming fuzzing runs. */
if (!strncmp(rsl, CASE_PREFIX, 3) &&
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
if (afl->in_place_resume ||
(!strncmp(rsl, CASE_PREFIX, 3) &&
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id)) {
u8 *src_str;
u32 src_id;
@ -2801,9 +2791,9 @@ void fix_up_sync(afl_state_t *afl) {
}
if (strlen(afl->sync_id) > 50) {
if (strlen(afl->sync_id) > SYNC_ID_MAX_LEN) {
FATAL("sync_id max length is 50 characters");
FATAL("sync_id max length is %d characters", SYNC_ID_MAX_LEN);
}
@ -2911,11 +2901,16 @@ 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);
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 1);
afl->shm_fuzz->shmemfuzz_mode = 1;
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
ck_free(shm_fuzz_map_size_str);
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
#else
@ -3116,7 +3111,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
!afl->fsrv.nyx_mode &&
#endif
!afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
SAYF("\n" cLRD "[-] " cRST
"Looks like the target binary is not instrumented! The fuzzer depends "
@ -3147,7 +3142,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
SAYF("\n" cLRD "[-] " cRST
"This program appears to be instrumented with AFL++ compilers, but is "
@ -3182,7 +3177,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
/* Detect persistent & deferred init signatures in the binary. */
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
OKF(cPIN "Persistent mode binary detected.");
setenv(PERSIST_ENV_VAR, "1", 1);
@ -3209,7 +3204,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if (afl->fsrv.frida_mode ||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
OKF(cPIN "Deferred forkserver binary detected.");
setenv(DEFER_ENV_VAR, "1", 1);

View File

@ -411,11 +411,12 @@ u8 fuzz_one_original(afl_state_t *afl) {
u_simplestring_time_diff(time_tmp, afl->prev_run_time + get_cur_time(),
afl->start_time);
ACTF(
"Fuzzing test case #%u (%u total, %llu crashes saved, state: %s, "
"Fuzzing test case #%u (%u total, %s%llu crashes saved%s, state: %s, "
"mode=%s, "
"perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
"exec_us=%llu, hits=%u, map=%u, ascii=%u, run_time=%s)...",
afl->current_entry, afl->queued_items, afl->saved_crashes,
afl->current_entry, afl->queued_items,
afl->saved_crashes != 0 ? cRED : "", afl->saved_crashes, cRST,
get_fuzzing_state(afl), afl->fuzz_mode ? "exploit" : "explore",
afl->queue_cur->perf_score, afl->queue_cur->weight,
afl->queue_cur->favored, afl->queue_cur->was_fuzzed,

View File

@ -26,8 +26,10 @@
#include "afl-fuzz.h"
#include <sys/time.h>
#include <sys/stat.h>
#include <signal.h>
#include <limits.h>
#include <glob.h>
#if !defined NAME_MAX
#define NAME_MAX _XOPEN_NAME_MAX
#endif
@ -493,36 +495,41 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
afl->afl_env.afl_post_process_keep_original = 1;
/* we need a dummy run if this is LTO + cmplog */
if (unlikely(afl->shm.cmplog_mode)) {
/*
if (unlikely(afl->shm.cmplog_mode)) {
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
we want to bail out quickly. */
// afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
// we want to bail out quickly.
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration;
if (!afl->non_instrumented_mode && !afl->stage_cur &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
}
fault = FSRV_RUN_NOINST;
goto abort_calibration;
if (!afl->non_instrumented_mode &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
fault = FSRV_RUN_NOINST;
goto abort_calibration;
}
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
#endif
}
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
#endif
}
*/
if (q->exec_cksum) {
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
hnb = has_new_bits(afl, afl->virgin_bits);
if (hnb > new_bits) { new_bits = hnb; }
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
}
@ -551,7 +558,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->non_instrumented_mode && !afl->stage_cur &&
if (!afl->non_instrumented_mode &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
fault = FSRV_RUN_NOINST;
@ -560,17 +567,19 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
}
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
#endif
classify_counts(&afl->fsrv);
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
if (q->exec_cksum != cksum) {
if (unlikely(q->exec_cksum != cksum)) {
hnb = has_new_bits(afl, afl->virgin_bits);
if (hnb > new_bits) { new_bits = hnb; }
if (q->exec_cksum) {
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
if (likely(q->exec_cksum)) {
u32 i;
@ -697,6 +706,110 @@ abort_calibration:
}
/* Do not sync items that were synced from us */
static bool is_known_case(afl_state_t *afl, u8 *name) {
static char coming_from_me_str[SYNC_ID_MAX_LEN + 2];
static u32 coming_from_me_len = 0;
static u32 min_len = 15 + 4 + 6;
if (!coming_from_me_len) {
snprintf(coming_from_me_str, sizeof(coming_from_me_str), "%s,",
afl->sync_id);
min_len += coming_from_me_len = strlen(coming_from_me_str);
}
// file name length long enough so it can be ours
if (unlikely(strlen(name) < min_len)) { return false; }
// is it based on a sync? allow optimizer to make an integer comparison
if (likely(memcmp(name + 10, "sync", 4) != 0)) { return false; }
// we jump over the ':' after 'sync' and compare to our sync name
if (unlikely(memcmp(name + 15, coming_from_me_str, coming_from_me_len) !=
0)) {
return false;
}
/* We do not need this as we now look on startup how many files are in sync
targets.
int src_id = atoi(name + 15 + coming_from_me_len + 4);
if (unlikely(src_id >= afl->queued_items)) return false;
*/
// yes it is highly likely a current testcase we already know
return true;
}
/* Write into .sync/INSTANCE.max how many queue files were there on startup */
void check_sync_fuzzers(afl_state_t *afl) {
if (unlikely(afl->afl_env.afl_no_sync)) { return; }
DIR *sd, *dir;
struct dirent *sd_ent, *entry;
u8 qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
sd = opendir(afl->sync_dir);
if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
u64 sync_start_us = get_cur_time_us();
// Look at the entries created for every other fuzzer in the sync directory.
while ((sd_ent = readdir(sd))) {
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
continue;
}
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
dir = opendir(qd_path);
if (dir) {
u32 max_start_id = 0;
while ((entry = readdir(dir)) != NULL) {
max_start_id++;
}
if (max_start_id > 4) {
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir,
sd_ent->d_name);
s32 max_fd = open(qd_synced_maxid, O_WRONLY | O_CREAT | O_TRUNC,
DEFAULT_PERMISSION);
if (max_fd >= 0) {
max_start_id -= 4; // without ".", "..", ".state" and counting from 0
write(max_fd, &max_start_id, sizeof(u32));
close(max_fd);
}
}
}
closedir(dir);
}
closedir(sd);
update_sync_time(afl, &sync_start_us);
}
/* Grab interesting test cases from other fuzzers. */
void sync_fuzzers(afl_state_t *afl) {
@ -715,8 +828,7 @@ void sync_fuzzers(afl_state_t *afl) {
afl->cur_depth = 0;
u64 sync_start_us = get_cur_time_us();
/* Look at the entries created for every other fuzzer in the sync directory.
*/
// Look at the entries created for every other fuzzer in the sync directory.
while ((sd_ent = readdir(sd))) {
@ -724,12 +836,11 @@ void sync_fuzzers(afl_state_t *afl) {
// iteration
update_sync_time(afl, &sync_start_us);
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
u32 min_accept = 0, next_min_accept = 0;
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
u32 min_accept = 0, next_min_accept = 0, max_start_id = 0;
s32 id_fd;
/* Skip dot files and our own output directory. */
// Skip dot files and our own output directory.
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
@ -764,14 +875,7 @@ void sync_fuzzers(afl_state_t *afl) {
synced++;
/* document the attempt to sync to this instance */
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
id_fd =
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (id_fd >= 0) close(id_fd);
/* Skip anything that doesn't have a queue/ subdirectory. */
// Skip anything that doesn't have a queue/ subdirectory.
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
@ -787,7 +891,7 @@ void sync_fuzzers(afl_state_t *afl) {
}
/* Retrieve the ID of the last seen test case. */
// Retrieve the ID of the last seen test case.
sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
@ -802,6 +906,55 @@ void sync_fuzzers(afl_state_t *afl) {
}
// now document the attempt to sync to this instance
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
int id_fd2 =
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (id_fd2 >= 0) close(id_fd2);
// It could be that the target syncing instance was restarted, check!
time_t last_mtime = 0;
char id0[PATH_MAX];
struct stat st;
if (stat(qd_synced_path, &st) == 0) { last_mtime = st.st_mtime; }
snprintf(id0, sizeof(id0), "%s/%s/cmdline", afl->sync_dir, sd_ent->d_name);
if (likely(stat(id0, &st) == 0)) {
if (unlikely(last_mtime && last_mtime <= st.st_mtime)) {
// the first entry is newer than when we synced last - instance was
// restarted - we have to reset our counter and will skip this instance
// this time. It could also be this was trimmed later, or restated with
// resume-in-place though but better be safe.
min_accept = 0;
ck_write(id_fd, &min_accept, sizeof(u32), qd_synced_path);
goto close_sync;
}
} else {
// something went wrong - this cannot be right, mabye the instance is
// restarting, skip
goto close_sync;
}
// check if there is a file documented the maximum id seen on startup
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir, sd_ent->d_name);
s32 max_fd = open(qd_synced_maxid, O_RDONLY, DEFAULT_PERMISSION);
if (max_fd >= 0) {
read(max_fd, &max_start_id, sizeof(u32));
close(max_fd);
if (max_start_id < next_min_accept) { unlink(qd_synced_maxid); }
}
/* Show stats */
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "sync %u", ++sync_cnt);
@ -855,34 +1008,37 @@ void sync_fuzzers(afl_state_t *afl) {
if (st.st_size && st.st_size <= MAX_FILE) {
u8 fault;
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (likely(next_min_accept < max_start_id ||
!is_known_case(afl, namelist[o]->d_name))) {
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
/* See what happens. We rely on save_if_interesting() to catch major
errors and save the test case. */
/* See what happens. We rely on save_if_interesting() to catch major
errors and save the test case. */
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
if (afl->stop_soon) {
u8 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
if (afl->stop_soon) {
munmap(mem, st.st_size);
close(fd);
goto close_sync;
}
afl->syncing_party = sd_ent->d_name;
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
show_stats(afl);
afl->syncing_party = 0;
munmap(mem, st.st_size);
close(fd);
goto close_sync;
}
afl->syncing_party = sd_ent->d_name;
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
show_stats(afl);
afl->syncing_party = 0;
munmap(mem, st.st_size);
}
close(fd);

View File

@ -39,6 +39,9 @@ void sanfuzz_exec_child(afl_forkserver_t *fsrv, char **argv) {
}
// In case users provide the normally instrumented binaries, this servers as
// the last resort to avoid collecting incorrect coverage.
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
execv(fsrv->target_path, argv);
}

View File

@ -148,6 +148,34 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
}
void afl_resize_map_buffers(afl_state_t *afl, u32 old_size, u32 new_size) {
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_size);
afl->top_rated = ck_realloc(afl->top_rated, new_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_size);
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, new_size);
afl->first_trace = ck_realloc(afl->first_trace, new_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_size);
if (old_size < new_size) {
u32 size_diff = new_size - old_size;
memset(afl->var_bytes + old_size, 0, size_diff);
memset(afl->top_rated + old_size * sizeof(void *), 0,
size_diff * sizeof(void *));
memset(afl->clean_trace + old_size, 0, size_diff);
memset(afl->clean_trace_custom + old_size, 0, size_diff);
memset(afl->first_trace + old_size, 0, size_diff);
memset(afl->map_tmp_buf + old_size, 0, size_diff);
}
}
/*This sets up the environment variables for afl-fuzz into the afl_state
* struct*/

View File

@ -28,8 +28,13 @@
#include "envs.h"
#include <limits.h>
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
"finished..."};
// 7 is the number of characters in a color control code
// 11 is the number of characters in the fuzzing state itself
// 5 is the number of characters in `cRST`
// 1 is for the null character
static char fuzzing_state[4][7 + 11 + 5 + 1] = {
"started :-)", "in progress", "final phase", cRED "finished..." cRST};
char *get_fuzzing_state(afl_state_t *afl) {
@ -54,13 +59,13 @@ char *get_fuzzing_state(afl_state_t *afl) {
u64 percent_cur = last_find_100 / cur_run_time;
u64 percent_total = last_find_100 / cur_total_run_time;
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
if (unlikely(percent_cur >= 75 && percent_total >= 75)) {
if (unlikely(afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; }
return fuzzing_state[3];
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
} else if (unlikely(percent_cur >= 50 && percent_total >= 50)) {
return fuzzing_state[2];

View File

@ -1745,7 +1745,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->cycle_schedules) {
afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32));
afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32 *));
}
@ -2307,11 +2307,7 @@ int main(int argc, char **argv_orig, char **envp) {
u64 target_hash = get_binary_hash(afl->fsrv.target_path);
#endif
if ((!target_hash || prev_target_hash != target_hash)
#ifdef __linux__
|| (afl->fsrv.nyx_mode && target_hash == 0)
#endif
) {
if (!target_hash || prev_target_hash != target_hash) {
ACTF("Target binary is different, cannot perform FAST RESUME!");
@ -2502,29 +2498,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
u32 old_map_size = map_size;
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
afl->first_trace = ck_realloc(afl->first_trace, map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
if (old_map_size < map_size) {
memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);
}
afl_resize_map_buffers(afl, map_size, MAP_SIZE);
}
@ -2552,31 +2527,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (map_size < new_map_size) {
OKF("Re-initializing maps to %u bytes", new_map_size);
u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
if (old_map_size < new_map_size) {
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
new_map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
}
afl_resize_map_buffers(afl, map_size, new_map_size);
afl_fsrv_kill(&afl->fsrv);
afl_shm_deinit(&afl->shm);
@ -2637,7 +2588,6 @@ int main(int argc, char **argv_orig, char **envp) {
*/
afl->san_fsrvs[i].trace_bits = ck_alloc(
afl->fsrv.map_size + 8); /* One more u64 according to afl_shm_init*/
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
afl->san_fsrvs[i].san_but_not_instrumented = 1;
afl->san_fsrvs[i].cs_mode = afl->fsrv.cs_mode;
@ -2647,10 +2597,6 @@ int main(int argc, char **argv_orig, char **envp) {
afl->san_fsrvs[i].target_path = afl->san_binary[i];
afl->san_fsrvs[i].init_child_func = sanfuzz_exec_child;
afl->san_fsrvs[i].child_kill_signal =
afl->fsrv.child_kill_signal; // I believe cmplog also needs this.
afl->san_fsrvs[i].fsrv_kill_signal = afl->fsrv.fsrv_kill_signal;
if ((map_size <= DEFAULT_SHMEM_SIZE ||
afl->san_fsrvs[i].map_size < map_size) &&
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
@ -2673,18 +2619,7 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Re-initializing maps to %u bytes due to SAN instrumented binary",
new_map_size);
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
afl_resize_map_buffers(afl, map_size, new_map_size);
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->san_fsrvs[i]);
@ -2750,31 +2685,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (map_size < new_map_size) {
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
if (old_map_size < new_map_size) {
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
new_map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
}
afl_resize_map_buffers(afl, map_size, new_map_size);
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->cmplog_fsrv);
@ -3002,6 +2913,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->stop_soon) { goto stop_fuzzing; }
if (!afl->in_place_resume) { check_sync_fuzzers(afl); }
/* Woop woop woop */
if (!afl->not_on_tty) {

View File

@ -71,6 +71,7 @@ void afl_shm_deinit(sharedmem_t *shm) {
if (shm->shmemfuzz_mode) {
unsetenv(SHM_FUZZ_ENV_VAR);
unsetenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
} else {

View File

@ -714,61 +714,8 @@ static void handle_stop_sig(int sig) {
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
char *afl_preload;
char *frida_afl_preload = NULL;
set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
if (fsrv->qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (fsrv->frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
#endif
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
#endif
}
} else if (fsrv->frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
#endif
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
afl_fsrv_setup_preload(fsrv, argv[0]);
}
@ -1540,9 +1487,15 @@ int main(int argc, char **argv_orig, char **envp) {
shm_fuzz->cmplog_mode = 0;
atexit(at_exit_handler);
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1);
shm_fuzz->shmemfuzz_mode = true;
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
ck_free(shm_fuzz_map_size_str);
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
#else
@ -1589,7 +1542,7 @@ int main(int argc, char **argv_orig, char **envp) {
// only reinitialize when it makes sense
if (map_size < new_map_size ||
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
(new_map_size < map_size && map_size - new_map_size > MAP_SIZE)) {
if (!be_quiet)
ACTF("Acquired new map size for target: %u bytes\n", new_map_size);

View File

@ -899,9 +899,7 @@ static void handle_stop_sig(int sig) {
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
u8 *x;
char *afl_preload;
char *frida_afl_preload = NULL;
u8 *x;
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@ -945,57 +943,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
}
set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
if (fsrv->qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (fsrv->frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
#endif
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
#endif
}
} else if (fsrv->frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
#endif
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
afl_fsrv_setup_preload(fsrv, argv[0]);
}
@ -1481,9 +1429,16 @@ int main(int argc, char **argv_orig, char **envp) {
/* initialize cmplog_mode */
shm_fuzz->cmplog_mode = 0;
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1);
shm_fuzz->shmemfuzz_mode = 1;
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
ck_free(shm_fuzz_map_size_str);
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
#else

View File

@ -49,7 +49,11 @@ int main(int argc, char **argv) {
if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
printf("Hum?\n");
#ifdef EXIT_AT_END
exit(1);
#else
return 1;
#endif
}
@ -77,6 +81,10 @@ int main(int argc, char **argv) {
}
#ifdef EXIT_AT_END
exit(0);
#endif
return 0;
}

View File

@ -16,7 +16,8 @@ test -z "$AFL_CC" && {
test -e ../afl-qemu-trace && {
cc -pie -fPIE -o test-instr ../test-instr.c
cc -o test-compcov test-compcov.c
test -e test-instr -a -e test-compcov && {
cc -pie -fPIE -o test-instr-exit-at-end -DEXIT_AT_END ../test-instr.c
test -e test-instr -a -e test-compcov -a -e test-instr-exit-at-end && {
{
mkdir -p in
echo 00000 > in/in
@ -149,11 +150,63 @@ test -e ../afl-qemu-trace && {
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode"
CODE=1
}
rm -rf in out errors
rm -rf out errors
} || {
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
}
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
$ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds"
{
IS_STATIC=""
file test-instr-exit-at-end | grep -q 'statically linked' && IS_STATIC=1
test -z "$IS_STATIC" && {
if file test-instr-exit-at-end | grep -q "32-bit"; then
# for 32-bit reduce 8 nibbles to the lower 7 nibbles
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.//'`
else
# for 64-bit reduce 16 nibbles to the lower 9 nibbles
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.......//'`
fi
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
}
test -n "$IS_STATIC" && {
export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}'`
}
export AFL_QEMU_PERSISTENT_GPR=1
$ECHO "Info: AFL_QEMU_PERSISTENT_ADDR=$AFL_QEMU_PERSISTENT_ADDR <= $(nm test-instr-exit-at-end | grep "T main" | awk '{print $1}')"
export AFL_QEMU_PERSISTENT_EXITS=1
../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-instr-exit-at-end
echo status "$?"
unset AFL_QEMU_PERSISTENT_ADDR
unset AFL_QEMU_PERSISTENT_GPR
unset AFL_QEMU_PERSISTENT_EXITS
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000000* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
RUNTIMEP_EXIT=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
test -n "$RUNTIME" -a -n "$RUNTIMEP_EXIT" && {
DIFF=`expr $RUNTIMEP_EXIT / $RUNTIME`
test "$DIFF" -gt 1 && { # must be at least twice as fast
$ECHO "$GREEN[+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode"
} || {
$ECHO "$YELLOW[-] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was not noticeable faster than standard qemu_mode"
}
} || {
$ECHO "$YELLOW[-] we got no data on executions performed? weird!"
}
} || {
echo CUT------------------------------------------------------------------CUT
cat errors
echo CUT------------------------------------------------------------------CUT
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
CODE=1
}
rm -rf in out errors
} || {
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS"
}
test -e ../qemu_mode/unsigaction/unsigaction32.so && {
${AFL_CC} -o test-unsigaction32 -m32 test-unsigaction.c >> errors 2>&1 && {
./test-unsigaction32
@ -212,7 +265,7 @@ test -e ../afl-qemu-trace && {
CODE=1
}
rm -f test-instr test-compcov
rm -f test-instr test-compcov test-instr-exit-at-end
} || {
$ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
INCOMPLETE=1

View File

@ -18,7 +18,8 @@ ifneq "" "$(LLVM_BINDIR)"
endif
endif
CFLAGS := -O3 -funroll-loops -g -fPIC
CFLAGS := -O3 -funroll-loops -g -fPIC -fno-lto
AR ?= ar
ifdef IOS_SDK_PATH
CFLAGS += -isysroot $(IOS_SDK_PATH)
@ -30,7 +31,7 @@ aflpp_driver.o: aflpp_driver.c
-$(CC) -I. -I../../include $(CFLAGS) -c aflpp_driver.c
libAFLDriver.a: aflpp_driver.o
@ar rc libAFLDriver.a aflpp_driver.o
@$(AR) rc libAFLDriver.a aflpp_driver.o
@cp -vf libAFLDriver.a ../../
debug:
@ -38,13 +39,13 @@ debug:
$(CC) -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
#$(CC) -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
#$(CC) -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
ar rc libAFLDriver.a afl-performance.o aflpp_driver.o
$(AR) rc libAFLDriver.a afl-performance.o aflpp_driver.o
aflpp_qemu_driver.o: aflpp_qemu_driver.c
-$(CC) $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
libAFLQemuDriver.a: aflpp_qemu_driver.o
@-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o
@-$(AR) rc libAFLQemuDriver.a aflpp_qemu_driver.o
@-cp -vf libAFLQemuDriver.a ../../
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o

View File

@ -64,6 +64,15 @@ extern "C" {
#include "hash.h"
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define SECTION_RODATA \
__attribute__((used, retain)) __attribute__((section("__RODATA,__" \
"rodata")))
#else
#define SECTION_RODATA \
__attribute__((used, retain)) __attribute__((section(".rodata")))
#endif
// AFL++ shared memory fuzz cases
int __afl_sharedmem_fuzzing = 1;
extern unsigned int *__afl_fuzz_len;
@ -106,14 +115,11 @@ __attribute__((weak)) void __asan_unpoison_memory_region(
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size);
// Notify AFL about persistent mode.
__attribute__((section(".rodata"), used,
retain)) static const char AFL_PERSISTENT[] =
"##SIG_AFL_PERSISTENT##";
int __afl_persistent_loop(unsigned int);
SECTION_RODATA static const char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
int __afl_persistent_loop(unsigned int);
// Notify AFL about deferred forkserver.
__attribute__((section(".rodata"), used,
retain)) static const char AFL_DEFER_FORKSVR[] =
SECTION_RODATA static const char AFL_DEFER_FORKSVR[] =
"##SIG_AFL_DEFER_FORKSRV##";
void __afl_manual_init();

View File

@ -0,0 +1,12 @@
# For cross compilation modify this as needed
#GLIBC_PATH := /path/to/glibc-2.xx/build/local_install
#CROSS_CFLAGS := -mfloat-abi=soft -nostdlib -I$(GLIBC_PATH)/include -L$(GLIBC_PATH)/lib -Wl,-rpath=/lib -Wl,--dynamic-linker=/lib/ld-linux.so.3
all: libaflppdesock.so
libaflppdesock.so: libaflppdesock.c
$(CC) $(CROSS_CFLAGS) -shared -fPIC -o libaflppdesock.so libaflppdesock.c
clean:
rm -f libaflppdesock.so *~ core

View File

@ -0,0 +1,46 @@
# AFL++ TCP desocket library
Other desocketing solutions:
* https://github.com/zardus/preeny (desock and desock2)
* https://github.com/fkie-cad/libdesock
* https://github.com/zyingp/desockmulti
* https://github.com/vanhauser-thc/network-emulator
If these desocket solutions fail, then this one will likely easily work
for you - alass with slightly lower performance.
And it is easy to extend :-)
## Why might this solution work when others do not?
What makes this desocket library special is that only **only** intercepts
`accept()` calls bound to a specified port. Hence any other network stuff
the application does is still working as expected.
## How to use
`AFL_PRELOAD` this library and use the following environment variables:
* `DESOCK_PORT=8080` - required for intercepting incoming connections for fuzzing - sets the TCP port
* `DESOCK_FORK=1` - intercept and prevent forking
* `DESOCK_CLOSE_EXIT=1` - call _exit() when the desocketed file descriptor is `close`d or `shutdown`ed
* `DESOCK_DEBUG=1` - print debug information to `stderr`
** Internals
Currently the library intercepts the following calls:
```
shutdown
close
fork
accept
accept4
listen
bind
setsockopt
getsockopt
getpeername
getsockname
```
`

View File

@ -0,0 +1,352 @@
/* desocket library by Marc "vanHauser" Heuse <vh@thc.org>
*
* Use this library for fuzzing if preeny's desock and desock2 solutions
* do not work for you - these would provide faster performance.
*
*/
// default: file descriptor 0 for stdin
#define FUZZ_INPUT_FD 0
#include <dlfcn.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void *handle;
static bool do_fork, do_close, debug, running;
static int port = -1;
static int listen_fd = -1;
struct myin_addr {
unsigned int s_addr; // IPv4 address in network byte order
};
struct mysockaddr {
unsigned short int sin_family; // Address family: AF_INET
unsigned short int sin_port; // Port number (network byte order)
struct myin_addr sin_addr; // Internet address
char sin_zero[8]; // Padding (unused)
};
#define RTLD_LAZY 0x00001
unsigned short int htons(unsigned short int hostshort) {
return (hostshort << 8) | (hostshort >> 8);
}
static void __get_handle() {
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
if (!(handle = dlopen("libc.so.6", RTLD_NOW))) {
if (!(handle = dlopen("libc-orig.so", RTLD_LAZY))) {
if (!(handle = dlopen("cygwin1.dll", RTLD_LAZY))) {
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
fprintf(stderr, "DESOCK: can not find libc!\n");
exit(-1);
}
}
}
}
}
if (getenv("DESOCK_DEBUG")) { debug = true; }
if (getenv("DESOCK_PORT")) { port = atoi(getenv("DESOCK_PORT")); }
if (getenv("DESOCK_FORK")) { do_fork = true; }
if (getenv("DESOCK_CLOSE_EXIT")) { do_close = true; }
if (debug) fprintf(stderr, "DESOCK: initialized!\n");
}
int (*o_shutdown)(int socket, int how);
int shutdown(int socket, int how) {
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
running = false;
if (do_close) {
if (debug) fprintf(stderr, "DESOCK: exiting\n");
_exit(0);
}
}
if (port == -1 && do_close) {
if (debug) fprintf(stderr, "DESOCK: exiting\n");
_exit(0);
}
if (!handle) { __get_handle(); }
if (!o_shutdown) { o_shutdown = dlsym(handle, "shutdown"); }
return o_shutdown(socket, how);
}
int (*o_close)(int socket);
int close(int socket) {
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
running = false;
if (do_close) {
if (debug) fprintf(stderr, "DESOCK: exiting\n");
_exit(0);
}
}
if (listen_fd != -1 && socket == listen_fd) {
if (debug) fprintf(stderr, "DESOCK: close bind\n");
listen_fd = -1;
}
if (!handle) { __get_handle(); }
if (!o_close) { o_close = dlsym(handle, "close"); }
return o_close(socket);
}
int (*o_fork)(void);
int fork() {
if (do_fork) {
if (debug) fprintf(stderr, "DESOCK: fake fork\n");
return 0;
}
if (!handle) { __get_handle(); }
if (!o_fork) { o_fork = dlsym(handle, "fork"); }
return o_fork();
}
int (*o_accept)(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen);
int accept(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen) {
if (!handle) { __get_handle(); }
if (!o_accept) { o_accept = dlsym(handle, "accept"); }
if (!running && sockfd == listen_fd) {
if (debug) fprintf(stderr, "DESOCK: intercepted accept on %d\n", sockfd);
if (addr && addrlen) {
// we need to fill this!
memset(addr, 0, *addrlen);
addr->sin_family = 2; // AF_INET
addr->sin_port = htons(1023); // Port 1023 in network byte order
addr->sin_addr.s_addr = 0x0100007f;
}
running = true;
return FUZZ_INPUT_FD;
}
return o_accept(sockfd, addr, addrlen);
}
int accept4(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen,
int flags) {
return accept(sockfd, addr, addrlen); // ignore flags
}
int (*o_listen)(int sockfd, int backlog);
int listen(int sockfd, int backlog) {
if (!handle) { __get_handle(); }
if (!o_listen) { o_listen = dlsym(handle, "listen"); }
if (sockfd == listen_fd) {
if (debug) fprintf(stderr, "DESOCK: intercepted listen on %d\n", sockfd);
return 0;
}
return o_listen(sockfd, backlog);
}
int (*o_bind)(int sockfd, const struct mysockaddr *addr,
unsigned long int addrlen);
int bind(int sockfd, const struct mysockaddr *addr, unsigned long int addrlen) {
if (!handle) { __get_handle(); }
if (!o_bind) { o_bind = dlsym(handle, "bind"); }
if (addr->sin_port == htons(port)) {
if (debug) fprintf(stderr, "DESOCK: intercepted bind on %d\n", sockfd);
listen_fd = sockfd;
return 0;
}
return o_bind(sockfd, addr, addrlen);
}
int (*o_setsockopt)(int sockfd, int level, int optname, const void *optval,
unsigned long int optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval,
unsigned long int optlen) {
if (!handle) { __get_handle(); }
if (!o_setsockopt) { o_setsockopt = dlsym(handle, "setsockopt"); }
if (listen_fd == sockfd) {
if (debug)
fprintf(stderr, "DESOCK: intercepted setsockopt on %d for %d\n", sockfd,
optname);
return 0;
}
return o_setsockopt(sockfd, level, optname, optval, optlen);
}
int (*o_getsockopt)(int sockfd, int level, int optname, void *optval,
unsigned long int *optlen);
int getsockopt(int sockfd, int level, int optname, void *optval,
unsigned long int *optlen) {
if (!handle) { __get_handle(); }
if (!o_getsockopt) { o_getsockopt = dlsym(handle, "getsockopt"); }
if (listen_fd == sockfd) {
if (debug)
fprintf(stderr, "DESOCK: intercepted getsockopt on %d for %d\n", sockfd,
optname);
int *o = (int *)optval;
if (o != NULL) {
*o = 1; // let's hope this is fine
}
return 0;
}
return o_getsockopt(sockfd, level, optname, optval, optlen);
}
int (*o_getpeername)(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen);
int getpeername(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen) {
if (!handle) { __get_handle(); }
if (!o_getpeername) { o_getpeername = dlsym(handle, "getpeername"); }
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
if (debug) fprintf(stderr, "DESOCK: getpeername\n");
if (addr && addrlen) {
// we need to fill this!
memset(addr, 0, *addrlen);
addr->sin_family = 2; // AF_INET
addr->sin_port = htons(1023); // Port 1023 in network byte order
addr->sin_addr.s_addr = 0x0100007f;
}
return 0;
}
return o_getpeername(sockfd, addr, addrlen);
}
int (*o_getsockname)(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen);
int getsockname(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen) {
if (!handle) { __get_handle(); }
if (!o_getsockname) { o_getsockname = dlsym(handle, "getsockname"); }
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
if (debug) fprintf(stderr, "DESOCK: getsockname\n");
if (addr && addrlen) {
// we need to fill this!
memset(addr, 0, *addrlen);
addr->sin_family = 2; // AF_INET
addr->sin_port = htons(port);
addr->sin_addr.s_addr = 0x0100007f;
}
return 0;
}
return o_getsockname(sockfd, addr, addrlen);
}
static FILE *(*o_fdopen)(int fd, const char *mode);
FILE *fdopen(int fd, const char *mode) {
if (!o_fdopen) {
if (!handle) { __get_handle(); }
o_fdopen = dlsym(handle, "fdopen");
if (!o_fdopen) {
fprintf(stderr, "%s(): can not find fdopen\n", dlerror());
exit(-1);
}
}
if (fd == FUZZ_INPUT_FD && strcmp(mode, "r") != 0) {
if (debug) fprintf(stderr, "DESOCK: intercepted fdopen(r+) for %d\n", fd);
return o_fdopen(fd, "r");
}
return o_fdopen(fd, mode);
}
/* TARGET SPECIFIC HOOKS - put extra needed code for your target here */

View File

@ -19,11 +19,11 @@ HELPER_PATH = $(PREFIX)/lib/afl
VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
CFLAGS_ADD += $(USENAMEDPAGE:1=-DUSENAMEDPAGE)
CFLAGS += $(CFLAGS_ADD)
override CFLAGS += $(CFLAGS_ADD)
all: libdislocator.so
@ -41,4 +41,3 @@ install: all
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md