Compare commits

...

57 Commits

Author SHA1 Message Date
0e8324d4b1 add output warning 2024-02-13 14:00:14 +01:00
5f5d848964 add output warning 2024-02-13 13:58:27 +01:00
4309e48085 enhancement 2024-02-12 09:18:07 +01:00
bf06b7e897 enhancement 2024-02-12 09:17:52 +01:00
6316994857 try ramp up for colorless 2024-02-11 23:12:24 +01:00
30c91e46af Merge pull request #1992 from ndrewh/dev
redqueen: time limit for colorization
2024-02-11 22:23:37 +01:00
c0b667178b redqueen: time limit for colorization
For nondeterministic inputs, or inputs where a large portion of the
input bytes break the path (e.g., bytes protected by a checksum),
colorization will split the range n times, once for every byte.

This is bad: for a 10k input that runs in 100ms, colorization
will take 15 minutes. For larger/slower inputs, it can easily
take hours.

This places a upper-bound on the runtime of colorization.
2024-02-11 12:17:55 -05:00
5404eef7be update docs 2024-02-09 17:08:23 +01:00
6fed799957 unicorn fix 2024-02-09 14:14:12 +01:00
dd88069711 fix 2024-02-09 13:57:45 +01:00
07bc202e0a fixes 2024-02-09 13:51:05 +01:00
f2b7357ff3 fixes 2024-02-09 13:09:23 +01:00
3cbaefd247 Merge pull request #1995 from seanm/issue1981
Fixed issue #1981: document PATH correctly based on homebrew version
2024-02-09 10:31:38 +01:00
037a14f621 Fixed issue #1981: document PATH correctly based on homebrew version
- removed reference to M1 as M2 and M3 exist now too.
- Also use current name and spelling of "macOS".
2024-02-08 21:15:59 -05:00
88e41f01c8 env fix 2024-02-08 15:28:19 +01:00
369fce9c85 code format 2024-02-08 15:13:46 +01:00
eaf4a29930 make redqueen hashmap not default 2024-02-08 14:54:10 +01:00
48070e0148 Merge branch '420' into dev 2024-02-08 14:51:13 +01:00
c23bbddde9 workaround for MOpt bug with -S 2024-02-08 14:31:36 +01:00
038fef962c performance 2024-02-08 12:46:08 +01:00
42c663e7c7 Merge pull request #1965 from CodeLinaro/stateful
replay mode support
2024-02-08 10:29:33 +01:00
956fa95d77 updated readme 2024-02-07 12:00:11 +01:00
ea0ea88ed3 add conditional check for persistent record mode on forkserver handling of hang/crash 2024-02-07 12:00:01 +01:00
e0e8645d6c Merge pull request #1990 from monik3r/dev
Add 7950x3d and 6900hs benchmarks, with and without mitigations
2024-02-07 09:03:01 +01:00
a2100f32e0 Add missing jsonl entry. Thanks @cjb! 2024-02-06 21:00:43 -08:00
25a6c2c006 Add benmark-results.jsonl 2024-02-06 20:39:34 -08:00
7f8347b12e Add 7950x3d and 6900hs benchmarks, with and without mitigations 2024-02-06 20:24:31 -08:00
8e4bd0314e added README.md to utils/replay_record 2024-02-06 21:34:56 +01:00
a7fd84e186 fix typo 2024-02-06 21:25:40 +01:00
e405e721fa reuse first_pass aux var in persistent loop for record replay mode, keep area ptr and loc logic intact in record replay mode, move replay record example to own dir in utils, update docs, move record compat layer to separate header file 2024-02-06 18:19:52 +01:00
49d4fa4346 add replay_record binaries to .gitignore 2024-02-06 18:16:37 +01:00
375aca2997 nits 2024-02-06 14:49:21 +01:00
9f8eea5467 add spec_rstack_overflow=off to persistent-config 2024-02-06 14:25:39 +01:00
58aa181d01 revert persistent_demo_new.c to b99bbf671b 2024-02-06 14:00:37 +01:00
f49e391022 prevent afl-whatsup tmp files 2024-02-06 10:48:24 +01:00
698f1e272b fix hashmap test 2024-02-06 09:34:21 +01:00
023fc19ce0 better replay mode error handling, added replay mode documentation, code formatting 2024-02-05 18:26:46 +01:00
40df85d1e6 adjust cmplog header 2024-02-05 15:05:46 +01:00
47e7d243f7 increase version 2024-02-04 16:18:21 +01:00
6d209ce045 fix -z 2024-02-04 16:16:32 +01:00
34a3060b0f config __afl_cmplog_max_len 2024-02-04 16:08:57 +01:00
c77709cdd9 add U256/32byte support 2024-02-04 16:03:12 +01:00
27338fcef1 new forkserver - client side 2024-02-03 18:27:01 +01:00
9fab7e892d new forkserver - server part 2024-02-03 16:48:38 +01:00
dc151caa18 add lto caller instrumentation 2024-02-03 15:53:54 +01:00
e1d7f4af35 Merge pull request #1988 from AFLplusplus/ltoctx
Ltoctx
2024-02-03 15:08:52 +01:00
d85722a4f6 deterministic fuzzing and -z 2024-02-03 13:31:31 +01:00
ba3a039e45 finish lto-ctx 2024-02-02 13:17:20 +01:00
bd13d32437 final touches 2024-02-02 09:54:24 +01:00
79080355ac better CTX instrumentation 2024-02-01 17:39:23 +01:00
e6eee685ce fix 2024-01-27 15:13:27 +01:00
ceb7e44e6f fixes 2024-01-27 08:28:47 +01:00
d668010bed fixes 2024-01-26 16:44:31 +01:00
44a7696169 fixes 2024-01-26 15:27:20 +01:00
b0a912a838 working ugly version 2024-01-26 12:15:42 +01:00
4d493452a4 tmp 2024-01-25 17:00:53 +01:00
8fedf49984 replay mode support 2024-01-23 19:36:49 +01:00
50 changed files with 7821 additions and 2261 deletions

View File

@ -5,6 +5,7 @@ on:
branches:
- stable
- dev
- 420
pull_request:
branches:
- dev # No need for stable-pull-request, as that equals dev-push

5
.gitignore vendored
View File

