Commit 322f3986 authored by Ondřej Surý's avatar Ondřej Surý

Add support for AFL Persistent Fuzzing Mode based on work by Jonathan Foote <jfoote@fastly.com>

parent a11e00b8
# Fuzzing
Knot DNS 2.0 includes `tests-fuzz/packet.c`. This compiles into a
test harness that is designed to be used with lcamtuf's [American
Fuzzy Lop (AFL) fuzzer](http://lcamtuf.coredump.cx/afl/). The test
harness exercises the packet parsing logic in Knot DNS.
## How it works
AFL 1.83b includes an experimental feature called ["persistent
mode"](http://lcamtuf.blogspot.com/2015/06/new-in-afl-persistent-mode.html)
that can be used to control AFL's fork server to fuzz inputs and
exercise the program without restarting it. You can use this new
feature along with the included Knot DNS test harness.
## Using the AFL persistent harness
### Gathering seed inputs
Gathering DNS packets for use in fuzzing is left to the tester, but
note that the fuzzing shim includes an environment variable to support
test cases minimization with `afl-cmin`:
```
$ KNOT_AFL_STDIN=1 KNOT_AFL_CMIN=1 afl-cmin -i ~/knot-seeds -o ~/knot-seeds-cmin -m 1000000 -t 400000 -- tests-fuzz/packet
```
### Compiling the test harness.
See the AFL [blog
post](http://lcamtuf.blogspot.com/2015/06/new-in-afl-persistent-mode.html)
and README for details on how to use LLVM mode and compile binaries
for use with persistent mode. For reference, you can use these
commands to build Knot with the fuzzing harness:
```
$ CC=afl-clang-fast ./configure --disable-shared
$ make check
```
### Fuzz
A basic AFL run can then be kicked off as follows:
```
AFL_PERSISTENT=1 afl-fuzz -i my_seeds -o my_output_dir -t 10000 -m 100000 -- tests-fuzz/packet
```
Note that AFL can be scaled up by supplying the `-M` flag and starting
multiple instances of the fuzzer.
......@@ -17,6 +17,7 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include "libknot/errcode.h"
#include "libknot/packet/pkt.h"
......@@ -25,19 +26,25 @@
int main(void)
{
log("reading packet data from stdin");
uint8_t buffer[UINT16_MAX + 1] = { 0 };
size_t len = fread(buffer, 1, sizeof(buffer), stdin);
log("parsing packet of size %zu", len);
knot_pkt_t *pkt = knot_pkt_new(buffer, len, NULL);
assert(pkt);
int r = knot_pkt_parse(pkt, 0);
knot_pkt_free(&pkt);
log("result %d (%s)", r, r == KNOT_EOK ? "success" : "failure");
return (r == KNOT_EOK ? 0 : 1);
for(;;) {
log("reading packet data from stdin");
uint8_t buffer[UINT16_MAX + 1] = { 0 };
size_t len = fread(buffer, 1, sizeof(buffer), stdin);
log("parsing packet of size %zu", len);
knot_pkt_t *pkt = knot_pkt_new(buffer, len, NULL);
assert(pkt);
int r = knot_pkt_parse(pkt, 0);
knot_pkt_free(&pkt);
log("result %d (%s)", r, r == KNOT_EOK ? "success" : "failure");
if (getenv("AFL_PERSISTENT")) {
raise(SIGSTOP);
} else {
return (r == KNOT_EOK ? 0 : 1);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment