Skip to content

Commit 4f8b677

Browse files
authored
feat: Add AFL++ fuzzing integration with persistent mode (#5932)
feat: add afl integration
1 parent 2e0a45f commit 4f8b677

File tree

12 files changed

+625
-1
lines changed

12 files changed

+625
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ releases
2121
.secrets
2222
cmake-build-debug
2323
.venv/
24+
fuzz/artifacts/
25+
fuzz/corpus/

CMakeLists.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ enable_testing()
77

88
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
99

10+
# AFL++ fuzzing support - must be set BEFORE project() command
11+
option(USE_AFL "Enable AFL++ fuzzing" OFF)
12+
if(USE_AFL)
13+
# Automatically set AFL++ compilers if not already set
14+
if(NOT CMAKE_C_COMPILER MATCHES "afl-" AND NOT CMAKE_CXX_COMPILER MATCHES "afl-")
15+
# Try to find afl-clang-fast
16+
find_program(AFL_CC afl-clang-lto)
17+
find_program(AFL_CXX afl-clang-lto++)
18+
19+
if(AFL_CC AND AFL_CXX)
20+
message(STATUS "AFL++ fuzzing enabled - setting compilers")
21+
set(CMAKE_C_COMPILER ${AFL_CC})
22+
set(CMAKE_CXX_COMPILER ${AFL_CXX})
23+
else()
24+
message(FATAL_ERROR "USE_AFL=ON but AFL++ compilers not found!\n"
25+
"Please install AFL++: apt install afl++ or build from source\n"
26+
"https://github.com/AFLplusplus/AFLplusplus")
27+
endif()
28+
endif()
29+
endif()
30+
1031
# Set targets in folders
1132
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
1233
project(DRAGONFLY C CXX)
@@ -42,6 +63,30 @@ find_package(OpenSSL)
4263

4364
SET(SANITIZERS OFF)
4465

66+
# AFL++ configuration - must be before sanitizer checks
67+
if(USE_AFL)
68+
message(STATUS "AFL++ fuzzing mode active")
69+
message(STATUS " C compiler: ${CMAKE_C_COMPILER}")
70+
message(STATUS " C++ compiler: ${CMAKE_CXX_COMPILER}")
71+
72+
# Add USE_AFL as compile definition so #ifdef USE_AFL works in code
73+
add_compile_definitions(USE_AFL)
74+
75+
# AFL++ requires specific compiler flags for coverage instrumentation
76+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
77+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
78+
79+
# Force disable sanitizers when fuzzing (AFL++ incompatible with ASAN/UBSAN)
80+
message(STATUS "Disabling sanitizers (incompatible with AFL++ fuzzing)")
81+
set(WITH_ASAN OFF CACHE BOOL "Disable ASAN for fuzzing" FORCE)
82+
set(WITH_USAN OFF CACHE BOOL "Disable UBSAN for fuzzing" FORCE)
83+
84+
# Disable AWS and GCP for fuzzing builds (not needed, reduces build time)
85+
message(STATUS "Disabling AWS and GCP integrations for fuzzing")
86+
set(WITH_AWS OFF CACHE BOOL "Disable AWS for fuzzing" FORCE)
87+
set(WITH_GCP OFF CACHE BOOL "Disable GCP for fuzzing" FORCE)
88+
endif()
89+
4590
option(WITH_ASAN "Enable -fsanitize=address" OFF)
4691
if (SUPPORT_ASAN AND WITH_ASAN)
4792
message(STATUS "address sanitizer enabled")

fuzz/FUZZING.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# AFL++ Fuzzing for Dragonfly
2+
3+
## Install AFL++
4+
5+
```bash
6+
# From package manager (Ubuntu/Debian)
7+
sudo apt update
8+
sudo apt install afl++
9+
10+
# Or build from source
11+
git clone https://github.com/AFLplusplus/AFLplusplus
12+
cd AFLplusplus
13+
make distrib
14+
sudo make install
15+
```
16+
17+
## Prepare System
18+
19+
```bash
20+
sudo afl-system-config
21+
```
22+
23+
Sets core_pattern and CPU governors for optimal AFL++ performance.
24+
25+
## Build
26+
27+
```bash
28+
cmake -B build-dbg -DUSE_AFL=ON -DCMAKE_BUILD_TYPE=Debug -GNinja
29+
ninja -C build-dbg dragonfly
30+
```
31+
32+
## Run
33+
34+
```bash
35+
cd fuzz
36+
./run_fuzzer.sh
37+
```
38+
39+
## Replay Crash on production dragonfly:
40+
```bash
41+
./dragonfly --port=6379 &
42+
nc localhost 6379 < artifacts/resp/default/crashes/id:000000,...
43+
```

fuzz/dict/resp.dict

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# AFL++ dictionary for RESP protocol
2+
# Dragonfly command keywords and common patterns
3+
4+
# RESP protocol markers
5+
"*"
6+
"$"
7+
"+"
8+
"-"
9+
":"
10+
"\x0d\x0a"
11+
12+
# Common commands - String operations
13+
"GET"
14+
"SET"
15+
"MGET"
16+
"MSET"
17+
"INCR"
18+
"DECR"
19+
"APPEND"
20+
"STRLEN"
21+
"SETEX"
22+
"SETNX"
23+
"GETSET"
24+
"GETRANGE"
25+
"SETRANGE"
26+
27+
# List operations
28+
"LPUSH"
29+
"RPUSH"
30+
"LPOP"
31+
"RPOP"
32+
"LLEN"
33+
"LRANGE"
34+
"LINDEX"
35+
"LSET"
36+
"LTRIM"
37+
"BLPOP"
38+
"BRPOP"
39+
40+
# Hash operations
41+
"HSET"
42+
"HGET"
43+
"HMSET"
44+
"HMGET"
45+
"HGETALL"
46+
"HDEL"
47+
"HEXISTS"
48+
"HLEN"
49+
"HKEYS"
50+
"HVALS"
51+
"HINCRBY"
52+
53+
# Set operations
54+
"SADD"
55+
"SREM"
56+
"SMEMBERS"
57+
"SISMEMBER"
58+
"SCARD"
59+
"SINTER"
60+
"SUNION"
61+
"SDIFF"
62+
"SPOP"
63+
64+
# Sorted set operations
65+
"ZADD"
66+
"ZREM"
67+
"ZRANGE"
68+
"ZRANGEBYSCORE"
69+
"ZRANK"
70+
"ZSCORE"
71+
"ZCARD"
72+
"ZCOUNT"
73+
"ZINCRBY"
74+
75+
# Key operations
76+
"DEL"
77+
"EXISTS"
78+
"EXPIRE"
79+
"TTL"
80+
"PERSIST"
81+
"KEYS"
82+
"SCAN"
83+
"TYPE"
84+
"RENAME"
85+
"RENAMENX"
86+
87+
# Transaction commands
88+
"MULTI"
89+
"EXEC"
90+
"DISCARD"
91+
"WATCH"
92+
"UNWATCH"
93+
94+
# Pub/Sub commands
95+
"PUBLISH"
96+
"SUBSCRIBE"
97+
"UNSUBSCRIBE"
98+
"PSUBSCRIBE"
99+
"PUNSUBSCRIBE"
100+
101+
# Stream commands
102+
"XADD"
103+
"XREAD"
104+
"XRANGE"
105+
"XLEN"
106+
"XDEL"
107+
"XTRIM"
108+
"XGROUP"
109+
"XREADGROUP"
110+
111+
# JSON commands
112+
"JSON.SET"
113+
"JSON.GET"
114+
"JSON.DEL"
115+
"JSON.TYPE"
116+
"JSON.NUMINCRBY"
117+
"JSON.ARRAPPEND"
118+
"JSON.ARRLEN"
119+
120+
# Bloom filter commands
121+
"BF.ADD"
122+
"BF.EXISTS"
123+
"BF.RESERVE"
124+
"BF.MADD"
125+
"BF.MEXISTS"
126+
127+
# HyperLogLog commands
128+
"PFADD"
129+
"PFCOUNT"
130+
"PFMERGE"
131+
132+
# Geo commands
133+
"GEOADD"
134+
"GEODIST"
135+
"GEORADIUS"
136+
"GEOSEARCH"
137+
138+
# Server commands
139+
"PING"
140+
"ECHO"
141+
"INFO"
142+
"DBSIZE"
143+
"SELECT"
144+
145+
# Cluster commands
146+
"CLUSTER"
147+
"READONLY"
148+
"READWRITE"
149+
150+
# Common keys for testing
151+
"key"
152+
"mykey"
153+
"key1"
154+
"key2"
155+
"test"
156+
"foo"
157+
"bar"
158+
"user:1"
159+
"session:123"
160+
161+
# Common values
162+
"value"
163+
"hello"
164+
"world"
165+
"123"
166+
"0"
167+
"1"
168+
"-1"
169+
170+
# Number patterns
171+
"0"
172+
"1"
173+
"100"
174+
"1000"
175+
"-1"
176+
"-100"
177+
178+
# Special arguments
179+
"NX"
180+
"XX"
181+
"EX"
182+
"PX"
183+
"GT"
184+
"LT"
185+
"WITHSCORES"
186+
"LIMIT"
187+
"COUNT"
188+
"MATCH"
189+
"BLOCK"
190+
191+
# Common RESP command patterns
192+
"*1\x0d\x0a$4\x0d\x0aPING\x0d\x0a"
193+
"*2\x0d\x0a$3\x0d\x0aGET\x0d\x0a$3\x0d\x0akey\x0d\x0a"
194+
"*3\x0d\x0a$3\x0d\x0aSET\x0d\x0a$3\x0d\x0akey\x0d\x0a$5\x0d\x0avalue\x0d\x0a"
195+
"*2\x0d\x0a$3\x0d\x0aDEL\x0d\x0a$3\x0d\x0akey\x0d\x0a"
196+
"*2\x0d\x0a$6\x0d\x0aEXISTS\x0d\x0a$3\x0d\x0akey\x0d\x0a"

0 commit comments

Comments
 (0)