@ -99,10 +99,15 @@ unicorn_mode/samples/*/\.test-*
utils/afl_network_proxy/afl-network-client
utils/afl_network_proxy/afl-network-server
utils/afl_proxy/afl-proxy
utils/bench/hash
utils/optimin/build
utils/optimin/optimin
utils/persistent_mode/persistent_demo
utils/persistent_mode/persistent_demo_new
utils/persistent_mode/persistent_demo_new_compat
utils/persistent_mode/test-instr
utils/replay_record/persistent_demo_replay
utils/replay_record/persistent_demo_replay_compat
utils/replay_record/persistent_demo_replay_argparse
utils/plot_ui/afl-plot-ui
vuln_prog

View File

@ -84,21 +84,27 @@ else
endif
endif
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
#endif
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# ifndef SOURCE_DATE_EPOCH
# HAVE_MARCHNATIVE = 1
# CFLAGS_OPT += -march=native
# endif
#endif
ifdef PERFORMANCE
SPECIAL_PERFORMANCE := -D_AFL_SPECIAL_PERFORMANCE
ifeq "$(SYS)" "Linux"
ifeq "$(shell grep avx2 /proc/cpuinfo)" ""
else
SPECIAL_PERFORMANCE += -mavx2 -D_HAVE_AVX2
endif
endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
HAVE_MARCHNATIVE = 1
SPECIAL_PERFORMANCE += -march=native
endif
$(info SPECIAL_PERFORMANCE=$(SPECIAL_PERFORMANCE))
else
SPECIAL_PERFORMANCE :=
endif
ifneq "$(SYS)" "Darwin"
#ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native
#endif
#ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native
#endif
#ifndef DEBUG
# CFLAGS_OPT += -D_FORTIFY_SOURCE=1
#endif
@ -389,6 +395,7 @@ help:
@echo
@echo Known build environment options:
@echo "=========================================="
@echo "PERFORMANCE - compile with performance options that make the binary not transferable to other systems. Recommended!"
@echo STATIC - compile AFL++ static
@echo "CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)"
@echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
@ -453,31 +460,31 @@ afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
@ln -sf afl-as as
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
$(CC) $(CFLAGS) $(CFLAGS_OPT) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
$(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-common.c -o src/afl-common.o
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-forkserver.c -o src/afl-forkserver.o
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -Wno-shift-count-overflow $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS)
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
.PHONY: document
document: afl-fuzz-document
@ -494,17 +501,17 @@ unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
./test/unittests/unit_maybe_alloc
test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
unit_hash: test/unittests/unit_hash.o src/afl-performance.o
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_hash
test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_rand
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)

View File

@ -4,7 +4,7 @@
Release version: [4.10c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.10c
GitHub version: 4.20a
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)

View File

@ -2,17 +2,15 @@
## Must
- UI revamp
- hardened_usercopy=0 page_alloc.shuffle=0
- add value_profile but only enable after 15 minutes without finds
- cmplog max len, cmplog max items envs?
- cmplog max items env?
- adapt MOpt to new mutation engine
- Update afl->pending_not_fuzzed for MOpt
- cmplog rtn sanity check on fixed length? currently we ignore the length
- afl-showmap -f support
- afl-fuzz multicore wrapper script
- when trimming then perform crash detection
- problem: either -L0 and/or -p mmopt results in zero new coverage
## Should

View File

@ -129,7 +129,7 @@ EOF
grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | grep -E -q 'noibrs pcid nopti' || {
echo "Configuring performance boot options"
LINE=`grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//' | tr -d '"'`
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
echo Setting boot options in /etc/default/grub to GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"
sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"|" /etc/default/grub
}

View File

@ -114,6 +114,7 @@ fi
CUR_TIME=`date +%s`
TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1
trap "rm -f $TMP" 1 2 3 13 15
ALIVE_CNT=0
DEAD_CNT=0

View File

@ -7,3 +7,7 @@ Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz | 4995 | 16 | 120064
12th Gen Intel(R) Core(TM) i7-1270P | 4761 | 16 | 149778 | 641219 | both |
AMD Ryzen 9 5950X 16-Core Processor | 4792 | 32 | 161690 | 2339763 | both |
Apple Mac Studio M2 Ultra 2023, Linux VM guest | 3500 | 16 | 163570 | 1157465 | both |
AMD Ryzen 9 6900HS with Radeon Graphics | 4676 | 16 | 62860 | 614404 | system |
AMD Ryzen 9 6900HS with Radeon Graphics | 4745 | 16 | 135501 | 991133 | both |
AMD Ryzen 9 7950X3D 16-Core Processor | 5400 | 32 | 71566 | 1566279 | system |
AMD Ryzen 9 7950X3D 16-Core Processor | 5478 | 32 | 161960 | 2173959 | both |

View File

@ -418,3 +418,7 @@
{"config": {"afl_persistent_config": true, "afl_system_config": true, "afl_version": "++4.08a", "comment": "", "compiler": "Ubuntu clang version 14.0.0-1ubuntu1.1", "target_arch": "x86_64-pc-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 3700.0, "cpu_model": "AMD Ryzen 5 PRO 4650G with Radeon Graphics", "cpu_threads": 12}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 704840.16, "execs_total": 21163992, "fuzzers_used": 12}, "singlecore": {"execs_per_sec": 95356.14, "execs_total": 2862114, "fuzzers_used": 1}}}}
{"config": {"afl_persistent_config": true, "afl_system_config": true, "afl_version": "++4.09a", "comment": "", "compiler": "Debian clang version 14.0.6", "target_arch": "aarch64-unknown-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 2400.0, "cpu_model": "Raspberry Pi 5", "cpu_threads": 4}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 101114.23, "execs_total": 3036637, "fuzzers_used": 4}, "singlecore": {"execs_per_sec": 25786.11, "execs_total": 774460, "fuzzers_used": 1}}}}
{"config": {"afl_persistent_config": true, "afl_system_config": true, "afl_version": "++4.07a", "comment": "", "compiler": "Debian clang version 17.0.0 (++20230417071830+ae77aceba5ad-1~exp1~20230417071935.630)", "target_arch": "x86_64-pc-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 4792.073, "cpu_model": "AMD Ryzen 9 5950X 16-Core Processor", "cpu_threads": 32}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 2339762.91, "execs_total": 70253164, "fuzzers_used": 32}, "singlecore": {"execs_per_sec": 161690.07, "execs_total": 4851838, "fuzzers_used": 1}}}}
{"config": {"afl_persistent_config": false, "afl_system_config": true, "afl_version": "++4.10c", "comment": "", "compiler": "clang version 17.0.6", "target_arch": "x86_64-pc-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 4675.949, "cpu_model": "AMD Ryzen 9 6900HS with Radeon Graphics", "cpu_threads": 16}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 614403.91, "execs_total": 18435083, "fuzzers_used": 16}, "singlecore": {"execs_per_sec": 62859.9, "execs_total": 1886111, "fuzzers_used": 1}}}}
{"config": {"afl_persistent_config": true, "afl_system_config": true, "afl_version": "++4.10c", "comment": "", "compiler": "clang version 17.0.6", "target_arch": "x86_64-pc-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 4744.522, "cpu_model": "AMD Ryzen 9 6900HS with Radeon Graphics", "cpu_threads": 16}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 991132.96, "execs_total": 29737588, "fuzzers_used": 16}, "singlecore": {"execs_per_sec": 135501.07, "execs_total": 4066116, "fuzzers_used": 1}}}}
{"config": {"afl_persistent_config": false, "afl_system_config": true, "afl_version": "++4.10c", "comment": "", "compiler": "Ubuntu clang version 14.0.6", "target_arch": "x86_64-pc-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 5399.822, "cpu_model": "AMD Ryzen 9 7950X3D 16-Core Processor", "cpu_threads": 32}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 1566279.42, "execs_total": 46994452, "fuzzers_used": 32}, "singlecore": {"execs_per_sec": 71565.56, "execs_total": 2147396, "fuzzers_used": 1}}}}
{"config": {"afl_persistent_config": true, "afl_system_config": true, "afl_version": "++4.10c", "comment": "", "compiler": "clang version 17.0.6", "target_arch": "x86_64-pc-linux-gnu"}, "hardware": {"cpu_fastest_core_mhz": 5478.258, "cpu_model": "AMD Ryzen 9 7950X3D 16-Core Processor", "cpu_threads": 32}, "targets": {"test-instr-persist-shmem": {"multicore": {"execs_per_sec": 2173959.15, "execs_total": 65229513, "fuzzers_used": 32}, "singlecore": {"execs_per_sec": 161960.29, "execs_total": 4859457, "fuzzers_used": 1}}}}

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.20a (dev)
! A new forkserver communication model is now introduced. afl-fuzz is
backward compatible to old compiled targets if they are not built
for CMPLOG/Redqueen, but new compiled targets will not work with
old afl-fuzz versions!
! Recompiled all targets that are instrumented for CMPLOG/Redqueen!
- AFL++ now supports up to 4 billion coverage edges, up from 6 million.
- New compile option: `make PERFORMANCE=1` - this will enable special
CPU dependent optimizations that make everything more performant - but
the binaries will likely won't work on different platforms. Also
enables a faster hasher if the CPU requirements are met.
- The persistent record feature (see config.h) was expanded to also
support replay, thanks to @quarta-qti !
- afl-fuzz:
- the new deterministic fuzzing feature is now activated by default,
deactivate with -z. Parameters -d and -D are ignored.
- small improvements to CMPLOG/redqueen
- workround for a bug with MOpt -L when used with -M - in the future
we will either remove or rewrite MOpt.
- afl-cc:
- added collision free caller instrumentation to LTO mode. activate with
`AFL_LLVM_LTO_CALLER=1`. You can set a max depth to go through single
block functions with `AFL_LLVM_LTO_CALLER_DEPTH` (default 0)
- Minor edits to afl-persistent-config
- Prevent temporary files being left behind on aborted afl-whatsup
- More CPU benchmarks added to benchmark/
### Version ++4.10c (release)
- afl-fuzz:
- default power schedule is now EXPLORE, due a fix in fast schedules

View File

@ -69,14 +69,15 @@ These build targets exist:
[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html),
you can also build statically linked versions of the AFL++ binaries by passing
the `STATIC=1` argument to make:
the `PERFORMANCE=1` argument to make:
```shell
make STATIC=1
make PERFORMANCE=1
```
These build options exist:
* PERFORMANCE - compile with performance options that make the binary not transferable to other systems. Recommended!
* STATIC - compile AFL++ static
* CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)
* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
@ -96,9 +97,9 @@ These build options exist:
e.g.: `make LLVM_CONFIG=llvm-config-14`
## MacOS X on x86 and arm64 (M1)
## macOS on x86_64 and arm64
MacOS has some gotchas due to the idiosyncrasies of the platform.
macOS has some gotchas due to the idiosyncrasies of the platform.
To build AFL, install llvm (and perhaps gcc) from brew and follow the general
instructions for Linux. If possible, avoid Xcode at all cost.
@ -107,17 +108,20 @@ instructions for Linux. If possible, avoid Xcode at all cost.
brew install wget git make cmake llvm gdb coreutils
```
Depending on your macOS system + brew version, brew may be installed in different places.
You can check with `brew info llvm` to know where, then create a variable for it:
```shell
export HOMEBREW_BASE="/opt/homebrew/opt"
# or
export HOMEBREW_BASE="/usr/local/opt"
```
Be sure to setup `PATH` to point to the correct clang binaries and use the
freshly installed clang, clang++, llvm-config, gmake and coreutils, e.g.:
```shell
# Depending on your MacOS system + brew version it is either
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
# or
export PATH="/usr/local/opt/llvm/bin:/usr/local/opt/coreutils/libexec/gnubin:$PATH"
# you can check with "brew info llvm"
export PATH="/usr/local/bin:$PATH"
export PATH="$HOMEBREW_BASE/coreutils/libexec/gnubin:/usr/local/bin:$HOMEBREW_BASE/llvm/bin:$PATH"
export CC=clang
export CXX=clang++
gmake
@ -130,9 +134,9 @@ sudo gmake install
`afl-gcc` will fail unless you have GCC installed, but that is using outdated
instrumentation anyway. `afl-clang` might fail too depending on your PATH setup.
But you don't want neither, you want `afl-clang-fast` anyway :) Note that
`afl-clang-lto`, `afl-gcc-fast` and `qemu_mode` are not working on MacOS.
`afl-clang-lto`, `afl-gcc-fast` and `qemu_mode` are not working on macOS.
The crash reporting daemon that comes by default with MacOS X will cause
The crash reporting daemon that comes by default with macOS will cause
problems with fuzzing. You need to turn it off:
```
@ -145,16 +149,16 @@ and definitely don't look POSIX-compliant. This means two things:
- Fuzzing will be probably slower than on Linux. In fact, some folks report
considerable performance gains by running the jobs inside a Linux VM on
MacOS X.
macOS.
- Some non-portable, platform-specific code may be incompatible with the AFL++
forkserver. If you run into any problems, set `AFL_NO_FORKSRV=1` in the
environment before starting afl-fuzz.
User emulation mode of QEMU does not appear to be supported on MacOS X, so
User emulation mode of QEMU does not appear to be supported on macOS, so
black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`)
works on both x86 and arm64 MacOS boxes.
works on both x86 and arm64 macOS boxes.
MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
macOS supports SYSV shared memory used by AFL's instrumentation, but the
default settings aren't usable with AFL++. The default settings on 10.14 seem to
be:

View File

@ -248,6 +248,9 @@ use (which only ever the author of this LTO implementation will use). These are
used if several separated instrumentations are performed which are then later
combined.
- `AFL_LLVM_LTO_CALLER` activates collision free CALLER instrumentation
- `AFL_LLVM_LTO_CALLER` sets the maximum mumber of single block functions
to dig deeper into a real function. Default 0.
- `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given
to which function. This helps to identify functions with variable bytes or
which functions were touched by an input.

View File

@ -5,6 +5,10 @@
* [afl-rs](https://github.com/rust-fuzz/afl.rs) - AFL++ for RUST
* [WASM](https://github.com/fgsect/WAFL) - AFL++ for WASM
## Starting multiple AFL++ instances in parallel with recommended settings:
* [https://github.com/0xricksanchez/AFL_Runner](https://github.com/0xricksanchez/AFL_Runner)
* [https://github.com/MegaManSec/AFLplusplus-Parallel-Gen](https://github.com/MegaManSec/AFLplusplus-Parallel-Gen)
## Speeding up fuzzing
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the

View File

@ -21,6 +21,9 @@ training, then we can highly recommend the following:
* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
A good workflow overview (like our [fuzzing_in_depth.md](fuzzing_in_depth.md)):
* [https://appsec.guide/docs/fuzzing/c-cpp/aflpp/](https://appsec.guide/docs/fuzzing/c-cpp/aflpp/)
Here is a good workflow description (and tutorial) for qemu_mode:
* [https://airbus-seclab.github.io/AFLplusplus-blogpost/](https://airbus-seclab.github.io/AFLplusplus-blogpost/)

View File

@ -124,6 +124,10 @@
#define CASE_PREFIX "id_"
#endif /* ^!SIMPLE_FILES */
#ifdef AFL_PERSISTENT_RECORD
#define RECORD_PREFIX "RECORD:"
#endif
#define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */
// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
@ -601,6 +605,9 @@ typedef struct afl_state {
#define N_FUZZ_SIZE (1 << 21)
u32 *n_fuzz;
/* CMPLOG colorless feature */
u64 cmplog_color_items, cmplog_color_fail, cmplog_color_depth;
volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen; /* Window resized? */

View File

@ -0,0 +1,131 @@
#ifndef _HAVE_PERSISTENT_REPLAY_H
#define _HAVE_PERSISTENT_REPLAY_H
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
static unsigned short int is_replay_record;
static unsigned int replay_record;
static unsigned int replay_record_cnt;
static char replay_record_path[PATH_MAX];
static char *replay_record_dir;
static struct dirent **record_list;
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
static char **record_arg = NULL;
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
static int select_files(const struct dirent *dirbuf) {
char fn[PATH_MAX];
if (dirbuf->d_name[0] == '.') {
return 0;
} else {
snprintf(fn, sizeof(fn), "RECORD:%06u", replay_record);
return !!strstr(dirbuf->d_name, fn);
}
}
static int compare_files(const struct dirent **da, const struct dirent **db) {
unsigned int c1 = 0, c2 = 0;
sscanf((*da)->d_name, "RECORD:%*u,cnt:%06u", &c1);
sscanf((*db)->d_name, "RECORD:%*u,cnt:%06u", &c2);
return c1 - c2;
}
__attribute__((destructor)) static void __afl_record_replay_destroy(void) {
for (int i = 0; i < replay_record_cnt; i++) {
free(record_list[i]);
}
free(record_list);
}
__attribute__((constructor)) static void __afl_record_replay_init(
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
int argc, char **argv
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
) {
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
char **argp;
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
struct stat sb;
/* caveat: if harness uses @@ and we don't pass it, it will regardless loop
* the number of iterations defined for AFL_LOOP (on the same file)*/
if (!(is_replay_record = !!getenv("AFL_PERSISTENT_REPLAY"))) {
// printf("[warning] AFL_PERSISTENT_REPLAY not set.\n");
return;
}
replay_record = atoi(getenv("AFL_PERSISTENT_REPLAY"));
replay_record_dir = getenv("AFL_PERSISTENT_DIR");
if (!(stat(replay_record_dir, &sb) == 0 && S_ISDIR(sb.st_mode))) {
fprintf(stderr, "[error] Can't find the requested record directory!\n");
is_replay_record = 0;
return;
}
replay_record_cnt = scandir(replay_record_dir ? replay_record_dir : "./",
&record_list, select_files, compare_files);
if (!replay_record_cnt) {
fprintf(stderr, "[error] Can't find the requested record!\n");
is_replay_record = 0;
}
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
argp = argv;
while (*argp) {
if (!strcmp(*argp, "@@")) {
record_arg = argp;
*record_arg = replay_record_path;
break;
}
++argp;
}
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
}
#endif // _HAVE_PERSISTENT_REPLAY_H

View File

@ -0,0 +1,67 @@
#ifndef _HAVE_AFL_COMPAT_H
#define _HAVE_AFL_COMPAT_H
#include <afl-persistent-replay.h>
#define FUZZ_BUF_SIZE 1024000
// extern ssize_t read(int fildes, void *buf, size_t nbyte);
// extern int __afl_persistent_loop(unsigned int max_cnt);
// extern unsigned char fuzz_buf[];
#ifndef __AFL_HAVE_MANUAL_CONTROL
#define __AFL_HAVE_MANUAL_CONTROL
#endif
#define __AFL_FUZZ_TESTCASE_LEN (read(0, fuzz_buf, FUZZ_BUF_SIZE))
#define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
#define __AFL_FUZZ_INIT() void sync(void);
#define __AFL_INIT() sync()
#define __AFL_LOOP(x) __afl_persistent_loop(x)
unsigned char fuzz_buf[FUZZ_BUF_SIZE];
int __afl_persistent_loop(unsigned int max_cnt) {
static unsigned int cycle_cnt = 1;
static unsigned short int inited = 0;
char tcase[PATH_MAX];
if (is_replay_record) {
if (!inited) {
cycle_cnt = replay_record_cnt;
inited = 1;
}
snprintf(tcase, PATH_MAX, "%s/%s",
replay_record_dir ? replay_record_dir : "./",
record_list[replay_record_cnt - cycle_cnt]->d_name);
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
if (record_arg) {
*record_arg = tcase;
} else
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
{
int fd = open(tcase, O_RDONLY);
dup2(fd, 0);
close(fd);
}
}
return --cycle_cnt;
}
#endif // _HAVE_AFL_COMPAT_H

View File

@ -38,18 +38,15 @@
#define SHAPE_BYTES(x) (x + 1)
#define CMP_TYPE_INS 1
#define CMP_TYPE_RTN 2
#define CMP_TYPE_INS 0
#define CMP_TYPE_RTN 1
struct cmp_header {
struct cmp_header { // 16 bit = 2 bytes
unsigned hits : 24;
unsigned id : 24;
unsigned shape : 5;
unsigned type : 2;
unsigned attribute : 4;
unsigned overflow : 1;
unsigned reserved : 4;
unsigned hits : 6; // up to 63 entries, we have CMP_MAP_H = 32
unsigned shape : 5; // 31+1 bytes max
unsigned type : 1; // 2: cmp, rtn
unsigned attribute : 4; // 16 for arithmetic comparison types
} __attribute__((packed));
@ -59,14 +56,17 @@ struct cmp_operands {
u64 v1;
u64 v0_128;
u64 v1_128;
u64 unused;
u8 unused1;
u8 unused2;
} __attribute__((packed));
struct cmpfn_operands {
u8 v0[31];
u8 v0[32];
u8 v0_len;
u8 v1[31];
u8 v1[32];
u8 v1_len;
} __attribute__((packed));

View File

@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++4.10c"
#define VERSION "++4.20a"
/******************************************************
* *
@ -85,6 +85,11 @@
/* Maximum allowed fails per CMP value. Default: 96 */
#define CMPLOG_FAIL_MAX 96
/* Starting timeout (in seconds) for the CMPLOG colorization phase. Upon
multiple timeouts this value will be doubled 4 times each.
So: 60 seconds => 960 seconds max. Good values are 30-120 seconds. */
#define CMPLOG_COLORIZATION_TIME_MAX_START 60ULL
/* -------------------------------------*/
/* Now non-cmplog configuration options */
/* -------------------------------------*/
@ -97,6 +102,11 @@
// #define AFL_PERSISTENT_RECORD
/* Adds support in compiler-rt to replay persistent records in @@-style
* harnesses */
// #define AFL_PERSISTENT_REPLAY_ARGPARSE
/* console output colors: There are three ways to configure its behavior
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect

View File

@ -21,7 +21,7 @@ static char *afl_environment_variables[] = {
"AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER",
"AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW",
"AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME",
"AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE",
"AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE",
"AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY",
"AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_INFO_PROGRAM",
"AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT",
@ -64,6 +64,8 @@ static char *afl_environment_variables[] = {
"AFL_REAL_LD", "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_ALLOWLIST",
"AFL_LLVM_DENYLIST", "AFL_LLVM_BLOCKLIST", "AFL_CMPLOG", "AFL_LLVM_CMPLOG",
"AFL_GCC_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CALLER", "AFL_LLVM_CTX",
"AFL_LLVM_LTO_CALLER", "AFL_LLVM_LTO_CTX", "AFL_LLVM_LTO_CALLER_DEPTH",
"AFL_LLVM_LTO_CTX_DEPTH", "AFL_LLVM_CALLER_DEPTH", "AFL_LLVM_CTX_DEPTH",
"AFL_LLVM_CTX_K", "AFL_LLVM_DICT2FILE", "AFL_LLVM_DICT2FILE_NO_MAIN",
"AFL_LLVM_DOCUMENT_IDS", "AFL_LLVM_INSTRIM_LOOPHEAD", "AFL_LLVM_INSTRUMENT",
"AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY",

738
include/t1ha.h Normal file
View File

@ -0,0 +1,738 @@
/*
* Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com,
* Fast Positive Hash.
*
* Portions Copyright (c) 2010-2020 Leonid Yuriev <leo@yuriev.ru>,
* The 1Hippeus project (t1h).
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* t1ha = { Fast Positive Hash, aka "Позитивный Хэш" }
* by [Positive Technologies](https://www.ptsecurity.ru)
*
* Briefly, it is a 64-bit Hash Function:
* 1. Created for 64-bit little-endian platforms, in predominantly for x86_64,
* but portable and without penalties it can run on any 64-bit CPU.
* 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash
* and all others portable hash-functions (which do not use specific
* hardware tricks).
* 3. Not suitable for cryptography.
*
* The Future will (be) Positive. Всё будет хорошо.
*
* ACKNOWLEDGEMENT:
* The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев)
* for The 1Hippeus project - zerocopy messaging in the spirit of Sparta!
*/
#pragma once
/*****************************************************************************
*
* PLEASE PAY ATTENTION TO THE FOLLOWING NOTES
* about macros definitions which controls t1ha behaviour and/or performance.
*
*
* 1) T1HA_SYS_UNALIGNED_ACCESS = Defines the system/platform/CPU/architecture
* abilities for unaligned data access.
*
* By default, when the T1HA_SYS_UNALIGNED_ACCESS not defined,
* it will defined on the basis hardcoded knowledge about of capabilities
* of most common CPU architectures. But you could override this
* default behavior when build t1ha library itself:
*
* // To disable unaligned access at all.
* #define T1HA_SYS_UNALIGNED_ACCESS 0
*
* // To enable unaligned access, but indicate that it significantly slow.
* #define T1HA_SYS_UNALIGNED_ACCESS 1
*
* // To enable unaligned access, and indicate that it effecient.
* #define T1HA_SYS_UNALIGNED_ACCESS 2
*
*
* 2) T1HA_USE_FAST_ONESHOT_READ = Controls the data reads at the end of buffer.
*
* When defined to non-zero, t1ha will use 'one shot' method for reading
* up to 8 bytes at the end of data. In this case just the one 64-bit read
* will be performed even when the available less than 8 bytes.
*
* This is little bit faster that switching by length of data tail.
* Unfortunately this will triggering a false-positive alarms from Valgrind,
* AddressSanitizer and other similar tool.
*
* By default, t1ha defines it to 1, but you could override this
* default behavior when build t1ha library itself:
*
* // For little bit faster and small code.
* #define T1HA_USE_FAST_ONESHOT_READ 1
*
* // For calmness if doubt.
* #define T1HA_USE_FAST_ONESHOT_READ 0
*
*
* 3) T1HA0_RUNTIME_SELECT = Controls choice fastest function in runtime.
*
* t1ha library offers the t1ha0() function as the fastest for current CPU.
* But actual CPU's features/capabilities and may be significantly different,
* especially on x86 platform. Therefore, internally, t1ha0() may require
* dynamic dispatching for choice best implementation.
*
* By default, t1ha enables such runtime choice and (may be) corresponding
* indirect calls if it reasonable, but you could override this default
* behavior when build t1ha library itself:
*
* // To enable runtime choice of fastest implementation.
* #define T1HA0_RUNTIME_SELECT 1
*
* // To disable runtime choice of fastest implementation.
* #define T1HA0_RUNTIME_SELECT 0
*
* When T1HA0_RUNTIME_SELECT is nonzero the t1ha0_resolve() function could
* be used to get actual t1ha0() implementation address at runtime. This is
* useful for two cases:
* - calling by local pointer-to-function usually is little
* bit faster (less overhead) than via a PLT thru the DSO boundary.
* - GNU Indirect functions (see below) don't supported by environment
* and calling by t1ha0_funcptr is not available and/or expensive.
*
* 4) T1HA_USE_INDIRECT_FUNCTIONS = Controls usage of GNU Indirect functions.
*
* In continue of T1HA0_RUNTIME_SELECT the T1HA_USE_INDIRECT_FUNCTIONS
* controls usage of ELF indirect functions feature. In general, when
* available, this reduces overhead of indirect function's calls though
* a DSO-bundary (https://sourceware.org/glibc/wiki/GNU_IFUNC).
*
* By default, t1ha engage GNU Indirect functions when it available
* and useful, but you could override this default behavior when build
* t1ha library itself:
*
* // To enable use of GNU ELF Indirect functions.
* #define T1HA_USE_INDIRECT_FUNCTIONS 1
*
* // To disable use of GNU ELF Indirect functions. This may be useful
* // if the actual toolchain or the system's loader don't support ones.
* #define T1HA_USE_INDIRECT_FUNCTIONS 0
*
* 5) T1HA0_AESNI_AVAILABLE = Controls AES-NI detection and dispatching on x86.
*
* In continue of T1HA0_RUNTIME_SELECT the T1HA0_AESNI_AVAILABLE controls
* detection and usage of AES-NI CPU's feature. On the other hand, this
* requires compiling parts of t1ha library with certain properly options,
* and could be difficult or inconvenient in some cases.
*
* By default, t1ha engade AES-NI for t1ha0() on the x86 platform, but
* you could override this default behavior when build t1ha library itself:
*
* // To disable detection and usage of AES-NI instructions for t1ha0().
* // This may be useful when you unable to build t1ha library properly
* // or known that AES-NI will be unavailable at the deploy.
* #define T1HA0_AESNI_AVAILABLE 0
*
* // To force detection and usage of AES-NI instructions for t1ha0(),
* // but I don't known reasons to anybody would need this.
* #define T1HA0_AESNI_AVAILABLE 1
*
* 6) T1HA0_DISABLED, T1HA1_DISABLED, T1HA2_DISABLED = Controls availability of
* t1ha functions.
*
* In some cases could be useful to import/use only few of t1ha functions
* or just the one. So, this definitions allows disable corresponding parts
* of t1ha library.
*
* // To disable t1ha0(), t1ha0_32le(), t1ha0_32be() and all AES-NI.
* #define T1HA0_DISABLED
*
* // To disable t1ha1_le() and t1ha1_be().
* #define T1HA1_DISABLED
*
* // To disable t1ha2_atonce(), t1ha2_atonce128() and so on.
* #define T1HA2_DISABLED
*
*****************************************************************************/
#define T1HA_VERSION_MAJOR 2
#define T1HA_VERSION_MINOR 1
#define T1HA_VERSION_RELEASE 1
#ifndef __has_attribute
#define __has_attribute(x) (0)
#endif
#ifndef __has_include
#define __has_include(x) (0)
#endif
#ifndef __GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define __GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
#define __GNUC_PREREQ(maj, min) 0
#endif
#endif /* __GNUC_PREREQ */
#ifndef __CLANG_PREREQ
#ifdef __clang__
#define __CLANG_PREREQ(maj, min) \
((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
#else
#define __CLANG_PREREQ(maj, min) (0)
#endif
#endif /* __CLANG_PREREQ */
#ifndef __LCC_PREREQ
#ifdef __LCC__
#define __LCC_PREREQ(maj, min) \
((__LCC__ << 16) + __LCC_MINOR__ >= ((maj) << 16) + (min))
#else
#define __LCC_PREREQ(maj, min) (0)
#endif
#endif /* __LCC_PREREQ */
/*****************************************************************************/
#ifdef _MSC_VER
/* Avoid '16' bytes padding added after data member 't1ha_context::total'
* and other warnings from std-headers if warning-level > 3. */
#pragma warning(push, 3)
#endif
#if defined(__cplusplus) && __cplusplus >= 201103L
#include <climits>
#include <cstddef>
#include <cstdint>
#else
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#endif
/*****************************************************************************/
#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
defined(i486) || defined(__i486) || defined(__i486__) || \
defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) || \
defined(__i686) || defined(__i686__) || defined(_M_IX86) || \
defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \
defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) || \
defined(__amd64__) || defined(__amd64) || defined(_M_X64) || \
defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
#ifndef __ia32__
/* LY: define neutral __ia32__ for x86 and x86-64 archs */
#define __ia32__ 1
#endif /* __ia32__ */
#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) || \
defined(__amd64) || defined(_M_X64))
/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
#define __amd64__ 1
#endif /* __amd64__ */
#endif /* all x86 */
#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \
!defined(__ORDER_BIG_ENDIAN__)
/* *INDENT-OFF* */
/* clang-format off */
#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID__) || \
defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
#include <endian.h>
#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) || \
defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
#include <machine/endian.h>
#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
#include <sys/isa_defs.h>
#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) || \
(__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
#include <sys/endian.h>
#include <sys/types.h>
#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__NETBSD__) || defined(__NetBSD__) || \
defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
#include <sys/param.h>
#endif /* OS */
/* *INDENT-ON* */
/* clang-format on */
#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
#define __BYTE_ORDER__ __BYTE_ORDER
#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
#define __BYTE_ORDER__ _BYTE_ORDER
#else
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_BIG_ENDIAN__ 4321
#if defined(__LITTLE_ENDIAN__) || \
(defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
defined(__ARMEL__) || defined(__THUMBEL__) || \
defined(__AARCH64EL__) || defined(__MIPSEL__) || defined(_MIPSEL) || \
defined(__MIPSEL) || defined(_M_ARM) || defined(_M_ARM64) || \
defined(__e2k__) || defined(__elbrus_4c__) || \
defined(__elbrus_8c__) || defined(__bfin__) || defined(__BFIN__) || \
defined(__ia64__) || defined(_IA64) || defined(__IA64__) || \
defined(__ia64) || defined(_M_IA64) || defined(__itanium__) || \
defined(__ia32__) || defined(__CYGWIN__) || defined(_WIN64) || \
defined(_WIN32) || defined(__TOS_WIN__) || defined(__WINDOWS__)
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#elif defined(__BIG_ENDIAN__) || \
(defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) || \
defined(__ARMEB__) || defined(__THUMBEB__) || \
defined(__AARCH64EB__) || defined(__MIPSEB__) || defined(_MIPSEB) || \
defined(__MIPSEB) || defined(__m68k__) || defined(M68000) || \
defined(__hppa__) || defined(__hppa) || defined(__HPPA__) || \
defined(__sparc__) || defined(__sparc) || defined(__370__) || \
defined(__THW_370__) || defined(__s390__) || defined(__s390x__) || \
defined(__SYSC_ZARCH__)
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
#else
#error __BYTE_ORDER__ should be defined.
#endif /* Arch */
#endif
#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
/*****************************************************************************/
#ifndef __dll_export
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
#if defined(__GNUC__) || __has_attribute(dllexport)
#define __dll_export __attribute__((dllexport))
#else
#define __dll_export __declspec(dllexport)
#endif
#elif defined(__GNUC__) || __has_attribute(__visibility__)
#define __dll_export __attribute__((__visibility__("default")))
#else
#define __dll_export
#endif
#endif /* __dll_export */
#ifndef __dll_import
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
#if defined(__GNUC__) || __has_attribute(dllimport)
#define __dll_import __attribute__((dllimport))
#else
#define __dll_import __declspec(dllimport)
#endif
#elif defined(__GNUC__) || __has_attribute(__visibility__)
#define __dll_import __attribute__((__visibility__("default")))
#else
#define __dll_import
#endif
#endif /* __dll_import */
#ifndef __force_inline
#ifdef _MSC_VER
#define __force_inline __forceinline
#elif __GNUC_PREREQ(3, 2) || __has_attribute(__always_inline__)
#define __force_inline __inline __attribute__((__always_inline__))
#else
#define __force_inline __inline
#endif
#endif /* __force_inline */
#ifndef T1HA_API
#if defined(t1ha_EXPORTS)
#define T1HA_API __dll_export
#elif defined(t1ha_IMPORTS)
#define T1HA_API __dll_import
#else
#define T1HA_API
#endif
#endif /* T1HA_API */
#if defined(_MSC_VER) && defined(__ia32__)
#define T1HA_ALIGN_PREFIX __declspec(align(32)) /* required only for SIMD */
#else
#define T1HA_ALIGN_PREFIX
#endif /* _MSC_VER */
#if defined(__GNUC__) && defined(__ia32__)
#define T1HA_ALIGN_SUFFIX \
__attribute__((__aligned__(32))) /* required only for SIMD */
#else
#define T1HA_ALIGN_SUFFIX
#endif /* GCC x86 */
#ifndef T1HA_USE_INDIRECT_FUNCTIONS
/* GNU ELF indirect functions usage control. For more info please see
* https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
* and https://sourceware.org/glibc/wiki/GNU_IFUNC */
#if defined(__ELF__) && defined(__amd64__) && \
(__has_attribute(__ifunc__) || \
(!defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && \
!defined(__SANITIZE_ADDRESS__) && !defined(__SSP_ALL__)))
/* Enable gnu_indirect_function by default if :
* - ELF AND x86_64
* - attribute(__ifunc__) is available OR
* GCC >= 4 WITHOUT -fsanitize=address NOR -fstack-protector-all */
#define T1HA_USE_INDIRECT_FUNCTIONS 1
#else
#define T1HA_USE_INDIRECT_FUNCTIONS 0
#endif
#endif /* T1HA_USE_INDIRECT_FUNCTIONS */
#if __GNUC_PREREQ(4, 0)
#pragma GCC visibility push(hidden)
#endif /* __GNUC_PREREQ(4,0) */
#ifdef __cplusplus
extern "C" {
#endif
typedef union T1HA_ALIGN_PREFIX t1ha_state256 {
uint8_t bytes[32];
uint32_t u32[8];
uint64_t u64[4];
struct {
uint64_t a, b, c, d;
} n;
} t1ha_state256_t T1HA_ALIGN_SUFFIX;
typedef struct t1ha_context {
t1ha_state256_t state;
t1ha_state256_t buffer;
size_t partial;
uint64_t total;
} t1ha_context_t;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/******************************************************************************
*
* Self-testing API.
*
* Unfortunately, some compilers (exactly only Microsoft Visual C/C++) has
* a bugs which leads t1ha-functions to produce wrong results. This API allows
* check the correctness of the actual code in runtime.
*
* All check-functions returns 0 on success, or -1 in case the corresponding
* hash-function failed verification. PLEASE, always perform such checking at
* initialization of your code, if you using MSVC or other troubleful compilers.
*/
T1HA_API int t1ha_selfcheck__all_enabled(void);
#ifndef T1HA2_DISABLED
T1HA_API int t1ha_selfcheck__t1ha2_atonce(void);
T1HA_API int t1ha_selfcheck__t1ha2_atonce128(void);
T1HA_API int t1ha_selfcheck__t1ha2_stream(void);
T1HA_API int t1ha_selfcheck__t1ha2(void);
#endif /* T1HA2_DISABLED */
#ifndef T1HA1_DISABLED
T1HA_API int t1ha_selfcheck__t1ha1_le(void);
T1HA_API int t1ha_selfcheck__t1ha1_be(void);
T1HA_API int t1ha_selfcheck__t1ha1(void);
#endif /* T1HA1_DISABLED */
#ifndef T1HA0_DISABLED
T1HA_API int t1ha_selfcheck__t1ha0_32le(void);
T1HA_API int t1ha_selfcheck__t1ha0_32be(void);
T1HA_API int t1ha_selfcheck__t1ha0(void);
/* Define T1HA0_AESNI_AVAILABLE to 0 for disable AES-NI support. */
#ifndef T1HA0_AESNI_AVAILABLE
#if defined(__e2k__) || \
(defined(__ia32__) && (!defined(_M_IX86) || _MSC_VER > 1800))
#define T1HA0_AESNI_AVAILABLE 1
#else
#define T1HA0_AESNI_AVAILABLE 0
#endif
#endif /* ifndef T1HA0_AESNI_AVAILABLE */
#if T1HA0_AESNI_AVAILABLE
T1HA_API int t1ha_selfcheck__t1ha0_ia32aes_noavx(void);
T1HA_API int t1ha_selfcheck__t1ha0_ia32aes_avx(void);
#ifndef __e2k__
T1HA_API int t1ha_selfcheck__t1ha0_ia32aes_avx2(void);
#endif
#endif /* if T1HA0_AESNI_AVAILABLE */
#endif /* T1HA0_DISABLED */
/******************************************************************************
*
* t1ha2 = 64 and 128-bit, SLIGHTLY MORE ATTENTION FOR QUALITY AND STRENGTH.
*
* - The recommended version of "Fast Positive Hash" with good quality
* for checksum, hash tables and fingerprinting.
* - Portable and extremely efficiency on modern 64-bit CPUs.
* Designed for 64-bit little-endian platforms,
* in other cases will runs slowly.
* - Great quality of hashing and still faster than other non-t1ha hashes.
* Provides streaming mode and 128-bit result.
*
* Note: Due performance reason 64- and 128-bit results are completely
* different each other, i.e. 64-bit result is NOT any part of 128-bit.
*/
#ifndef T1HA2_DISABLED
/* The at-once variant with 64-bit result */
T1HA_API uint64_t t1ha2_atonce(const void *data, size_t length, uint64_t seed);
/* The at-once variant with 128-bit result.
* Argument `extra_result` is NOT optional and MUST be valid.
* The high 64-bit part of 128-bit hash will be always unconditionally
* stored to the address given by `extra_result` argument. */
T1HA_API uint64_t t1ha2_atonce128(uint64_t *__restrict extra_result,
const void *__restrict data, size_t length,
uint64_t seed);
/* The init/update/final trinity for streaming.
* Return 64 or 128-bit result depentently from `extra_result` argument. */
T1HA_API void t1ha2_init(t1ha_context_t *ctx, uint64_t seed_x, uint64_t seed_y);
T1HA_API void t1ha2_update(t1ha_context_t *__restrict ctx,
const void *__restrict data, size_t length);
/* Argument `extra_result` is optional and MAY be NULL.
* - If `extra_result` is NOT NULL then the 128-bit hash will be calculated,
* and high 64-bit part of it will be stored to the address given
* by `extra_result` argument.
* - Otherwise the 64-bit hash will be calculated
* and returned from function directly.
*
* Note: Due performance reason 64- and 128-bit results are completely
* different each other, i.e. 64-bit result is NOT any part of 128-bit. */
T1HA_API uint64_t t1ha2_final(t1ha_context_t *__restrict ctx,
uint64_t *__restrict extra_result /* optional */);
#endif /* T1HA2_DISABLED */
/******************************************************************************
*
* t1ha1 = 64-bit, BASELINE FAST PORTABLE HASH:
*
* - Runs faster on 64-bit platforms in other cases may runs slowly.
* - Portable and stable, returns same 64-bit result
* on all architectures and CPUs.
* - Unfortunately it fails the "strict avalanche criteria",
* see test results at https://github.com/demerphq/smhasher.
*
* This flaw is insignificant for the t1ha1() purposes and imperceptible
* from a practical point of view.
* However, nowadays this issue has resolved in the next t1ha2(),
* that was initially planned to providing a bit more quality.
*/
#ifndef T1HA1_DISABLED
/* The little-endian variant. */
T1HA_API uint64_t t1ha1_le(const void *data, size_t length, uint64_t seed);
/* The big-endian variant. */
T1HA_API uint64_t t1ha1_be(const void *data, size_t length, uint64_t seed);
#endif /* T1HA1_DISABLED */
/******************************************************************************
*
* t1ha0 = 64-bit, JUST ONLY FASTER:
*
* - Provides fast-as-possible hashing for current CPU, including
* 32-bit systems and engaging the available hardware acceleration.
* - It is a facade that selects most quick-and-dirty hash
* for the current processor. For instance, on IA32 (x86) actual function
* will be selected in runtime, depending on current CPU capabilities
*
* BE CAREFUL!!! THIS IS MEANS:
*
* 1. The quality of hash is a subject for tradeoffs with performance.
* So, the quality and strength of t1ha0() may be lower than t1ha1(),
* especially on 32-bit targets, but then much faster.
* However, guaranteed that it passes all SMHasher tests.
*
* 2. No warranty that the hash result will be same for particular
* key on another machine or another version of libt1ha.
*
* Briefly, such hash-results and their derivatives, should be
* used only in runtime, but should not be persist or transferred
* over a network.
*
*
* When T1HA0_RUNTIME_SELECT is nonzero the t1ha0_resolve() function could
* be used to get actual t1ha0() implementation address at runtime. This is
* useful for two cases:
* - calling by local pointer-to-function usually is little
* bit faster (less overhead) than via a PLT thru the DSO boundary.
* - GNU Indirect functions (see below) don't supported by environment
* and calling by t1ha0_funcptr is not available and/or expensive.
*/
#ifndef T1HA0_DISABLED
/* The little-endian variant for 32-bit CPU. */
uint64_t t1ha0_32le(const void *data, size_t length, uint64_t seed);
/* The big-endian variant for 32-bit CPU. */
uint64_t t1ha0_32be(const void *data, size_t length, uint64_t seed);
/* Define T1HA0_AESNI_AVAILABLE to 0 for disable AES-NI support. */
#ifndef T1HA0_AESNI_AVAILABLE
#if defined(__e2k__) || \
(defined(__ia32__) && (!defined(_M_IX86) || _MSC_VER > 1800))
#define T1HA0_AESNI_AVAILABLE 1
#else
#define T1HA0_AESNI_AVAILABLE 0
#endif
#endif /* T1HA0_AESNI_AVAILABLE */
/* Define T1HA0_RUNTIME_SELECT to 0 for disable dispatching t1ha0 at runtime.
*/
#ifndef T1HA0_RUNTIME_SELECT
#if T1HA0_AESNI_AVAILABLE && !defined(__e2k__)
#define T1HA0_RUNTIME_SELECT 1
#else
#define T1HA0_RUNTIME_SELECT 0
#endif
#endif /* T1HA0_RUNTIME_SELECT */
#if !T1HA0_RUNTIME_SELECT && !defined(T1HA0_USE_DEFINE)
#if defined(__LCC__)
#define T1HA0_USE_DEFINE 1
#else
#define T1HA0_USE_DEFINE 0
#endif
#endif /* T1HA0_USE_DEFINE */
#if T1HA0_AESNI_AVAILABLE
uint64_t t1ha0_ia32aes_noavx(const void *data, size_t length, uint64_t seed);
uint64_t t1ha0_ia32aes_avx(const void *data, size_t length, uint64_t seed);
#ifndef __e2k__
uint64_t t1ha0_ia32aes_avx2(const void *data, size_t length, uint64_t seed);
#endif
#endif /* T1HA0_AESNI_AVAILABLE */
#if T1HA0_RUNTIME_SELECT
typedef uint64_t (*t1ha0_function_t)(const void *, size_t, uint64_t);
T1HA_API t1ha0_function_t t1ha0_resolve(void);
#if T1HA_USE_INDIRECT_FUNCTIONS
T1HA_API uint64_t t1ha0(const void *data, size_t length, uint64_t seed);
#else
/* Otherwise function pointer will be used.
* Unfortunately this may cause some overhead calling. */
T1HA_API extern uint64_t (*t1ha0_funcptr)(const void *data, size_t length,
uint64_t seed);
static __force_inline uint64_t t1ha0(const void *data, size_t length,
uint64_t seed) {
return t1ha0_funcptr(data, length, seed);
}
#endif /* T1HA_USE_INDIRECT_FUNCTIONS */
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#if T1HA0_USE_DEFINE
#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \
(!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED))
#if defined(T1HA1_DISABLED)
#define t1ha0 t1ha2_atonce
#else
#define t1ha0 t1ha1_be
#endif /* T1HA1_DISABLED */
#else /* 32/64 */
#define t1ha0 t1ha0_32be
#endif /* 32/64 */
#else /* T1HA0_USE_DEFINE */
static __force_inline uint64_t t1ha0(const void *data, size_t length,
uint64_t seed) {
#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \
(!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED))
#if defined(T1HA1_DISABLED)
return t1ha2_atonce(data, length, seed);
#else
return t1ha1_be(data, length, seed);
#endif /* T1HA1_DISABLED */
#else /* 32/64 */
return t1ha0_32be(data, length, seed);
#endif /* 32/64 */
}
#endif /* !T1HA0_USE_DEFINE */
#else /* !T1HA0_RUNTIME_SELECT && __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */
#if T1HA0_USE_DEFINE
#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \
(!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED))
#if defined(T1HA1_DISABLED)
#define t1ha0 t1ha2_atonce
#else
#define t1ha0 t1ha1_le
#endif /* T1HA1_DISABLED */
#else /* 32/64 */
#define t1ha0 t1ha0_32le
#endif /* 32/64 */
#else
static __force_inline uint64_t t1ha0(const void *data, size_t length,
uint64_t seed) {
#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \
(!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED))
#if defined(T1HA1_DISABLED)
return t1ha2_atonce(data, length, seed);
#else
return t1ha1_le(data, length, seed);
#endif /* T1HA1_DISABLED */
#else /* 32/64 */
return t1ha0_32le(data, length, seed);
#endif /* 32/64 */
}
#endif /* !T1HA0_USE_DEFINE */
#endif /* !T1HA0_RUNTIME_SELECT */
#endif /* T1HA0_DISABLED */
#ifdef __cplusplus
}
#endif
#if __GNUC_PREREQ(4, 0)
#pragma GCC visibility pop
#endif /* __GNUC_PREREQ(4,0) */

