Skip to content

Commit 05bd983

Browse files
KlavishnikEvgeny Shtanov
andauthored
Fuzz update (#1033)
* Remove libfuzzer wrappers * update harness, add script for AFL++ pers mod instr * Update README.md --------- Co-authored-by: Evgeny Shtanov <[email protected]>
1 parent f8a2925 commit 05bd983

12 files changed

+301
-206
lines changed

src/CMakeLists.txt

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,19 +1211,6 @@ if (ENABLE_FUZZ_TEST)
12111211
target_link_libraries(process_netflow_packet_v5_fuzz sflow_plugin netflow_plugin example_plugin fastnetmon_logic ${LOG4CPP_LIBRARY_PATH})
12121212
endif()
12131213

1214-
# Fuzz test with AFL++ or clang
1215-
if (ENABLE_FUZZ_TEST_LIBFUZZER)
1216-
add_executable(parse_sflow_v5_packet_fuzz tests/fuzz/parse_sflow_v5_packet_fuzz_libfuzzer.cpp)
1217-
target_link_libraries(parse_sflow_v5_packet_fuzz sflow_plugin netflow_plugin example_plugin fastnetmon_logic ${LOG4CPP_LIBRARY_PATH})
1218-
target_compile_options(parse_sflow_v5_packet_fuzz PRIVATE -fsanitize=fuzzer)
1219-
target_link_options(parse_sflow_v5_packet_fuzz PRIVATE -fsanitize=fuzzer)
1220-
1221-
add_executable(process_netflow_packet_v5_fuzz tests/fuzz/process_netflow_packet_v5_fuzz_libfuzzer.cpp)
1222-
target_link_libraries(process_netflow_packet_v5_fuzz sflow_plugin netflow_plugin example_plugin fastnetmon_logic ${LOG4CPP_LIBRARY_PATH})
1223-
target_compile_options(process_netflow_packet_v5_fuzz PRIVATE -fsanitize=fuzzer)
1224-
target_link_options(process_netflow_packet_v5_fuzz PRIVATE -fsanitize=fuzzer)
1225-
endif()
1226-
12271214
# Chaged interface socket to console input
12281215
if (ENABLE_FUZZ_TEST_DESOCK)
12291216
target_link_libraries(fastnetmon desock)

src/tests/fuzz/README.md

Lines changed: 123 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ This section describes the fuzzing testing process, the approaches used, and met
88
- [Docker Image](#docker-image)
99
- [CMake](#cmake)
1010
- [File Structure](#file-structure)
11-
- [Example of Fuzzing Run](#example-of-fuzzing-run)
11+
- [Example of Fuzzing Run](#example-of-manual-fuzzing-launch-for-individual-fuzzing-wrappers)
1212
- [Other Fuzzing Techniques](#other-fuzzing-techniques)
13-
- [Techniques That Didn't Work](#techniques-that-didnt-work)
13+
- [Fuzzing Launch in Docker Container](#fuzzing-launch-in-docker-container)
1414

1515
## Docker Image
1616
--------------------------------
@@ -44,24 +44,23 @@ A number of options have been added to the source `CMakeLists.txt` file, allowin
4444
| Option | Description |
4545
|-----------------------------------|-----------------------------------------------------------|
4646
| `-DENABLE_FUZZ_TEST` | Builds two fuzzing wrappers for `AFL++`. Use **only with the `afl-c++` compiler** or its variations |
47-
| `DENABLE_FUZZ_TEST_LIBFUZZER` | Builds two fuzzing wrappers for `libfuzzer`. Use **with the `clang` compiler or variations of `afl-c++`** |
4847
| `-DENABLE_FUZZ_TEST_DESOCK` | This option allows modifying the behavior of the standard `socket` function. Now data will come from the input stream instead of the network socket. **Instruments the original `fastnetmon` executable** |
4948
| `-DCMAKE_BUILD_TYPE=Debug` | Debugging option required for proper debugger functionality. **Do not use on release builds or during tests - false positives may occur with sanitizer functions like `assert()`** |
5049

5150
## File Structure
5251
--------------------------------
53-
```bash
54-
fuzz/
55-
├── README.md
56-
├── README_rus.md
57-
├── fastnetmon.conf
58-
├── parse_sflow_v5_packet_fuzz.cpp
59-
├── parse_sflow_v5_packet_fuzz_libfuzzer.cpp
60-
── process_netflow_packet_v5_fuzz.cpp
61-
├── process_netflow_packet_v5_fuzz_libfuzzer.cpp └── scripts/
62-
├── minimize_out.sh
63-
├── start_fuzz_conf_file.sh
64-
└── start_fuzz_harness.sh
52+
```
53+
fuzz/
54+
├── README.md
55+
├── README_rus.md
56+
├── fastnetmon.conf
57+
├── parse_sflow_v5_packet_fuzz.cpp
58+
├── process_netflow_packet_v5_fuzz.cpp
59+
── scripts/
60+
│ ├── minimize_out.sh
61+
├── afl_pers_mod_instr.sh
62+
├── start_fuzz_conf_file.sh
63+
└── start_fuzz_harness.sh
6564
```
6665
### File Descriptions
6766
--------------------------------
@@ -72,47 +71,98 @@ fuzz/
7271
| `README_rus.md` | Documentation in **Russian** about the fuzz testing of the project. |
7372
| `fastnetmon.conf` | Configuration file for FastNetMon. Only the netflow and sflow protocols are left for operation. |
7473
| `parse_sflow_v5_packet_fuzz.cpp` | Wrapper for fuzzing the `parse_sflow_v5_packet_fuzz` function using `AFL++`. |
75-
| `parse_sflow_v5_packet_fuzz_libfuzzer.cpp` | Wrapper for fuzzing the `parse_sflow_v5_packet_fuzz` function using `libfuzzer`. |
7674
| `process_netflow_packet_v5_fuzz.cpp` | Wrapper for fuzzing the `process_netflow_packet_v5_fuzz` function using `AFL++`. |
77-
| `process_netflow_packet_v5_fuzz_libfuzzer.cpp` | Wrapper for fuzzing the `process_netflow_packet_v5_fuzz` function using `libfuzzer`. |
7875

7976
| File/Directory | Description | Run |
8077
|----------------------------------------|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
8178
| `/scripts/` | Directory containing scripts for automating fuzzing. | |
8279
| `/scripts/minimize_out.sh` | Script for minimizing, verifying, and clustering crash outputs. | `./minimize_out.sh <path_to_out_directory> <./binary>` |
8380
| `/scripts/start_fuzz_conf_file.sh` | Script for running fuzzing on configuration files. Launches several tmux sessions. Uses options `./fastnetmon --configuration_check --configuration_file`. | Run from the current directory without additional options. The environment is automatically set up. |
8481
| `/scripts/start_fuzz_harness.sh` | Script for testing binary files compiled from wrappers into separate executables. Designed for wrappers compiled for `AFL++`. It sets up the environment, creates folders, and launches two tmux sessions with fuzzer instances. After fuzzing ends, it runs the `minimize_out.sh` script for crash clustering. | `./start_fuzz_harness.sh <path/to/bin>` The script will stop if no new paths are found within a certain time. By default, the time is 1 hour. To change it, modify the `TIME` variable (in seconds) inside the script. |
82+
| `/scripts/afl_pers_mod_instr.sh` | A script that adds `AFL++` instrumentation for fuzzing in `persistent mode`. **Important! Currently used only with `netflow_collector.cpp` and `sflow_collector.cpp`** | `./afl_pers_mod_instr.sh <netflow_plugin/netflow_collector.cpp>` |
8583

8684

87-
## Example of Fuzzing Run
88-
--------------------------------
85+
## Example of manual fuzzing launch for individual fuzzing wrappers
86+
--------------------------------
87+
Run the container:
88+
```bash
89+
docker run --privileged -it fuzz /bin/bash
90+
```
91+
To run AFL++ fuzzing with multi-threading enabled:
8992

90-
Run the container:
9193
```bash
92-
docker run --privileged -it fuzz /bin/bash
94+
echo core | tee /proc/sys/kernel/core_pattern
9395
```
96+
**Don't forget to collect the data corpus in the in folder**
9497

95-
To enable multi-threaded fuzzing with AFL++, we set up core dumping:
98+
For a test run, use a single sed with a '1':
9699
```bash
97-
echo core | tee /proc/sys/kernel/core_pattern
100+
mkdir in
101+
echo "1" >> in/1
98102
```
99-
With the standard `docker image` build, the `build_fuzz` directory will be created, inside which the fuzzing wrappers will be compiled:
103+
104+
With a standard docker image build, there will be a folder build_fuzz_harness where the following fuzzing wrappers will be compiled:
105+
100106
- `parse_sflow_v5_packet_fuzz`
101107
- `process_netflow_packet_v5_fuzz`
102108

103-
To run fuzzing, we use the `start_fuzz_harness` script:
109+
**Start fuzzing:**
110+
```bash
111+
afl-fuzz -i in -o out -- ./parse_sflow_v5_packet_fuzz
112+
```
113+
Or
114+
115+
```bash
116+
afl-fuzz -i in -o out -- ./process_netflow_packet_v5_fuzz
117+
```
118+
- The `build_netflow_pers_mod` folder will contain the code for fuzzing the `process_netflow_packet_v5` function via `AFL++ persistent mode`.
119+
- The `build_sflow_pers_mod` folder will contain the code for fuzzing the `parse_sflow_v5_packet` function via `AFL++ persistent mode`.
120+
If the build is done manually, use the `afl_pers_mod_instr.sh` script to instrument the files.
121+
122+
The fuzzing launch for these functions is the same, as the final executable file fastnetmon is instrumented:
123+
124+
```bash
125+
afl-fuzz -i in -o out -- ./fastnetmon
126+
```
127+
128+
**IMPORTANT!**
129+
For multi-thread fuzzing of the fastnetmon file, you need to provide a separate configuration file for each instance of the fuzzer for `fastnetmon`, specifying different ports for protocols, otherwise, the instances will conflict, and multiple threads will not be able to run.
130+
131+
132+
## Example of fuzzing launch via automation script
133+
--------------------------------
134+
*All actions take place inside the container, where the working directory is `src`, so paths are constructed relative to this folder.*
135+
136+
For fuzzing, we use the `start_fuzz_harness` script.
137+
138+
For wrappers compiled into binary files:
139+
140+
```bash
141+
/src/tests/fuzz/scripts/start_fuzz_harness.sh ./build_fuzz_harness/process_netflow_packet_v5_fuzz
142+
```
143+
Or
144+
145+
```bash
146+
/src/tests/fuzz/scripts/start_fuzz_harness.sh ./build_fuzz_harness/parse_sflow_v5_packet_fuzz
147+
```
104148

149+
For instrumenting `fastnetmon`:
105150
```bash
106-
/src/tests/fuzz/scripts/start_fuzz_harness.sh ./process_netflow_packet_v5_fuzz
151+
/src/tests/fuzz/scripts/start_fuzz_harness.sh ./build_netflow_pers_mod/fastnetmon
107152
```
108-
Or
153+
Or
154+
109155
```bash
110-
/src/tests/fuzz/scripts/start_fuzz_harness.sh ./parse_sflow_v5_packet_fuzz
156+
/src/tests/fuzz/scripts/start_fuzz_harness.sh ./build_sflow_pers_mod/fastnetmon
111157
```
112-
After starting, a directory `<bin_name>_fuzz_dir` will be created, containing the input and output folders.
113-
A `tmux session` will be started with two tabs — each running an instance of the `AFL++` fuzzer.
114-
Fuzzing will continue until no new paths are found within one hour (this timeout value can be modified in the script).
115-
After that, the tmux session will end, and crash clustering and verification will begin with the `minimize_out.sh` script.
158+
159+
After launching, a directory `<bin_name>_fuzz_dir` will be created, inside which a folder `input` will be generated.
160+
A folder `/output` will be created at the root of the system, where fuzzing output files and clustering files will be sent.
161+
This is necessary to easily access data after fuzzing inside the container (see below).
162+
A `tmux` session with an AFL++ fuzzer instance will be started.
163+
Fuzzing will continue until no new paths are found within an hour (this value can be changed inside the script).
164+
Then, the tmux session will end, and clustering and crash checking will begin using the `minimize_out.sh` script.
165+
116166

117167
## Other Fuzzing Techniques
118168

@@ -133,11 +183,51 @@ How the instrumentation looks:
133183
5. Build with the AFL++ compiler and sanitizers. No wrappers are needed for compilation.
134184
6. Run fuzzing with: `afl-fuzz -i in -o out -- ./fastnetmon`
135185

186+
For these two purposes, an automation script for code instrumentation has been created.
187+
See more details in the script `/scripts/afl_pers_mod_instr.sh`.
188+
136189

137-
### Techniques That Didn't Work
190+
### Other Fuzzing Techniques
138191
--------------------------------
139192

140193
| Name | Description |
141194
|---------------------|------------------------------------------------------------------------------------------------------|
142195
| `AFLNet` | The characteristics of the protocol (lack of feedback) prevent the use of this fuzzer. |
143196
| `desock` | Code instrumentation is successful, but the fuzzer does not start and cannot collect feedback. I consider this method **promising**, but the fuzzer requires adjustments. |
197+
| `libfuzzer` | Wrappers for `libfuzzer` were written and implemented into cmake, but due to the peculiarities of the build and the project's focus on fuzzing via `AFL++`, they were removed from the project. Commit with a working [`libfuzzer`] wrappers (https://github.com/pavel-odintsov/fastnetmon/commit/c3b72c18f0bc7f43b535a5da015c3954d716be22)
198+
199+
200+
## Fuzzing Launch in Docker Container
201+
202+
### A Few Words for Context
203+
204+
Each fuzzer thread requires one system thread.
205+
206+
The `start_fuzz_harness.sh` script includes a time limit for fuzzing.
207+
The `TIME` variable is responsible for the "last path found" time parameter.
208+
If this parameter stops resetting, it means the fuzzer has hit a deadlock and there's no point in continuing fuzzing.
209+
From empirical experience, this parameter should be set to 2 hours. The project has it set to 1 hour.
210+
If shallow testing is needed, this parameter can be reduced to 10-15 minutes, making the total fuzzing time last a few hours.
211+
212+
### Build and Launch
213+
214+
Build:
215+
216+
```bash
217+
cd fastnetmon
218+
docker build -f tests/Dockerfile.ubuntu-24.04-afl++ -t fuzz .
219+
```
220+
221+
Launch the container:
222+
```
223+
mkdir work
224+
docker run -v $(pwd)/work:/output --privileged -it fuzz /bin/bash -c "/src/tests/fuzz/scripts/start_fuzz_harness.sh ./build_netflow_pers_mod/fastnetmon"
225+
```
226+
227+
This method can be used to launch any wrapper / binary file by simply providing the command from the *Example of fuzzing launch via automation script* section in quotes after the `-c` argument.
228+
229+
After fuzzing is completed, the results will be placed in the host system's work folder—both the results folder and the clustering folder will be there.
230+
231+
The container will have a status exit. It can be manually restarted to check for crashes.
232+
233+

0 commit comments

Comments
 (0)