Skip to content

Commit e7db4d4

Browse files
committed
fix sync script, update remote sync documentation
1 parent 567042d commit e7db4d4

File tree

2 files changed

+68
-48
lines changed

2 files changed

+68
-48
lines changed

docs/parallel_fuzzing.md

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ n-core system, you can almost always run around n concurrent fuzzing jobs with
1010
virtually no performance hit (you can use the afl-gotcpu tool to make sure).
1111

1212
In fact, if you rely on just a single job on a multi-core system, you will
13-
be underutilizing the hardware. So, parallelization is usually the right
14-
way to go.
13+
be underutilizing the hardware. So, parallelization is always the right way to
14+
go.
1515

1616
When targeting multiple unrelated binaries or using the tool in
1717
"non-instrumented" (-n) mode, it is perfectly fine to just start up several
@@ -65,22 +65,7 @@ still perform deterministic checks; while the secondary instances will
6565
proceed straight to random tweaks.
6666

6767
Note that you must always have one -M main instance!
68-
69-
Note that running multiple -M instances is wasteful, although there is an
70-
experimental support for parallelizing the deterministic checks. To leverage
71-
that, you need to create -M instances like so:
72-
73-
```
74-
./afl-fuzz -i testcase_dir -o sync_dir -M mainA:1/3 [...]
75-
./afl-fuzz -i testcase_dir -o sync_dir -M mainB:2/3 [...]
76-
./afl-fuzz -i testcase_dir -o sync_dir -M mainC:3/3 [...]
77-
```
78-
79-
...where the first value after ':' is the sequential ID of a particular main
80-
instance (starting at 1), and the second value is the total number of fuzzers to
81-
distribute the deterministic fuzzing across. Note that if you boot up fewer
82-
fuzzers than indicated by the second number passed to -M, you may end up with
83-
poor coverage.
68+
Running multiple -M instances is wasteful!
8469

8570
You can also monitor the progress of your jobs from the command line with the
8671
provided afl-whatsup tool. When the instances are no longer finding new paths,
@@ -99,61 +84,88 @@ example may be:
9984
This is not a concern if you use @@ without -f and let afl-fuzz come up with the
10085
file name.
10186