183
include/t1ha0_ia32aes_b.h Normal file
View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com,
* Fast Positive Hash.
*
* Portions Copyright (c) 2010-2020 Leonid Yuriev <leo@yuriev.ru>,
* The 1Hippeus project (t1h).
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* t1ha = { Fast Positive Hash, aka "Позитивный Хэш" }
* by [Positive Technologies](https://www.ptsecurity.ru)
*
* Briefly, it is a 64-bit Hash Function:
* 1. Created for 64-bit little-endian platforms, in predominantly for x86_64,
* but portable and without penalties it can run on any 64-bit CPU.
* 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash
* and all others portable hash-functions (which do not use specific
* hardware tricks).
* 3. Not suitable for cryptography.
*
* The Future will (be) Positive. Всё будет хорошо.
*
* ACKNOWLEDGEMENT:
* The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев)
* for The 1Hippeus project - zerocopy messaging in the spirit of Sparta!
*/
#include "t1ha_bits.h"
#include "t1ha_selfcheck.h"
#if T1HA0_AESNI_AVAILABLE
uint64_t T1HA_IA32AES_NAME(const void *data, uint32_t len) {
uint64_t a = 0;
uint64_t b = len;
if (likely(len > 32)) {
__m128i x = _mm_set_epi64x(a, b);
__m128i y = _mm_aesenc_si128(x, _mm_set_epi64x(prime_0, prime_1));
const __m128i *v = (const __m128i *)data;
const __m128i *const detent =
(const __m128i *)((const uint8_t *)data + (len & ~15ul));
data = detent;
if (len & 16) {
x = _mm_add_epi64(x, _mm_loadu_si128(v++));
y = _mm_aesenc_si128(x, y);
}
len &= 15;
if (v + 7 < detent) {
__m128i salt = y;
do {
__m128i t = _mm_aesenc_si128(_mm_loadu_si128(v++), salt);
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
t = _mm_aesdec_si128(t, _mm_loadu_si128(v++));
salt = _mm_add_epi64(salt, _mm_set_epi64x(prime_5, prime_6));
t = _mm_aesenc_si128(x, t);
x = _mm_add_epi64(y, x);
y = t;
} while (v + 7 < detent);
}
while (v < detent) {
__m128i v0y = _mm_add_epi64(y, _mm_loadu_si128(v++));
__m128i v1x = _mm_sub_epi64(x, _mm_loadu_si128(v++));
x = _mm_aesdec_si128(x, v0y);
y = _mm_aesdec_si128(y, v1x);
}
x = _mm_add_epi64(_mm_aesdec_si128(x, _mm_aesenc_si128(y, x)), y);
#if defined(__x86_64__) || defined(_M_X64)
#if defined(__SSE4_1__) || defined(__AVX__)
a = _mm_extract_epi64(x, 0);
b = _mm_extract_epi64(x, 1);
#else
a = _mm_cvtsi128_si64(x);
b = _mm_cvtsi128_si64(_mm_unpackhi_epi64(x, x));
#endif
#else
#if defined(__SSE4_1__) || defined(__AVX__)
a = (uint32_t)_mm_extract_epi32(x, 0) | (uint64_t)_mm_extract_epi32(x, 1)
<< 32;
b = (uint32_t)_mm_extract_epi32(x, 2) | (uint64_t)_mm_extract_epi32(x, 3)
<< 32;
#else
a = (uint32_t)_mm_cvtsi128_si32(x);
a |= (uint64_t)_mm_cvtsi128_si32(_mm_shuffle_epi32(x, 1)) << 32;
x = _mm_unpackhi_epi64(x, x);
b = (uint32_t)_mm_cvtsi128_si32(x);
b |= (uint64_t)_mm_cvtsi128_si32(_mm_shuffle_epi32(x, 1)) << 32;
#endif
#endif
#ifdef __AVX__
_mm256_zeroupper();
#elif !(defined(_X86_64_) || defined(__x86_64__) || defined(_M_X64) || \
defined(__e2k__))
_mm_empty();
#endif
}
const uint64_t *v = (const uint64_t *)data;
switch (len) {
default:
mixup64(&a, &b, fetch64_le_unaligned(v++), prime_4);
/* fall through */
case 24:
case 23:
case 22:
case 21:
case 20:
case 19:
case 18:
case 17:
mixup64(&b, &a, fetch64_le_unaligned(v++), prime_3);
/* fall through */
case 16:
case 15:
case 14:
case 13:
case 12:
case 11:
case 10:
case 9:
mixup64(&a, &b, fetch64_le_unaligned(v++), prime_2);
/* fall through */
case 8:
case 7:
case 6:
case 5:
case 4:
case 3:
case 2:
case 1:
mixup64(&b, &a, tail64_le_unaligned(v, len), prime_1);
/* fall through */
case 0:
return final64(a, b);
}
}
#endif /* T1HA0_AESNI_AVAILABLE */
#undef T1HA_IA32AES_NAME

