Skip to content

Commit 46e010b

Browse files
tokatokadomenukk
authored andcommitted
Reachability example (#65)
* add reachability observer/feedback * add fuzzer exmaple * fmt * remove reachabilityobserver, use stdmapobserver instead * update diff.patch * update README * fix the clippy warning * Squashed commit of the following: commit f20524e Author: Andrea Fioraldi <andreafioraldi@gmail.com> Date: Tue May 4 16:00:39 2021 +0200 Composing feedback (#85) * composing feedbacks as logic operations and bump to 0.2 * adapt fuzzers and libafl_frida * fix windows build commit e06efaa Author: Andrea Fioraldi <andreafioraldi@gmail.com> Date: Tue May 4 13:54:46 2021 +0200 Observers refactor (#84) * new observer structure with HasExecHooks * adapt libafl_frida to new observers * docstrings commit 17c6fcd Merge: 08a2d43 a78a4b7 Author: Andrea Fioraldi <andreafioraldi@gmail.com> Date: Mon May 3 11:16:49 2021 +0200 Merge branch 'main' into dev commit 08a2d43 Author: David CARLIER <devnexen@gmail.com> Date: Mon May 3 10:15:28 2021 +0100 Build warning fix proposal, mostly about reference to packed fields. (#79) commit 88fe8fa Merge: d5d46ad d2e7719 Author: Andrea Fioraldi <andreafioraldi@gmail.com> Date: Mon May 3 11:05:42 2021 +0200 Merge pull request #80 from marcograss/book-typos fixed some minor typos in the book commit a78a4b7 Author: s1341 <s1341@users.noreply.github.com> Date: Mon May 3 10:34:15 2021 +0300 frida-asan: Un-inline report funclet to reduce code bloat (#81) * frida-asan: Outline report funclet to reduce code bloat * fmt commit d2e7719 Author: Marco Grassi <marco.gra@gmail.com> Date: Sun May 2 21:58:33 2021 +0800 fixed some minor typos in the book commit d5d46ad Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 23:09:10 2021 +0200 make clippy less pedantic commit 52d25e9 Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 22:23:59 2021 +0200 fixing clippy::match-same-arms commit cd66f88 Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 14:02:07 2021 +0200 fixed clippy run in workflow commit ddcf086 Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 13:53:29 2021 +0200 Update README.md commit c715f1f Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 13:48:38 2021 +0200 using clippy.sh commit 9374b26 Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 13:47:44 2021 +0200 some clippy warning ignored commit b9e75c0 Author: Dominik Maier <domenukk@gmail.com> Date: Sat May 1 13:24:02 2021 +0200 Tcp Broker to Broker Communication (#66) * initial b2b implementation * no_std and clippy fixes * b2b testcase added * more correct testcases * fixed b2b * typo * fixed unused warning * feedbacks now return a boolean value * use feedback_or, and modify Cargo.toml * fix diff between dev and this branch * fmt Co-authored-by: Dominik Maier <domenukk@gmail.com>
1 parent 2e192fd commit 46e010b

File tree

14 files changed

+661
-0
lines changed

14 files changed

+661
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
libpng-*
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[package]
2+
name = "libfuzzer_reachability"
3+
version = "0.2.0"
4+
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
5+
edition = "2018"
6+
7+
[features]
8+
default = ["std"]
9+
std = []
10+
11+
#[profile.release]
12+
#lto = true
13+
#codegen-units = 1
14+
#opt-level = 3
15+
#debug = true
16+
17+
[build-dependencies]
18+
cc = { version = "1.0", features = ["parallel"] }
19+
which = { version = "4.0.2" }
20+
num_cpus = "1.0"
21+
22+
[dependencies]
23+
libafl = { path = "../../libafl/" }
24+
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_hitcounts", "libfuzzer"] }
25+
# TODO Include it only when building cc
26+
libafl_cc = { path = "../../libafl_cc/" }
27+
28+
[lib]
29+
name = "libfuzzer_libpng"
30+
crate-type = ["staticlib"]
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Libfuzzer for libpng
2+
3+
This folder contains an example fuzzer for libpng, using LLMP for fast multi-process fuzzing and crash detection.
4+
5+
In contrast to other fuzzer examples, this setup uses `fuzz_loop_for`, to occasionally respawn the fuzzer executor.
6+
While this costs performance, it can be useful for targets with memory leaks or other instabilities.
7+
If your target is really instable, however, consider exchanging the `InProcessExecutor` for a `ForkserverExecutor` instead.
8+
9+
To show off crash detection, we added a `ud2` instruction to the harness, edit harness.cc if you want a non-crashing example.
10+
It has been tested on Linux.
11+
12+
## Build
13+
14+
To build this example, run
15+
16+
```bash
17+
cargo build --release
18+
```
19+
20+
This will build the library with the fuzzer (src/lib.rs) with the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback.
21+
In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(libafl_c/xx).rs) that you must use to compile the target.
22+
23+
The compiler wrappers, `libafl_cc` and libafl_cxx`, will end up in `./target/release/` (or `./target/debug`, in case you did not build with the `--release` flag).
24+
25+
Then download libpng, and unpack the archive:
26+
```bash
27+
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
28+
tar -xvf libpng-1.6.37.tar.xz
29+
```
30+
Run `patch libpng-1.6.37/png.c diff.patch` before compiling the libpng
31+
Now compile libpng, using the libafl_cc compiler wrapper:
32+
33+
```bash
34+
cd libpng-1.6.37
35+
./configure
36+
make CC=$(realpath ../target/release/libafl_cc) CXX=$(realpath ../target/release/libafl_cxx) -j `nproc`
37+
```
38+
39+
You can find the static lib at `libpng-1.6.37/.libs/libpng16.a`.
40+
41+
Now, we have to build the libfuzzer harness and link all together to create our fuzzer binary.
42+
43+
```
44+
cd ..
45+
./target/release/libafl_cxx ./harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer_libpng -lz -lm
46+
```
47+
48+
Afterward, the fuzzer will be ready to run.
49+
Note that, unless you use the `launcher`, you will have to run the binary multiple times to actually start the fuzz process, see `Run` in the following.
50+
This allows you to run multiple different builds of the same fuzzer alongside, for example, with and without ASAN (`-fsanitize=address`) or with different mutators.
51+
52+
## Run
53+
54+
The first time you run the binary, the broker will open a tcp port (currently on port `1337`), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel. Currently you must run the clients from the libfuzzer_libpng directory for them to be able to access the PNG corpus.
55+
56+
```
57+
./fuzzer_libpng
58+
59+
[libafl/src/bolts/llmp.rs:407] "We're the broker" = "We\'re the broker"
60+
Doing broker things. Run this tool again to start fuzzing in a client.
61+
```
62+
63+
And after running the above again in a separate terminal:
64+
65+
```
66+
[libafl/src/bolts/llmp.rs:1464] "New connection" = "New connection"
67+
[libafl/src/bolts/llmp.rs:1464] addr = 127.0.0.1:33500
68+
[libafl/src/bolts/llmp.rs:1464] stream.peer_addr().unwrap() = 127.0.0.1:33500
69+
[LOG Debug]: Loaded 4 initial testcases.
70+
[New Testcase #2] clients: 3, corpus: 6, objectives: 0, executions: 5, exec/sec: 0
71+
< fuzzing stats >
72+
```
73+
74+
As this example uses in-process fuzzing, we added a Restarting Event Manager (`setup_restarting_mgr`).
75+
This means each client will start itself again to listen for crashes and timeouts.
76+
By restarting the actual fuzzer, it can recover from these exit conditions.
77+
78+
In any real-world scenario, you should use `taskset` to pin each client to an empty CPU core, the lib does not pick an empty core automatically (yet).
79+
218 Bytes
Loading
Loading
Loading
Loading
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
15a16,19
2+
> #define TARGET_SIZE 4
3+
>
4+
> size_t __lafl_dummy_list[TARGET_SIZE] = {0};
5+
> size_t *__libafl_target_list = __lafl_dummy_list;
6+
2562a2567
7+
> __lafl_dummy_list[0] = 1;
8+
2584a2590
9+
> __lafl_dummy_list[1] = 1;
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// libpng_read_fuzzer.cc
2+
// Copyright 2017-2018 Glenn Randers-Pehrson
3+
// Copyright 2015 The Chromium Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style license that may
5+
// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE
6+
7+
// Last changed in libpng 1.6.35 [July 15, 2018]
8+
9+
// The modifications in 2017 by Glenn Randers-Pehrson include
10+
// 1. addition of a PNG_CLEANUP macro,
11+
// 2. setting the option to ignore ADLER32 checksums,
12+
// 3. adding "#include <string.h>" which is needed on some platforms
13+
// to provide memcpy().
14+
// 4. adding read_end_info() and creating an end_info structure.
15+
// 5. adding calls to png_set_*() transforms commonly used by browsers.
16+
17+
#include <stddef.h>
18+
#include <stdint.h>
19+
#include <string.h>
20+
21+
#include <vector>
22+
23+
#define PNG_INTERNAL
24+
#include "png.h"
25+
26+
#define PNG_CLEANUP \
27+
if(png_handler.png_ptr) \
28+
{ \
29+
if (png_handler.row_ptr) \
30+
png_free(png_handler.png_ptr, png_handler.row_ptr); \
31+
if (png_handler.end_info_ptr) \
32+
png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
33+
&png_handler.end_info_ptr); \
34+
else if (png_handler.info_ptr) \
35+
png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
36+
nullptr); \
37+
else \
38+
png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \
39+
png_handler.png_ptr = nullptr; \
40+
png_handler.row_ptr = nullptr; \
41+
png_handler.info_ptr = nullptr; \
42+
png_handler.end_info_ptr = nullptr; \
43+
}
44+
45+
struct BufState {
46+
const uint8_t* data;
47+
size_t bytes_left;
48+
};
49+
50+
struct PngObjectHandler {
51+
png_infop info_ptr = nullptr;
52+
png_structp png_ptr = nullptr;
53+
png_infop end_info_ptr = nullptr;
54+
png_voidp row_ptr = nullptr;
55+
BufState* buf_state = nullptr;
56+
57+
~PngObjectHandler() {
58+
if (row_ptr)
59+
png_free(png_ptr, row_ptr);
60+
if (end_info_ptr)
61+
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
62+
else if (info_ptr)
63+
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
64+
else
65+
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
66+
delete buf_state;
67+
}
68+
};
69+
70+
void user_read_data(png_structp png_ptr, png_bytep data, size_t length) {
71+
BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr));
72+
if (length > buf_state->bytes_left) {
73+
png_error(png_ptr, "read error");
74+
}
75+
memcpy(data, buf_state->data, length);
76+
buf_state->bytes_left -= length;
77+
buf_state->data += length;
78+
}
79+
80+
static const int kPngHeaderSize = 8;
81+
82+
// Entry point for LibFuzzer.
83+
// Roughly follows the libpng book example:
84+
// http://www.libpng.org/pub/png/book/chapter13.html
85+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
86+
if (size < kPngHeaderSize) {
87+
return 0;
88+
}
89+
90+
std::vector<unsigned char> v(data, data + size);
91+
if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) {
92+
// not a PNG.
93+
return 0;
94+
}
95+
96+
PngObjectHandler png_handler;
97+
png_handler.png_ptr = nullptr;
98+
png_handler.row_ptr = nullptr;
99+
png_handler.info_ptr = nullptr;
100+
png_handler.end_info_ptr = nullptr;
101+
102+
png_handler.png_ptr = png_create_read_struct
103+
(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
104+
if (!png_handler.png_ptr) {
105+
return 0;
106+
}
107+
108+
png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);
109+
if (!png_handler.info_ptr) {
110+
PNG_CLEANUP
111+
return 0;
112+
}
113+
114+
png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);
115+
if (!png_handler.end_info_ptr) {
116+
PNG_CLEANUP
117+
return 0;
118+
}
119+
120+
png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
121+
#ifdef PNG_IGNORE_ADLER32
122+
png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
123+
#endif
124+
125+
// Setting up reading from buffer.
126+
png_handler.buf_state = new BufState();
127+
png_handler.buf_state->data = data + kPngHeaderSize;
128+
png_handler.buf_state->bytes_left = size - kPngHeaderSize;
129+
png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);
130+
png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);
131+
132+
if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
133+
PNG_CLEANUP
134+
return 0;
135+
}
136+
137+
// Reading.
138+
png_read_info(png_handler.png_ptr, png_handler.info_ptr);
139+
140+
// reset error handler to put png_deleter into scope.
141+
if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
142+
PNG_CLEANUP
143+
return 0;
144+
}
145+
146+
png_uint_32 width, height;
147+
int bit_depth, color_type, interlace_type, compression_type;
148+
int filter_type;
149+
150+
if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,
151+
&height, &bit_depth, &color_type, &interlace_type,
152+
&compression_type, &filter_type)) {
153+
PNG_CLEANUP
154+
return 0;
155+
}
156+
157+
// This is going to be too slow.
158+
if (width && height > 100000000 / width) {
159+
PNG_CLEANUP
160+
#ifdef HAS_DUMMY_CRASH
161+
#ifdef __aarch64__
162+
asm volatile (".word 0xf7f0a000\n");
163+
#else
164+
asm("ud2");
165+
#endif
166+
#endif
167+
return 0;
168+
}
169+
170+
// Set several transforms that browsers typically use:
171+
png_set_gray_to_rgb(png_handler.png_ptr);
172+
png_set_expand(png_handler.png_ptr);
173+
png_set_packing(png_handler.png_ptr);
174+
png_set_scale_16(png_handler.png_ptr);
175+
png_set_tRNS_to_alpha(png_handler.png_ptr);
176+
177+
int passes = png_set_interlace_handling(png_handler.png_ptr);
178+
179+
png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);
180+
181+
png_handler.row_ptr = png_malloc(
182+
png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,
183+
png_handler.info_ptr));
184+
185+
for (int pass = 0; pass < passes; ++pass) {
186+
for (png_uint_32 y = 0; y < height; ++y) {
187+
png_read_row(png_handler.png_ptr,
188+
static_cast<png_bytep>(png_handler.row_ptr), nullptr);
189+
}
190+
}
191+
192+
png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
193+
194+
PNG_CLEANUP
195+
return 0;
196+
}
197+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use libafl_cc::{ClangWrapper, CompilerWrapper, LIB_EXT, LIB_PREFIX};
2+
use std::env;
3+
4+
fn main() {
5+
let args: Vec<String> = env::args().collect();
6+
if args.len() > 1 {
7+
let mut dir = env::current_exe().unwrap();
8+
dir.pop();
9+
10+
let mut cc = ClangWrapper::new("clang", "clang++");
11+
cc.from_args(&args)
12+
.unwrap()
13+
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
14+
.unwrap()
15+
.add_link_arg(
16+
dir.join(format!("{}libfuzzer_libpng.{}", LIB_PREFIX, LIB_EXT))
17+
.display()
18+
.to_string(),
19+
)
20+
.unwrap();
21+
// Libraries needed by libafl on Windows
22+
#[cfg(windows)]
23+
cc.add_link_arg("-lws2_32".into())
24+
.unwrap()
25+
.add_link_arg("-lBcrypt".into())
26+
.unwrap()
27+
.add_link_arg("-lAdvapi32".into())
28+
.unwrap();
29+
cc.run().unwrap();
30+
} else {
31+
panic!("LibAFL CC: No Arguments given");
32+
}
33+
}

0 commit comments

Comments
 (0)