102-
## 3) Syncing with non-afl fuzzers or independant instances
87+
## 3) Multiple -M mains
88+
89+
90+
There is support for parallelizing the deterministic checks.
91+
This is only needed where
92+
93+
1. many new paths are found fast over a long time and it looks unlikely that
94+
main node will ever catch up, and
95+
2. deterministic fuzzing is actively helping path discovery (you can see this
96+
in the main node for the first for lines in the "fuzzing strategy yields"
97+
section. If the ration `found/attemps` is high, then it is effective. It
98+
most commonly isn't.)
99+
100+
Only if both are true it is beneficial to have more than one main.
101+
You can leverage this by creating -M instances like so:
102+
103+
```
104+
./afl-fuzz -i testcase_dir -o sync_dir -M mainA:1/3 [...]
105+
./afl-fuzz -i testcase_dir -o sync_dir -M mainB:2/3 [...]
106+
./afl-fuzz -i testcase_dir -o sync_dir -M mainC:3/3 [...]
107+
```
108+
109+
... where the first value after ':' is the sequential ID of a particular main
110+
instance (starting at 1), and the second value is the total number of fuzzers to
111+
distribute the deterministic fuzzing across. Note that if you boot up fewer
112+
fuzzers than indicated by the second number passed to -M, you may end up with
113+
poor coverage.
114+
115+
## 4) Syncing with non-afl fuzzers or independant instances
103116

104117
A -M main node can be told with the `-F other_fuzzer_queue_directory` option
105118
to sync results from other fuzzers, e.g. libfuzzer or honggfuzz.
106119

107120
Only the specified directory will by synced into afl, not subdirectories.
108-
The specified directories do not need to exist yet at the start of afl.
121+
The specified directory does not need to exist yet at the start of afl.
109122

110-
## 4) Multi-system parallelization
123+
The `-F` option can be passed to the main node several times.
124+
125+
## 5) Multi-system parallelization
111126

112127
The basic operating principle for multi-system parallelization is similar to
113128
the mechanism explained in section 2. The key difference is that you need to
114129
write a simple script that performs two actions:
115130

116131
- Uses SSH with authorized_keys to connect to every machine and retrieve
117-
a tar archive of the /path/to/sync_dir/<fuzzer_id>/queue/ directories for
118-
every <fuzzer_id> local to the machine. It's best to use a naming scheme
119-
that includes host name in the fuzzer ID, so that you can do something
120-
like:
132+
a tar archive of the /path/to/sync_dir/<main_node(s)> directory local to
133+
the machine.
134+
It is best to use a naming scheme that includes host name and it's being
135+
a main node (e.g. main1, main2) in the fuzzer ID, so that you can do
136+
something like:
121137

122138
```sh
123-
for s in {1..10}; do
124-
ssh user@host${s} "tar -czf - sync/host${s}_fuzzid*/[qf]*" >host${s}.tgz
139+
for host in `cat HOSTLIST`; do
140+
ssh user@$host "tar -czf - sync/$host_main*/" > $host.tgz
125141
done
126142
```
127143

128144
- Distributes and unpacks these files on all the remaining machines, e.g.:
129145

130146
```sh
131-
for s in {1..10}; do
132-
for d in {1..10}; do
147+
for srchost in `cat HOSTLIST`; do
148+
for dsthost in `cat HOSTLIST`; do
133149
test "$s" = "$d" && continue
134-
ssh user@host${d} 'tar -kxzf -' <host${s}.tgz
150+
ssh user@$srchost 'tar -kxzf -' < $dsthost.tgz
135151
done
136152
done
137153
```
138154

139-
There is an example of such a script in examples/distributed_fuzzing/;
140-
you can also find a more featured, experimental tool developed by
141-
Martijn Bogaard at:
142-
143-
https://github.com/MartijnB/disfuzz-afl
144-
145-
Another client-server implementation from Richo Healey is:
155+
There is an example of such a script in examples/distributed_fuzzing/.
146156

147-
https://github.com/richo/roving
157+
There are other (older) more featured, experimental tools:
158+
* https://github.com/richo/roving
159+
* https://github.com/MartijnB/disfuzz-afl
148160

149-
Note that these third-party tools are unsafe to run on systems exposed to the
150-
Internet or to untrusted users.
161+
However these do not support syncing just main nodes (yet).
151162

152163
When developing custom test case sync code, there are several optimizations
153164
to keep in mind:
154165

155166
- The synchronization does not have to happen very often; running the
156-
task every 30 minutes or so may be perfectly fine.
167+
task every 60 minutes or even less often at later fuzzing stages is
168+
fine
157169

158170
- There is no need to synchronize crashes/ or hangs/; you only need to
159171
copy over queue/* (and ideally, also fuzzer_stats).
@@ -179,12 +191,17 @@ to keep in mind:
179191
- You do not want a "main" instance of afl-fuzz on every system; you should
180192
run them all with -S, and just designate a single process somewhere within
181193
the fleet to run with -M.
194+
195+
- Syncing is only necessary for the main nodes on a system. It is possible
196+
to run main-less with only secondaries. However then you need to find out
197+
which secondary took over the temporary role to be the main node. Look for
198+
the `is_main` file in the fuzzer directories, eg. `sync-dir/hostname-*/is_main`
182199

183200
It is *not* advisable to skip the synchronization script and run the fuzzers
184201
directly on a network filesystem; unexpected latency and unkillable processes
185202
in I/O wait state can mess things up.
186203

187-
## 5) Remote monitoring and data collection
204+
## 6) Remote monitoring and data collection
188205

189206
You can use screen, nohup, tmux, or something equivalent to run remote
190207
instances of afl-fuzz. If you redirect the program's output to a file, it will
@@ -208,7 +225,7 @@ Keep in mind that crashing inputs are *not* automatically propagated to the
208225
main instance, so you may still want to monitor for crashes fleet-wide
209226
from within your synchronization or health checking scripts (see afl-whatsup).
210227

211-
## 6) Asymmetric setups
228+
## 7) Asymmetric setups
212229

213230
It is perhaps worth noting that all of the following is permitted:
214231

@@ -224,7 +241,7 @@ It is perhaps worth noting that all of the following is permitted:
224241
the discovered test cases can have synergistic effects and improve the
225242
overall coverage.
226243

227-
(In this case, running one -M instance per each binary is a good plan.)
244+
(In this case, running one -M instance per target is necessary.)
228245

229246
- Having some of the fuzzers invoke the binary in different ways.
230247
For example, 'djpeg' supports several DCT modes, configurable with

examples/distributed_fuzzing/sync_script.sh

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ FUZZ_USER=bob
3939
# Directory to synchronize
4040
SYNC_DIR='/home/bob/sync_dir'
4141

42-
# Interval (seconds) between sync attempts
43-
SYNC_INTERVAL=$((30 * 60))
42+
# We only capture -M main nodes, set the name to your chosen nameing scheme
43+
MAIN_NAME='main'
44+
45+
# Interval (seconds) between sync attempts (eg one hour)
46+
SYNC_INTERVAL=$((60 * 60))
4447

4548
if [ "$AFL_ALLOW_TMP" = "" ]; then
4649

@@ -63,7 +66,7 @@ while :; do
6366
echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..."
6467

6568
ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \
66-
"cd '$SYNC_DIR' && tar -czf - ${host}_*/[qf]*" >".sync_tmp/${host}.tgz"
69+
"cd '$SYNC_DIR' && tar -czf - ${host}_${MAIN_NAME}*/" > ".sync_tmp/${host}.tgz"
6770

6871
done
6972

@@ -80,7 +83,7 @@ while :; do
8083
echo " Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..."
8184

8285
ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \
83-
"cd '$SYNC_DIR' && tar -xkzf -" <".sync_tmp/${src_host}.tgz"
86+
"cd '$SYNC_DIR' && tar -xkzf - " < ".sync_tmp/${src_host}.tgz"
8487

8588
done
8689

0 commit comments

Comments
 (0)