1422
include/t1ha_bits.h Normal file

File diff suppressed because it is too large Load Diff

77
include/t1ha_selfcheck.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com,
* Fast Positive Hash.
*
* Portions Copyright (c) 2010-2020 Leonid Yuriev <leo@yuriev.ru>,
* The 1Hippeus project (t1h).
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* t1ha = { Fast Positive Hash, aka "Позитивный Хэш" }
* by [Positive Technologies](https://www.ptsecurity.ru)
*
* Briefly, it is a 64-bit Hash Function:
* 1. Created for 64-bit little-endian platforms, in predominantly for x86_64,
* but portable and without penalties it can run on any 64-bit CPU.
* 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash
* and all others portable hash-functions (which do not use specific
* hardware tricks).
* 3. Not suitable for cryptography.
*
* The Future will (be) Positive. Всё будет хорошо.
*
* ACKNOWLEDGEMENT:
* The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев)
* for The 1Hippeus project - zerocopy messaging in the spirit of Sparta!
*/
#pragma once
#if defined(_MSC_VER) && _MSC_VER > 1800
#pragma warning(disable : 4464) /* relative include path contains '..' */
#endif /* MSVC */
#include "t1ha.h"
/***************************************************************************/
/* Self-checking */
extern const uint8_t t1ha_test_pattern[64];
int t1ha_selfcheck(uint64_t (*hash)(const void *, size_t, uint64_t),
const uint64_t *reference_values);
#ifndef T1HA2_DISABLED
extern const uint64_t t1ha_refval_2atonce[81];
extern const uint64_t t1ha_refval_2atonce128[81];
extern const uint64_t t1ha_refval_2stream[81];
extern const uint64_t t1ha_refval_2stream128[81];
#endif /* T1HA2_DISABLED */
#ifndef T1HA1_DISABLED
extern const uint64_t t1ha_refval_64le[81];
extern const uint64_t t1ha_refval_64be[81];
#endif /* T1HA1_DISABLED */
#ifndef T1HA0_DISABLED
extern const uint64_t t1ha_refval_32le[81];
extern const uint64_t t1ha_refval_32be[81];
#if T1HA0_AESNI_AVAILABLE
extern const uint64_t t1ha_refval_ia32aes_a[81];
extern const uint64_t t1ha_refval_ia32aes_b[81];
#endif /* T1HA0_AESNI_AVAILABLE */
#endif /* T1HA0_DISABLED */

