diff --git a/.gitignore b/.gitignore index b6ed83c55d..915686f0b8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ doc/doxygen/*.tmp *bin # Build directory /build +# AFL findings +fuzzing/**/findings/ # Backup files *~ *.orig diff --git a/Makefile.include b/Makefile.include index 2aa7c7647c..8f0e050356 100644 --- a/Makefile.include +++ b/Makefile.include @@ -747,6 +747,11 @@ test-input-hash: true endif +.PHONY: fuzz +fuzz: + env FLASHFILE="$(FLASHFILE)" PORT="$(PORT)" TERMFLAGS="$(TERMFLAGS)" \ + "$(RIOTBASE)"/dist/tools/fuzzing/afl.sh $(AFL_FLAGS) + # Default OBJDUMPFLAGS for platforms which do not specify it: OBJDUMPFLAGS ?= -S -D -h diff --git a/dist/tools/fuzzing/afl.sh b/dist/tools/fuzzing/afl.sh new file mode 100755 index 0000000000..d0bb7bf6c3 --- /dev/null +++ b/dist/tools/fuzzing/afl.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ ! -d "${APPDIR}/input" ]; then + echo "${APPDIR}: Doesn't provide a test corpus" 1>&2 + exit 1 +fi + +mkdir -p "${APPDIR}/findings" +exec afl-fuzz -m 800 -i "${APPDIR}/input" -o "${APPDIR}/findings" "$@" -- \ + "${FLASHFILE}" "${PORT}" ${TERMFLAGS} diff --git a/fuzzing/Makefile.fuzzing_common b/fuzzing/Makefile.fuzzing_common new file mode 100644 index 0000000000..8766f575fe --- /dev/null +++ b/fuzzing/Makefile.fuzzing_common @@ -0,0 +1,21 @@ +RIOTBASE ?= $(CURDIR)/../.. + +# Instrumend code with AFL by default +TOOLCHAIN ?= afl + +# Automatically set application to a sensible default +APPLICATION ?= fuzzing_$(notdir $(patsubst %/,%,$(CURDIR))) + +# Fuzzing is only supported on native +BOARD ?= native +FEATURES_REQUIRED += arch_native + +CFLAGS += -ggdb # Make ASAN output more useful error messages +CFLAGS += -D_FORTIFY_SOURCE=2 # Compiler hardening + +# Various utilitiy modules +USEMODULE += fuzzing +USEMODULE += ssp + +# Enable DEVELHELP by default +DEVELHELP ?= 1 diff --git a/fuzzing/README.md b/fuzzing/README.md new file mode 100644 index 0000000000..baad60f05b --- /dev/null +++ b/fuzzing/README.md @@ -0,0 +1,35 @@ +# Fuzzing + +Automated fuzzing tests for RIOT network applications. + +## Setup + +The following additional dependencies are required: + +* [afl][afl homepage] +* [libasan][sanitizers github] (optional but recommended) + +## Invocation + +Before fuzzing an application it needs to be compiled, to ease detection +of unwanted behaviour (e.g. out-of-bounds buffer accesses), compiling +with `all-asan` is highly recommended. For example: + + make -C fuzzing/ all-asan + +Afterwards invoke afl using: + + make -C fuzzing/ fuzz + +### Parallel Fuzzing + +Parallel fuzzing is supported through `AFL_FLAGS`, e.g.: + + # Start first AFL instance + AFL_FLAGS="-M fuzzer01" make -C fuzzing/gnrc_tcp/ fuzz + + # Start second AFL instance in a different terminal + AFL_FLAGS="-M fuzzer02" make -C fuzzing/gnrc_tcp/ fuzz + +[sanitizers github]: https://github.com/google/sanitizers +[afl homepage]: http://lcamtuf.coredump.cx/afl/ diff --git a/makefiles/vars.inc.mk b/makefiles/vars.inc.mk index c96c626452..16b6a7e72d 100644 --- a/makefiles/vars.inc.mk +++ b/makefiles/vars.inc.mk @@ -106,4 +106,6 @@ export UNZIP_HERE # Use `cd $(SOME_FOLDER) && $(UNZIP_HERE) $(SOME_FI export LAZYSPONGE # Command saving stdin to a file only on content update. export LAZYSPONGE_FLAGS # Parameters supplied to LAZYSPONGE. +export AFL_FLAGS # Additional command-line flags passed to afl during fuzzing. + # LOG_LEVEL # Logging level as integer (NONE: 0, ERROR: 1, WARNING: 2, INFO: 3, DEBUG: 4, default: 3)