View File

@ -49,6 +49,14 @@ typedef uint128_t u128;
#define FS_ERROR_OLD_CMPLOG 32
#define FS_ERROR_OLD_CMPLOG_QEMU 64
/* New Forkserver */
#define FS_NEW_VERSION_MIN 1
#define FS_NEW_VERSION_MAX 1
#define FS_NEW_ERROR 0xeffe0000
#define FS_NEW_OPT_MAPSIZE 0x00000001 // parameter: 32 bit value
#define FS_NEW_OPT_SHDMEM_FUZZ 0x00000002 // parameter: none
#define FS_NEW_OPT_AUTODICT 0x00000800 // autodictionary data
/* Reporting options */
#define FS_OPT_ENABLED 0x80000001
#define FS_OPT_MAPSIZE 0x40000000

File diff suppressed because it is too large Load Diff

View File

@ -195,4 +195,34 @@ Then as first line after the `__AFL_LOOP` while loop:
int len = __AFL_FUZZ_TESTCASE_LEN;
```
And that is all!
And that is all!
## 6) Persistent record, and replay
If your software under test requires keeping a state between persistent loop iterations (i.e., a stateful network stack), you can use the `AFL_PERSISTENT_RECORD` variable as described in the [environment variables documentation](../docs/env_variables.md).
When `AFL_PERSISTENT_RECORD` is enabled, replay functionality is also included in the compiler-rt library. To replay a specific record, assign the record number to the AFL_PERSISTENT_REPLAY environment variable (i.e., `RECORD:XXXXX`` -> `AFL_PERSISTENT_REPLAY=XXXXX`), and run the test binary as you would normally do.
The directory where the record files live can be specified via the `AFL_PERSISTENT_DIR` environment varilable, otherwise by default it will be considered the current directory (`./`).
If your harness reads the input files from arguments using the special `@@` argument you will need to include support by enabling `AFL_PERSISTENT_ARGPARSE` in `config.h`.
In order to offer transparent support to harnesses using the `@@` command line argument, arguments are parsed by the `__afl_record_replay_init` init function. Since not all systems support passing arguments to initializers, this functionality is disabled by default, it's recommendable to use the `__AFL_FUZZ_TESTCASE_BUF/__AFL_FUZZ_TESTCASE_LEN` shared memory mechanism instead.
## 7) Drop-in persistent loop replay replacement
To use the replay functionality without having to use `afl-cc`, include the [include/record_compat.h](../include/afl-record_compat.h) header file. Together with the [include/afl-persistent-replay.h](../include/afl-persistent-replay.h) header included in it, `afl-record-compat.h` provides a drop-in replacement for the persistent loop mechanism.
```c
#ifndef __AFL_FUZZ_TESTCASE_LEN
// #define AFL_PERSISTENT_REPLAY_ARGPARSE
#include "afl-record-compat.h"
#endif
__AFL_FUZZ_INIT();
```
A simple example is provided in [persistent_demo_replay.c](../utils/replay_record/persistent_demo_replay.c).
Be aware that the [afl-record-compat.h](../include/afl-record-compat.h) header should only be included in a single compilation unit, or you will end up with clobbered functions and variables.
If you need a cleaner solution, you'll have to move the functions and variables defined in [include/record_compat.h](../include/afl-record-compat.h) and [include/afl-persistent-replay.h](../include/afl-persistent-replay.h) in a C file, and add the relevant declarations to a header file. After including the new header file, the compilation unit resulting from compiling the C file can then be linked with your program.

File diff suppressed because it is too large Load Diff

View File

@ -87,6 +87,10 @@ __attribute__((weak)) void __sanitizer_symbolize_pc(void *, const char *fmt,
#include <sys/mman.h>
#include <fcntl.h>
#ifdef AFL_PERSISTENT_RECORD
#include "afl-persistent-replay.h"
#endif
/* Globals needed by the injected instrumentation. The __afl_area_initial region
is used for instrumentation output before __afl_map_shm() has a chance to
run. It will end up as .comm, so it shouldn't be too wasteful. */
@ -186,6 +190,8 @@ __thread u32 __afl_prev_ctx;
struct cmp_map *__afl_cmp_map;
struct cmp_map *__afl_cmp_map_backup;
static u8 __afl_cmplog_max_len = 32; // 16-32
/* Child pid? */
static s32 child_pid;
@ -264,7 +270,7 @@ static void send_forkserver_error(int error) {
u32 status;
if (!error || error > 0xffff) return;
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
status = (FS_NEW_ERROR | error);
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; }
}
@ -367,32 +373,13 @@ static void __afl_map_shm(void) {
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); }
if (val < __afl_final_loc) {
if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) {
if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) {
if (!getenv("AFL_QUIET"))
fprintf(stderr,
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u "
"to be able to run this instrumented program!\n",
__afl_final_loc);
if (id_str) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
exit(-1);
}
} else {
if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) {
fprintf(stderr,
"Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u "
"to be able to run this instrumented program if this "
"crashes!\n",
__afl_final_loc);
}
fprintf(stderr,
"Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u "
"to be able to run this instrumented program if this "
"crashes!\n",
__afl_final_loc);
}
@ -400,15 +387,6 @@ static void __afl_map_shm(void) {
}
} else {
if (getenv("AFL_DUMP_MAP_SIZE")) {
printf("%u\n", MAP_SIZE);
exit(-1);
}
}
if (__afl_sharedmem_fuzzing && (!id_str || !getenv(SHM_FUZZ_ENV_VAR) ||
@ -474,14 +452,13 @@ static void __afl_map_shm(void) {
if (__afl_debug) {
fprintf(
stderr,
"DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, "
"__afl_final_loc %u, __afl_map_size %u, max_size_forkserver %u/0x%x\n",
id_str == NULL ? "<null>" : id_str, __afl_area_ptr, __afl_area_initial,
__afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, __afl_final_loc,
__afl_map_size, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
fprintf(stderr,
"DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, "
"__afl_final_loc %u, __afl_map_size %u\n",
id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
__afl_final_loc, __afl_map_size);
}
@ -639,12 +616,10 @@ static void __afl_map_shm(void) {
fprintf(stderr,
"DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE "
"%u, __afl_final_loc %u, __afl_map_size %u, "
"max_size_forkserver %u/0x%x\n",
"%u, __afl_final_loc %u, __afl_map_size %u",
id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
__afl_final_loc, __afl_map_size, FS_OPT_MAX_MAPSIZE,
FS_OPT_MAX_MAPSIZE);
__afl_final_loc, __afl_map_size);
}
@ -761,6 +736,19 @@ static void __afl_map_shm(void) {
#endif // __AFL_CODE_COVERAGE
if (!__afl_cmp_map && getenv("AFL_CMPLOG_DEBUG")) {
__afl_cmp_map_backup = __afl_cmp_map = malloc(sizeof(struct cmp_map));
}
if (getenv("AFL_CMPLOG_MAX_LEN")) {
int tmp = atoi(getenv("AFL_CMPLOG_MAX_LEN"));
if (tmp >= 16 && tmp <= 32) { __afl_cmplog_max_len = tmp; }
}
}
/* unmap SHM. */
@ -855,242 +843,6 @@ void write_error_with_location(char *text, char *filename, int linenumber) {
}
#ifdef __linux__
static void __afl_start_snapshots(void) {
static u8 tmp[4] = {0, 0, 0, 0};
u32 status = 0;
u32 already_read_first = 0;
u32 was_killed;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
/* 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. */
status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT | FS_OPT_NEWCMPLOG);
if (__afl_sharedmem_fuzzing) { status |= FS_OPT_SHDMEM_FUZZ; }
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (__afl_dictionary_len && __afl_dictionary) { status |= FS_OPT_AUTODICT; }
memcpy(tmp, &status, 4);
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
write_error("read to afl-fuzz");
_exit(1);
}
if (__afl_debug) {
fprintf(stderr, "DEBUG: target forkserver recv: %08x\n", was_killed);
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
__afl_map_shm_fuzz();
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
(FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
__afl_dictionary_len && __afl_dictionary) {
// great lets pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
s32 ret;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1);
}
while (len != 0) {
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
if (ret < 1) {
write(2, "Error: could not send dictionary\n",
strlen("Error: could not send dictionary\n"));
_exit(1);
}
len -= ret;
offset += ret;
}
} else {
// uh this forkserver does not understand extended option passing
// or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1;
}
}
while (1) {
int status;
if (already_read_first) {
already_read_first = 0;
} else {
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
write_error("reading from afl-fuzz");
_exit(1);
}
}
#ifdef _AFL_DOCUMENT_MUTATIONS
if (__afl_fuzz_ptr) {
static uint32_t counter = 0;
char fn[32];
sprintf(fn, "%09u:forkserver", counter);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd_doc >= 0) {
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
fprintf(stderr, "write of mutation file failed: %s\n", fn);
unlink(fn);
}
close(fd_doc);
}
counter++;
}
#endif
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old
process. */
if (child_stopped && was_killed) {
child_stopped = 0;
if (waitpid(child_pid, &status, 0) < 0) {
write_error("child_stopped && was_killed");
_exit(1); // TODO why exit?
}
}
if (!child_stopped) {
/* Once woken up, create a clone of our process. */
child_pid = fork();
if (child_pid < 0) {
write_error("fork");
_exit(1);
}
/* In child process: close fds, resume execution. */
if (!child_pid) {
//(void)nice(-20); // does not seem to improve
signal(SIGCHLD, old_sigchld_handler);
signal(SIGTERM, old_sigterm_handler);
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS |
AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) {
raise(SIGSTOP);
}
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
return;
}
} else {
/* Special handling for persistent mode: if the child is alive but
currently stopped, simply restart it with SIGCONT. */
kill(child_pid, SIGCONT);
child_stopped = 0;
}
/* In parent process: write PID to pipe, then wait for child. */
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
write_error("write to afl-fuzz");
_exit(1);
}
if (waitpid(child_pid, &status, WUNTRACED) < 0) {
write_error("waitpid");
_exit(1);
}
/* In persistent mode, the child stops itself with SIGSTOP to indicate
a successful run. In this case, we want to wake it up without forking
again. */
if (WIFSTOPPED(status)) child_stopped = 1;
/* Relay wait status to pipe, then loop back. */
if (write(FORKSRV_FD + 1, &status, 4) != 4) {
write_error("writing to afl-fuzz");
_exit(1);
}
}
}
#endif
/* Fork server logic. */
static void __afl_start_forkserver(void) {
@ -1103,114 +855,93 @@ static void __afl_start_forkserver(void) {
old_sigterm_handler = orig_action.sa_handler;
signal(SIGTERM, at_exit);
#ifdef __linux__
if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
afl_snapshot_init() >= 0) {
__afl_start_snapshots();
return;
}
#endif
u8 tmp[4] = {0, 0, 0, 0};
u32 status_for_fsrv = 0;
u32 already_read_first = 0;
u32 was_killed;
u32 version = 0x41464c00 + FS_NEW_VERSION_MAX;
u32 tmp = version ^ 0xffffffff, status2, status = version;
u8 *msg = (u8 *)&status;
u8 *reply = (u8 *)&status2;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) {
status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
}
if (__afl_dictionary_len && __afl_dictionary) {
status_for_fsrv |= FS_OPT_AUTODICT;
}
if (__afl_sharedmem_fuzzing) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
if (status_for_fsrv) {
status_for_fsrv |= (FS_OPT_ENABLED | FS_OPT_NEWCMPLOG);
}
memcpy(tmp, &status_for_fsrv, 4);
/* 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. */
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
// return because possible non-forkserver usage
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
__afl_connected = 1;
if (read(FORKSRV_FD, reply, 4) != 4) { _exit(1); }
if (tmp != status2) {
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
write_error("wrong forkserver message from AFL++ tool");
_exit(1);
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
}
if (__afl_debug) {
// send the set/requested options to forkserver
status = FS_NEW_OPT_MAPSIZE; // we always send the map size
if (__afl_sharedmem_fuzzing) { status |= FS_NEW_OPT_SHDMEM_FUZZ; }
if (__afl_dictionary_len && __afl_dictionary) {
fprintf(stderr, "DEBUG: target forkserver recv: %08x\n", was_killed);
status |= FS_NEW_OPT_AUTODICT;
}
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// Now send the parameters for the set options, increasing by option number
// FS_NEW_OPT_MAPSIZE - we always send the map size
status = __afl_map_size;
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// FS_NEW_OPT_SHDMEM_FUZZ - no data
// FS_NEW_OPT_AUTODICT - send autodictionary
if (__afl_dictionary_len && __afl_dictionary) {
// pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1);
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
while (len != 0) {
__afl_map_shm_fuzz();
s32 ret;
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
}
if (ret < 1) {
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
(FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
__afl_dictionary_len && __afl_dictionary) {
// great lets pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
write_error("could not send dictionary");
_exit(1);
}
while (len != 0) {
s32 ret;
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
if (ret < 1) {
write(2, "Error: could not send dictionary\n",
strlen("Error: could not send dictionary\n"));
_exit(1);
}
len -= ret;
offset += ret;
}
} else {
// uh this forkserver does not understand extended option passing
// or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1;
len -= ret;
offset += ret;
}
}
// send welcome message as final message
status = version;
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// END forkserver handshake
__afl_connected = 1;
if (__afl_sharedmem_fuzzing) { __afl_map_shm_fuzz(); }
while (1) {
int status;
@ -1225,7 +956,7 @@ static void __afl_start_forkserver(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
// write_error("read from afl-fuzz");
write_error("read from AFL++ tool");
_exit(1);
}
@ -1354,6 +1085,10 @@ int __afl_persistent_loop(unsigned int max_cnt) {
static u8 first_pass = 1;
static u32 cycle_cnt;
#ifdef AFL_PERSISTENT_RECORD
char tcase[PATH_MAX];
#endif
if (first_pass) {
/* Make sure that every iteration of __AFL_LOOP() starts with a clean slate.
@ -1365,14 +1100,59 @@ int __afl_persistent_loop(unsigned int max_cnt) {
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
cycle_cnt = max_cnt;
first_pass = 0;
__afl_selective_coverage_temp = 1;
#ifdef AFL_PERSISTENT_RECORD
if (unlikely(is_replay_record)) {
cycle_cnt = replay_record_cnt;
goto persistent_record;
} else
#endif
{
cycle_cnt = max_cnt;
}
return 1;
} else if (--cycle_cnt) {
#ifdef AFL_PERSISTENT_RECORD
if (unlikely(is_replay_record)) {
persistent_record:
snprintf(tcase, PATH_MAX, "%s/%s",
replay_record_dir ? replay_record_dir : "./",
record_list[replay_record_cnt - cycle_cnt]->d_name);
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
if (unlikely(record_arg)) {
*record_arg = tcase;
} else
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
{
int fd = open(tcase, O_RDONLY);
dup2(fd, 0);
close(fd);
}
return 1;
}
#endif
raise(SIGSTOP);
__afl_area_ptr[0] = 1;
@ -2181,7 +1961,8 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) {
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) {
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2219,7 +2000,8 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr) {
// fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr);
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2257,7 +2039,8 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) {
// fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr);
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2300,7 +2083,8 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr,
// (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1,
// attr);
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2 || size > __afl_cmplog_max_len)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2344,6 +2128,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr,
void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) {
if (likely(!__afl_cmp_map)) return;
if (16 > __afl_cmplog_max_len) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2537,13 +2322,25 @@ void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u64 len) {
// fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
if (likely(!__afl_cmp_map)) return;
if (unlikely(!len)) return;
int len0 = MIN(len, 31);
if (unlikely(!len || len > __afl_cmplog_max_len)) return;
int len0 = MIN(len, 32);
int len1 = strnlen(ptr1, len0);
if (len1 < 31) len1 = area_is_valid(ptr1, len1 + 1);
if (len1 <= 32) len1 = area_is_valid(ptr1, len1 + 1);
if (len1 > __afl_cmplog_max_len) len1 = 0;
int len2 = strnlen(ptr2, len0);
if (len2 < 31) len2 = area_is_valid(ptr2, len2 + 1);
int l = MAX(len1, len2);
if (len2 <= 32) len2 = area_is_valid(ptr2, len2 + 1);
if (len2 > __afl_cmplog_max_len) len2 = 0;
int l;
if (!len1)
l = len2;
else if (!len2)
l = len1;
else
l = MAX(len1, len2);
if (l < 2) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
@ -2587,10 +2384,18 @@ void __cmplog_rtn_hook_str(u8 *ptr1, u8 *ptr2) {
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
if (likely(!__afl_cmp_map)) return;
if (unlikely(!ptr1 || !ptr2)) return;
int len1 = strnlen(ptr1, 30) + 1;
int len2 = strnlen(ptr2, 30) + 1;
int l = MAX(len1, len2);
if (l < 3) return;
int len1 = strnlen(ptr1, 31) + 1;
int len2 = strnlen(ptr2, 31) + 1;
if (len1 > __afl_cmplog_max_len) len1 = 0;
if (len2 > __afl_cmplog_max_len) len2 = 0;
int l;
if (!len1)
l = len2;
else if (!len2)
l = len1;
else
l = MAX(len1, len2);
if (l < 2) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2632,7 +2437,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
/*
u32 i;
if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return;
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn arg0=");
for (i = 0; i < 32; i++)
fprintf(stderr, "%02x", ptr1[i]);
@ -2645,10 +2450,10 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
if (likely(!__afl_cmp_map)) return;
int l1, l2;
if ((l1 = area_is_valid(ptr1, 31)) <= 0 ||
(l2 = area_is_valid(ptr2, 31)) <= 0)
if ((l1 = area_is_valid(ptr1, 32)) <= 0 ||
(l2 = area_is_valid(ptr2, 32)) <= 0)
return;
int len = MIN(31, MIN(l1, l2));
int len = MIN(__afl_cmplog_max_len, MIN(l1, l2));
// fprintf(stderr, "RTN2 %u\n", len);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
@ -2697,7 +2502,7 @@ void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) {
#if 0
/*
u32 i;
if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return;
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn_n len=%u arg0=", len);
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr1[i]);
@ -2709,12 +2514,15 @@ void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) {
// fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
if (likely(!__afl_cmp_map)) return;
if (unlikely(!len)) return;
int l = MIN(31, len);
if (!len) return;
int l = MIN(32, len), l1, l2;
if ((l = area_is_valid(ptr1, l)) <= 0 || (l = area_is_valid(ptr2, l)) <= 0)
if ((l1 = area_is_valid(ptr1, l)) <= 0 || (l2 = area_is_valid(ptr2, l)) <= 0)
return;
len = MIN(l1, l2);
if (len > __afl_cmplog_max_len) return;
// fprintf(stderr, "RTN2 %u\n", l);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));

View File

@ -1 +1 @@
e63c9af193
40033af00c

View File

@ -828,7 +828,7 @@ static void instrument_mode_old_environ(aflcc_state_t *aflcc) {
}
if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
if (getenv("AFL_LLVM_CALLER"))
if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_LTO_CALLER") || getenv("AFL_LLVM_LTO_CTX"))
aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
if (getenv("AFL_LLVM_NGRAM_SIZE")) {
@ -1148,12 +1148,16 @@ static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) {
}
if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM)
if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM &&
!((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
aflcc->compiler_mode == LTO))
FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
if (aflcc->instrument_opt_mode &&
aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
aflcc->instrument_mode != INSTRUMENT_CLASSIC)
aflcc->instrument_mode != INSTRUMENT_CLASSIC &&
!(aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER &&
aflcc->compiler_mode == LTO))
FATAL(
"CALLER, CTX and NGRAM instrumentation options can only be used with "
"the LLVM CLASSIC instrumentation mode.");
@ -2917,11 +2921,12 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
" AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
"functions\n"
" into this file (LTO mode)\n"
" AFL_LLVM_LTO_CALLER: activate CALLER/CTX instrumentation\n"
" AFL_LLVM_LTO_CALLER_DEPTH: skip how many empty functions\n"
" AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
"global var\n"
" AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
"a "
"bb\n"
"a bb\n"
" AFL_REAL_LD: use this lld linker instead of the compiled in "
"path\n"
" AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "

View File

@ -389,7 +389,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
while (1) {
uint32_t was_killed;
int status;
u32 status;
/* Wait for parent by reading from the pipe. Exit if read fails. */
@ -524,7 +524,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output) {
int st_pipe[2], ctl_pipe[2];
s32 status;
u32 status;
s32 rlen;
char *ignore_autodict = getenv("AFL_NO_AUTODICT");
@ -1017,83 +1017,68 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (rlen == 4) {
/*
* The new fork server model works like this:
* Client: sends "AFLx" in little endian, with x being the forkserver
* protocol version.
* Server: replies with XOR of the message or exits with an error if it
* is not a supported version.
* Client: sends 32 bit of options and then sends all parameters of
* the options, one after another, increasing by option number.
* Ends with "AFLx".
* After the initial protocol version confirmation the server does not
* send any data anymore - except a future option requires this.
*/
if ((status & FS_NEW_ERROR) == FS_NEW_ERROR) {
report_error_and_exit(status & 0x0000ffff);
}
if (status >= 0x41464c00 && status <= 0x41464cff) {
FATAL(
"Target uses the new forkserver model, you need to switch to a newer "
"afl-fuzz too!");
u32 version = status - 0x41464c00;
}
if (!version) {
if (!be_quiet) { OKF("All right - fork server is up."); }
FATAL(
"Fork server version is not assigned, this should not happen. "
"Recompile target.");
if (getenv("AFL_DEBUG")) {
} else if (version < FS_NEW_VERSION_MIN || version > FS_NEW_VERSION_MAX) {
ACTF("Extended forkserver functions received (%08x).", status);
}
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
// workaround for recent AFL++ versions
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
status = (status & 0xf0ffffff);
if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
if (fsrv->qemu_mode || fsrv->frida_mode) {
report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
} else {
report_error_and_exit(FS_ERROR_OLD_CMPLOG);
}
FATAL(
"Fork server version is not not supported. Recompile the target.");
}
if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
u32 keep = status;
status ^= 0xffffffff;
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
fsrv->snapshot = 1;
if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
FATAL("Writing to forkserver failed.");
}
if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
if (!be_quiet) {
if (fsrv->support_shmem_fuzz) {
fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
}
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
}
OKF("All right - new fork server model v%u is up.", version);
}
if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
rlen = read(fsrv->fsrv_st_fd, &status, 4);
u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
if (getenv("AFL_DEBUG")) {
ACTF("Forkserver options received: (0x%08x)", status);
}
if ((status & FS_NEW_OPT_MAPSIZE)) {
u32 tmp_map_size;
rlen = read(fsrv->fsrv_st_fd, &tmp_map_size, 4);
if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
@ -1110,7 +1095,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
FATAL(
"Target's coverage map size of %u is larger than the one this "
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and "
"restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
@ -1119,22 +1105,250 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
fsrv->map_size = tmp_map_size;
} else {
fsrv->real_map_size = fsrv->map_size = MAP_SIZE;
}
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
if ((status & FS_NEW_OPT_SHDMEM_FUZZ)) {
if (!ignore_autodict) {
if (fsrv->support_shmem_fuzz) {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
}
}
if ((status & FS_NEW_OPT_AUTODICT)) {
u32 dict_size;
if (read(fsrv->fsrv_st_fd, &dict_size, 4) != 4) {
FATAL("Reading from forkserver failed.");
}
if (dict_size < 2 || dict_size > 0xffffff) {
FATAL("Dictionary has an illegal size: %d", dict_size);
}
u32 offset = 0, count = 0;
u8 *dict = ck_alloc(dict_size);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory",
dict_size);
}
while (dict_size != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size);
if (rlen > 0) {
dict_size -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, dict_size);
}
}
offset = 0;
while (offset < dict_size && (u8)dict[offset] + offset < dict_size) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
}
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
}
u32 status2;
rlen = read(fsrv->fsrv_st_fd, &status2, 4);
if (status2 != keep) {
FATAL("Error in forkserver communication (%08x=>%08x)", keep, status2);
}
} else {
if (!fsrv->qemu_mode && !fsrv->cs_mode
#ifdef __linux__
&& !fsrv->nyx_mode
#endif
) {
WARNF(
"Old fork server model is used by the target, this still works "
"though.");
}
if (!be_quiet) { OKF("All right - old fork server is up."); }
if (getenv("AFL_DEBUG")) {
ACTF("Extended forkserver functions received (%08x).", status);
}
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if (fsrv->cmplog_binary && !fsrv->qemu_mode) {
FATAL("Target was compiled with outdated CMPLOG, recompile it!\n");
}
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
// workaround for recent AFL++ versions
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) ==
FS_OPT_OLD_AFLPP_WORKAROUND)
status = (status & 0xf0ffffff);
if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
if (fsrv->qemu_mode || fsrv->frida_mode) {
report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
} else {
report_error_and_exit(FS_ERROR_OLD_CMPLOG);
}
}
if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
fsrv->snapshot = 1;
if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
}
if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
if (fsrv->support_shmem_fuzz) {
fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
}
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
}
}
if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
fsrv->real_map_size = tmp_map_size;
if (tmp_map_size % 64) {
tmp_map_size = (((tmp_map_size + 63) >> 6) << 6);
}
if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
if (tmp_map_size > fsrv->map_size) {
FATAL(
"Target's coverage map size of %u is larger than the one this "
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and "
"restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
}
fsrv->map_size = tmp_map_size;
}
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
if (!ignore_autodict) {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED);
}
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
return;
}
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED);
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
}
@ -1144,82 +1358,63 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
return;
if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
}
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
}
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
FATAL("Reading from forkserver failed.");
}
if (status < 2 || (u32)status > 0xffffff) {
FATAL("Dictionary has an illegal size: %d", status);
}
u32 offset = 0, count = 0;
u32 len = status;
u8 *dict = ck_alloc(len);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory", len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
if (rlen > 0) {
len -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
FATAL("Reading from forkserver failed.");
}
}
if (status < 2 || (u32)status > 0xffffff) {
offset = 0;
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
FATAL("Dictionary has an illegal size: %d", status);
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
}
u32 offset = 0, count = 0;
u32 len = status;
u8 *dict = ck_alloc(len);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory",
len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
if (rlen > 0) {
len -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
}
}
offset = 0;
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
}
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
}
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
}
}
@ -1599,6 +1794,11 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
u32 exec_ms;
u32 write_value = fsrv->last_run_timed_out;
#ifdef AFL_PERSISTENT_RECORD
fsrv_run_result_t retval = FSRV_RUN_OK;
char *persistent_out_fmt;
#endif
#ifdef __linux__
if (fsrv->nyx_mode) {
@ -1798,6 +1998,18 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (unlikely(fsrv->last_run_timed_out)) {
fsrv->last_kill_signal = fsrv->child_kill_signal;
#ifdef AFL_PERSISTENT_RECORD
if (unlikely(fsrv->persistent_record)) {
retval = FSRV_RUN_TMOUT;
persistent_out_fmt = "%s/hangs/RECORD:%06u,cnt:%06u";
goto store_persistent_record;
}
#endif
return FSRV_RUN_TMOUT;
}
@ -1819,42 +2031,21 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
(fsrv->uses_crash_exitcode &&
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
/* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
fsrv->last_kill_signal =
WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
#ifdef AFL_PERSISTENT_RECORD
if (unlikely(fsrv->persistent_record)) {
char fn[PATH_MAX];
u32 i, writecnt = 0;
for (i = 0; i < fsrv->persistent_record; ++i) {
u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
u8 *data = fsrv->persistent_record_data[entry];
u32 len = fsrv->persistent_record_len[entry];
if (likely(len && data)) {
snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
writecnt++);
int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd >= 0) {
ck_write(fd, data, len, fn);
close(fd);
}
}
}
++fsrv->persistent_record_cnt;
retval = FSRV_RUN_CRASH;
persistent_out_fmt = "%s/crashes/RECORD:%06u,cnt:%06u";
goto store_persistent_record;
}
#endif
/* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
fsrv->last_kill_signal =
WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
return FSRV_RUN_CRASH;
}
@ -1862,6 +2053,40 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
/* success :) */
return FSRV_RUN_OK;
#ifdef AFL_PERSISTENT_RECORD
store_persistent_record: {
char fn[PATH_MAX];
u32 i, writecnt = 0;
for (i = 0; i < fsrv->persistent_record; ++i) {
u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
u8 *data = fsrv->persistent_record_data[entry];
u32 len = fsrv->persistent_record_len[entry];
if (likely(len && data)) {
snprintf(fn, sizeof(fn), persistent_out_fmt, fsrv->persistent_record_dir,
fsrv->persistent_record_cnt, writecnt++);
int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd >= 0) {
ck_write(fd, data, len, fn);
close(fd);
}
}
}
++fsrv->persistent_record_cnt;
return retval;
}
#endif
}
void afl_fsrv_killall() {

View File

@ -1921,6 +1921,9 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
#ifdef AFL_PERSISTENT_RECORD
delete_files(fn, RECORD_PREFIX);
#endif
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
ck_free(fn);
@ -1953,6 +1956,9 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
#ifdef AFL_PERSISTENT_RECORD
delete_files(fn, RECORD_PREFIX);
#endif
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
ck_free(fn);

View File

@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 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.
@ -29,6 +29,7 @@
#include "cmplog.h"
// #define _DEBUG
// #define USE_HASHMAP
// #define CMPLOG_INTROSPECTION
// CMP attribute enum
@ -87,6 +88,13 @@ static u32 hshape;
static u64 screen_update;
static u64 last_update;
#ifdef USE_HASHMAP
// hashmap functions
void hashmap_reset();
bool hashmap_search_and_add(uint8_t type, uint64_t key);
bool hashmap_search_and_add_ptr(uint8_t type, u8 *key);
#endif
static struct range *add_range(struct range *ranges, u32 start, u32 end) {
struct range *r = ck_alloc_nozero(sizeof(struct range));
@ -99,11 +107,12 @@ static struct range *add_range(struct range *ranges, u32 start, u32 end) {
}
static struct range *pop_biggest_range(struct range **ranges) {
static struct range *pop_biggest_range(struct range **ranges, int *num_ranges) {
struct range *r = *ranges;
struct range *rmax = NULL;
u32 max_size = 0;
u32 count = 0;
while (r) {
@ -121,9 +130,11 @@ static struct range *pop_biggest_range(struct range **ranges) {
}
r = r->next;
++count;
}
*num_ranges = count;
return rmax;
}
@ -303,6 +314,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
afl->stage_short = "colorization";
afl->stage_max = (len << 1);
afl->stage_cur = 0;
++(afl->cmplog_color_items);
// in colorization we do not classify counts, hence we have to calculate
// the original checksum.
@ -324,7 +336,8 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
}
while ((rng = pop_biggest_range(&ranges)) != NULL &&
u32 range_count = 0;
while ((rng = pop_biggest_range(&ranges, &range_count)) != NULL &&
afl->stage_cur < afl->stage_max) {
u32 s = 1 + rng->end - rng->start;
@ -355,6 +368,50 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
ranges = add_range(ranges, rng->start, rng->start - 1 + s / 2);
ranges = add_range(ranges, rng->start + s / 2, rng->end);
/* Check the number of *remaining* execs for colorization; since
each represents a previously split range, and may be split
again, we break when emptying the queue would consume *half*
the timeout */
if ((range_count * afl->queue_cur->exec_us) >
((CMPLOG_COLORIZATION_TIME_MAX_START << afl->cmplog_color_depth) /
2 * 1000000)) {
if (afl->afl_env.afl_no_ui) {
WARNF(
"Colorization took too long, skipping (%llu/%llu, depth %llu).",
afl->cmplog_color_fail + 1, afl->cmplog_color_items,
afl->cmplog_color_depth);
}
if (unlikely(afl->cmplog_color_depth < 4)) {
++(afl->cmplog_color_fail);
if (likely(afl->cmplog_color_items > 4) &&
unlikely(afl->cmplog_color_items / afl->cmplog_color_fail) <
2) {
++(afl->cmplog_color_depth);
afl->cmplog_color_items = 0;
afl->cmplog_color_fail = 0;
if (afl->afl_env.afl_no_ui) {
WARNF("Increasing colorization time depth to %llu.",
afl->cmplog_color_depth);
}
}
}
goto checksum_fail;
}
}
if (ranges == rng) {
@ -795,7 +852,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 *o_buf_64 = (u64 *)&orig_buf[idx];
u32 *o_buf_32 = (u32 *)&orig_buf[idx];
u16 *o_buf_16 = (u16 *)&orig_buf[idx];
u8 *o_buf_8 = &orig_buf[idx];
// u8 *o_buf_8 = &orig_buf[idx];
u32 its_len = MIN(len - idx, taint_len);
@ -836,6 +893,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// necessary for preventing heap access overflow
bytes = MIN(bytes, len - idx);
if (unlikely(bytes <= 1)) { return 0; }
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
if (afl->cmplog_enable_transform && (lvl & LVL3)) {
@ -1266,6 +1324,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
/*
if (*status != 1) { // u8
// if (its_len >= 1)
@ -1290,6 +1349,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
*/
}
// If 'S' is set for cmplog mode then we try a scale encoding of the value.
@ -1881,6 +1942,8 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
hshape = SHAPE_BYTES(h->shape);
if (hshape < 2) { return 0; }
if (h->hits > CMP_MAP_H) {
loggeds = CMP_MAP_H;
@ -1906,8 +1969,6 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
#endif
if (hshape < 2) { return 0; }
for (i = 0; i < loggeds; ++i) {
struct cmp_operands *o = &afl->shm.cmp_map->log[key][i];
@ -1945,6 +2006,19 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
#ifdef USE_HASHMAP
// TODO: add attribute? not sure
if (hshape <= 8 && hashmap_search_and_add(hshape - 1, o->v0) &&
hashmap_search_and_add(hshape - 1, orig_o->v0) &&
hashmap_search_and_add(hshape - 1, o->v1) &&
hashmap_search_and_add(hshape - 1, orig_o->v1)) {
continue;
}
#endif
#ifdef _DEBUG
fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n",
orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape);
@ -2219,15 +2293,15 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 31 || l1 > 31 ||
ol0 > 31 || ol1 > 31) {
if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 32 || l1 > 32 ||
ol0 > 32 || ol1 > 32) {
l0 = ol0 = hshape;
}
u8 lmax = MAX(l0, ol0);
u8 save[40];
u8 save[80];
u32 saved_idx = idx, pre, from = 0, to = 0, i, j;
u32 its_len = MIN(MIN(lmax, hshape), len - idx);
its_len = MIN(its_len, taint_len);
@ -2330,7 +2404,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
u32 tob64 = 0, fromb64 = 0;
u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0;
u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0;
u8 xor_val[32], arith_val[32], tmp[48];
u8 xor_val[64], arith_val[64], tmp[64];
idx = saved_idx;
its_len = saved_its_len;
@ -2615,12 +2689,13 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
memcpy(buf + idx, tmp, hlen + 1 + off);
u32 tmp_l = hlen + 1 + off;
memcpy(buf + idx, tmp, tmp_l);
if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
tmp[hlen + 1 + off] = 0;
tmp[tmp_l] = 0;
// fprintf(stderr, "RTN ATTEMPT idx=%u len=%u fromhex %u %s %s result
// %u\n", idx, len, fromhex, tmp, repl, *status);
memcpy(buf + idx, save, hlen + 1 + off);
memcpy(buf + idx, save, tmp_l);
}
@ -2755,6 +2830,18 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
fprintf(stderr, "\n");
#endif
#ifdef USE_HASHMAP
if (hshape <= 8 && hashmap_search_and_add_ptr(hshape - 1, o->v0) &&
hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) &&
hashmap_search_and_add_ptr(hshape - 1, o->v1) &&
hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) {
continue;
}
#endif
t = taint;
while (t->next) {
@ -3021,6 +3108,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
// Start insertion loop
#ifdef USE_HASHMAP
hashmap_reset();
#endif
u64 orig_hit_cnt, new_hit_cnt;
u64 orig_execs = afl->fsrv.total_execs;
orig_hit_cnt = afl->queued_items + afl->saved_crashes;

View File

@ -102,7 +102,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->stats_update_freq = 1;
afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000;
afl->stats_avg_exec = 0;
afl->skip_deterministic = 1;
afl->skip_deterministic = 0;
afl->sync_time = SYNC_TIME;
afl->cmplog_lvl = 2;
afl->min_length = 1;

View File

@ -1112,7 +1112,7 @@ void show_stats_normal(afl_state_t *afl) {
} else if (likely(afl->skip_deterministic)) {
strcpy(tmp, "disabled (default, enable with -D)");
strcpy(tmp, "disabled (-z switch used)");
} else {

View File

@ -170,7 +170,6 @@ static void usage(u8 *argv0, int more_help) {
" -g minlength - set min length of generated fuzz input (default: 1)\n"
" -G maxlength - set max length of generated fuzz input (default: "
"%lu)\n"
" -D - enable (a new) effective deterministic fuzzing\n"
" -L minutes - use MOpt(imize) mode and set the time limit for "
"entering the\n"
" pacemaker mode (minutes of no new finds). 0 = "
@ -213,7 +212,8 @@ static void usage(u8 *argv0, int more_help) {
" -F path - sync to a foreign fuzzer queue directory (requires "
"-M, can\n"
" be specified up to %u times)\n"
// " -d - skip deterministic fuzzing in -M mode\n"
" -z - skip the enhanced deterministic fuzzing\n"
" (note that the old -d and -D flags are ignored.)\n"
" -T text - text banner to show on the screen\n"
" -I command - execute this command/script when a new crash is "
"found\n"
@ -401,6 +401,12 @@ static void usage(u8 *argv0, int more_help) {
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
#endif
#ifdef _AFL_SPECIAL_PERFORMANCE
SAYF(
"Compiled with special performance options for this specific system, it "
"might not work on other platforms!\n");
#endif
SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
exit(1);
@ -539,7 +545,7 @@ int main(int argc, char **argv_orig, char **envp) {
// still available: HjJkKqruvwz
while ((opt = getopt(argc, argv,
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
"T:UV:WXx:YZ")) > 0) {
"T:UV:WXx:YzZ")) > 0) {
switch (opt) {
@ -955,20 +961,17 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'D': /* partial deterministic */
case 'd':
case 'D': /* old deterministic */
afl->skip_deterministic = 0;
WARNF(
"Parameters -d and -D are deprecated, a new enhanced deterministic "
"fuzzing is active by default, to disable it use -z");
break;
case 'd': /* no deterministic */
case 'z': /* no deterministic */
// this is the default and currently a lot of infrastructure enforces
// it (e.g. clusterfuzz, fuzzbench) based on that this feature
// originally was bad performance wise. We now have a better
// implementation, hence if it is activated, we do not want to
// deactivate it by such setups.
// afl->skip_deterministic = 1;
afl->skip_deterministic = 1;
break;
case 'B': /* load bitmap */
@ -1232,6 +1235,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
afl->old_seed_selection = 1;
u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000;
if ((s32)limit_time_puppet2 < afl->limit_time_puppet) {
@ -2182,7 +2186,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir);
afl->fsrv.persistent_record_dir = alloc_printf("%s", afl->out_dir);
}

View File

@ -2,9 +2,17 @@
#include "afl-fuzz.h"
#include "types.h"
#define XXH_INLINE_ALL
#include "xxhash.h"
#undef XXH_INLINE_ALL
#ifdef _HAVE_AVX2
#define T1HA0_AESNI_AVAILABLE 1
#define T1HA_USE_FAST_ONESHOT_READ 1
#define T1HA_USE_INDIRECT_FUNCTIONS 1
#define T1HA_IA32AES_NAME XXH3_64bits
#include "t1ha0_ia32aes_b.h"
#else
#define XXH_INLINE_ALL
#include "xxhash.h"
#undef XXH_INLINE_ALL
#endif
void rand_set_seed(afl_state_t *afl, s64 init_seed) {

149
src/hashmap.c Normal file
View File

@ -0,0 +1,149 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "types.h"
#define TABLE_SIZE 10007 // Use a prime number for better distribution
typedef struct HashNode {
uint64_t key;
struct HashNode *next;
} HashNode;
typedef struct HashMap {
HashNode **table;
} HashMap;
static HashMap *_hashmap;
void hashmap_reset() {
if (unlikely(!_hashmap)) {
_hashmap = (HashMap *)malloc(sizeof(HashMap));
_hashmap->table = (HashNode **)malloc(sizeof(HashNode *) * TABLE_SIZE);
memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE);
} else {
for (int i = 0; i < TABLE_SIZE; i++) {
HashNode *node = _hashmap->table[i];
while (node) {
HashNode *temp = node;
node = node->next;
free(temp);
}
}
memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE);
}
}
static inline unsigned int hash(uint64_t key) {
return key % TABLE_SIZE;
}
// type must be below 8
bool hashmap_search_and_add(uint8_t type, uint64_t key) {
if (unlikely(type >= 8)) return false;
uint64_t val = (key & 0xf8ffffffffffffff) + (type << 56);
unsigned int index = hash(val);
HashNode *node = _hashmap->table[index];
while (node) {
if (node->key == val) return true;
node = node->next;
}
// not found so add it
node = (HashNode *)malloc(sizeof(HashNode));
node->key = val;
node->next = _hashmap->table[index];
_hashmap->table[index] = node;
return false;
}
// type must be below 8
bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) {
if (unlikely(type >= 8)) return false;
uint64_t key_t = 0;
memcpy(((char *)key_t) + (7 - type), key, type + 1);
return hashmap_search_and_add(type, key_t);
}
/* below is not used */
void hashmap_insert(uint64_t key) {
unsigned int index = hash(key);
HashNode *node = (HashNode *)malloc(sizeof(HashNode));
node->key = key;
node->next = _hashmap->table[index];
_hashmap->table[index] = node;
}
bool hashmap_search(uint64_t key) {
unsigned int index = hash(key);
HashNode *node = _hashmap->table[index];
while (node) {
if (node->key == key) return true;
node = node->next;
}
return false;
}
void delete(uint64_t key) {
unsigned int index = hash(key);
HashNode *prev = NULL, *node = _hashmap->table[index];
while (node) {
if (node->key == key) {
if (prev)
prev->next = node->next;
else
_hashmap->table[index] = node->next;
free(node);
return;
}
prev = node;
node = node->next;
}
}
void freeHashMap(HashMap *map) {
free(_hashmap->table);
free(map);
}

View File

@ -62,7 +62,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
$ECHO "$RED[!] llvm_mode threadsafe instrumentation failed"
CODE=1
}
rm -f test-instr.ts.0 test-instr.ts.1
rm -f test-instr.ts.0 test-instr.ts.1 test-instr.ts
} || {
$ECHO "$RED[!] llvm_mode (threadsafe) failed"
CODE=1

View File

@ -63,7 +63,7 @@ test -e ../afl-qemu-trace && {
{
export AFL_PRELOAD=../libcompcov.so
export AFL_COMPCOV_LEVEL=2
../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-compcov >>errors 2>&1
AFL_NO_UI=1 ../afl-fuzz -V07 -Q -i in -o out -- ./test-compcov 2>&1
unset AFL_PRELOAD
unset AFL_COMPCOV_LEVEL
} >>errors 2>&1
@ -88,7 +88,7 @@ test -e ../afl-qemu-trace && {
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 qemu_mode cmplog, this will take approx 10 seconds"
{
../afl-fuzz -m none -V07 -Q -c 0 -l 3 -i in -o out -- ./test-compcov >>errors 2>&1
../afl-fuzz -V07 -Q -c 0 -l 3 -i in -o out -- ./test-compcov >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode cmplog"

View File

@ -198,10 +198,12 @@ $MAKECMD -j1 || exit 1
echo "[+] Build process successful!"
echo "[*] Installing Unicorn python bindings..."
XOPT=
$PYTHONBIN -m pip install --help 2>/dev/null | grep -q break-system-packages && XOPT=--break-system-packages
cd unicorn/bindings/python || exit 1
if [ -z "$VIRTUAL_ENV" ]; then
echo "[*] Info: Installing python unicornafl using --user"
THREADS=$CORES $PYTHONBIN -m pip install --user --force .|| exit 1
THREADS=$CORES $PYTHONBIN -m pip install --user $XOPT --force .|| exit 1
else
echo "[*] Info: Installing python unicornafl to virtualenv: $VIRTUAL_ENV"
THREADS=$CORES $PYTHONBIN -m pip install --force .|| exit 1
@ -211,7 +213,7 @@ echo "[*] Installing Unicornafl python bindings..."
cd bindings/python || exit 1
if [ -z "$VIRTUAL_ENV" ]; then
echo "[*] Info: Installing python unicornafl using --user"
THREADS=$CORES $PYTHONBIN -m pip install --user --force .|| exit 1
THREADS=$CORES $PYTHONBIN -m pip install --user $XOPT --force .|| exit 1
else
echo "[*] Info: Installing python unicornafl to virtualenv: $VIRTUAL_ENV"
THREADS=$CORES $PYTHONBIN -m pip install --force .|| exit 1

8
utils/bench/Makefile Normal file
View File

@ -0,0 +1,8 @@
all: hash
hash: hash.c
gcc -O3 -mavx2 -march=native -I../../include -o hash hash.c
clean:
rm -f hash

2
utils/bench/README.md Normal file
View File

@ -0,0 +1,2 @@
# Internal AFL++ benchmarking

53
utils/bench/hash.c Normal file
View File

@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#define T1HA0_AESNI_AVAILABLE 1
#define T1HA_USE_FAST_ONESHOT_READ 1
#define T1HA_USE_INDIRECT_FUNCTIONS 1
#define T1HA_IA32AES_NAME t1ha0_ia32aes
#include "t1ha0_ia32aes_b.h"
#define XXH_INLINE_ALL
#include "xxhash.h"
#undef XXH_INLINE_ALL
int main() {
char *data = malloc(4097);
struct timespec start, end;
long long duration;
int i;
uint64_t res;
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < 100000000; ++i) {
res = XXH3_64bits(data, 4097);
memcpy(data + 16, (char *)&res, 8);
}
clock_gettime(CLOCK_MONOTONIC, &end);
duration = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("xxh3 duration: %lld ns\n", duration);
memset(data, 0, 4097);
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < 100000000; ++i) {
res = t1ha0_ia32aes(data, 4097);
memcpy(data + 16, (char *)&res, 8);
}
clock_gettime(CLOCK_MONOTONIC, &end);
duration = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("t1ha0_ia32aes duration: %lld ns\n", duration);
return 0;
}

View File

@ -7,4 +7,4 @@ document:
AFL_DONT_OPTIMIZE=1 ../../afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c
clean:
rm -f persistent_demo persistent_demo_new test-instr
rm -f persistent_demo persistent_demo_new persistent_demo_new_compat test-instr

View File

@ -0,0 +1,8 @@
all:
test `grep '//[\s\t ]*#define[\s\t ]*AFL_PERSISTENT_RECORD' ../../include/config.h | wc -l` -eq 0 || (echo "AFL_PERSISTENT_RECORD must be enabled in config.h"; exit 1)
../../afl-clang-fast -o persistent_demo_replay persistent_demo_replay.c
${CC} -I ../../include -o persistent_demo_replay_compat persistent_demo_replay.c
${CC} -g -I ../../include -DAFL_PERSISTENT_REPLAY_ARGPARSE -o persistent_demo_replay_argparse persistent_demo_replay.c
clean:
rm -f persistent_demo_replay persistent_demo_replay_argparse persistent_demo_replay_compat

View File

@ -0,0 +1,10 @@
# AFL++ persistent record replay
This persistent record replay demo showcases the `AFL_PERSISTENT_RECORD` replay functionality.
The [Makefile](Makefile) will produce three binaries:
+ persistent_demo_replay: uses afl-cc and makes use of the replay functionality included in the compiler runtime library
+ persistent_demo_replay_compat: uses the [afl-record-compat.h](../../include/afl-record-compat.h) compatibility header to compile the same example without `afl-cc`
+ persistent_demo_replay_argparse: makes use of `afl-record-compat.h`, and the Makefile defines `AFL_PERSISTENT_REPLAY_ARGPARSE` to test the replay functionality but parses the input file via a command-line argument (`@@`-style harness).
For more information see [README.persistent_mode.md](../../instrumentation/README.persistent_mode.md).

View File

@ -0,0 +1,148 @@
/*
american fuzzy lop++ - persistent mode example
--------------------------------------------
Originally written by Michal Zalewski
Copyright 2015 Google Inc. 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
This file demonstrates the high-performance "persistent mode" that may be
suitable for fuzzing certain fast and well-behaved libraries, provided that
they are stateless or that their internal state can be easily reset
across runs.
To make this work, the library and this shim need to be compiled in LLVM
mode using afl-clang-fast (other compiler wrappers will *not* work).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <limits.h>
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
#include <sys/stat.h>
#include <fcntl.h>
#endif
/* this lets the source compile without afl-clang-fast/lto */
#ifndef __AFL_FUZZ_TESTCASE_LEN
#include "afl-record-compat.h"
#endif
__AFL_FUZZ_INIT();
/* Main entry point. */
/* To ensure checks are not optimized out it is recommended to disable
code optimization for the fuzzer harness main() */
#pragma clang optimize off
#pragma GCC optimize("O0")
int main(int argc, char **argv) {
ssize_t len; /* how much input did we read? */
unsigned char *buf; /* test case buffer pointer */
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
int fd;
if (argc < 2) { printf("Need an input file!"); }
#endif
/* The number passed to __AFL_LOOP() controls the maximum number of
iterations before the loop exits and the program is allowed to
terminate normally. This limits the impact of accidental memory leaks
and similar hiccups. */
__AFL_INIT();
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
buf = malloc(1000);
#else
buf = __AFL_FUZZ_TESTCASE_BUF; // this must be assigned before __AFL_LOOP!
#endif
while (__AFL_LOOP(UINT_MAX)) { // increase if you have good stability
#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
fd = open(argv[1], O_RDONLY);
len = read(fd, buf, 1000);
close(fd);
#else
len = __AFL_FUZZ_TESTCASE_LEN; // do not use the macro directly in a call!
#endif
// fprintf(stderr, "input: %zd \"%s\"\n", len, buf);
/* do we have enough data? */
if (len < 8) continue;
if (strcmp((char *)buf, "thisisateststring") == 0) printf("teststring\n");
if (buf[0] == 'f') {
printf("one\n");
if (buf[1] == 'o') {
printf("two\n");
if (buf[2] == 'o') {
printf("three\n");
if (buf[3] == '!') {
printf("four\n");
if (buf[4] == '!') {
printf("five\n");
if (buf[5] == '!') {
printf("six\n");
abort();
} else {
if (buf[5] == 'O') {
// hang
while (1) {
continue;
};
}
}
}
}
}
}
}
/*** END PLACEHOLDER CODE ***/
}
/* Once the loop is exited, terminate normally - AFL will restart the process
when this happens, with a clean slate when it comes to allocated memory,
leftover file descriptors, etc. */
return 0;
}