summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Turnbull <philipturnbull@github.com>2017-06-26 15:05:30 -0400
committerPhil Turnbull <philipturnbull@github.com>2017-06-27 15:37:04 -0400
commitc1dea4ee507ef62b121051e34e36a9b24459ea39 (patch)
treeb08c2272ff191ea8ee29ebac00ecd9bd8b89aa84
parent70a6a168146baa6ab0df33d4ddf424ba5d40b151 (diff)
Add Makefile target and harness to fuzz with libFuzzer
This can be run locally with `make libFuzzer` but the harness will be integrated into oss-fuzz for large-scale fuzzing.
-rwxr-xr-xCMakeLists.txt1
-rw-r--r--Makefile8
-rw-r--r--README.md8
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--test/cmark-fuzz.c28
-rwxr-xr-xtest/run-cmark-fuzz4
6 files changed, 60 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4e60fd5..33180e5 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@ set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_
option(CMARK_TESTS "Build cmark tests and enable testing" ON)
option(CMARK_STATIC "Build static libcmark library" ON)
option(CMARK_SHARED "Build shared libcmark library" ON)
+option(CMARK_LIB_FUZZER "Build libFuzzer fuzzing harness" OFF)
add_subdirectory(src)
if(CMARK_TESTS AND CMARK_SHARED)
diff --git a/Makefile b/Makefile
index 1b58bf7..c10c035 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@ BENCHFILE=$(BENCHDIR)/benchinput.md
ALLTESTS=alltests.md
NUMRUNS?=10
CMARK=$(BUILDDIR)/src/cmark
+CMARK_FUZZ=$(BUILDDIR)/src/cmark-fuzz
PROG?=$(CMARK)
VERSION?=$(SPECVERSION)
RELEASE?=CommonMark-$(VERSION)
@@ -81,6 +82,13 @@ afl:
-t 100 \
$(CMARK) $(CMARK_OPTS)
+libFuzzer:
+ @[ -n "$(LIB_FUZZER_PATH)" ] || { echo '$$LIB_FUZZER_PATH not set'; false; }
+ mkdir -p $(BUILDDIR)
+ cd $(BUILDDIR) && cmake -DCMAKE_BUILD_TYPE=Asan -DCMARK_LIB_FUZZER=ON -DCMAKE_LIB_FUZZER_PATH=$(LIB_FUZZER_PATH) ..
+ $(MAKE) -j2 -C $(BUILDDIR) cmark-fuzz
+ test/run-cmark-fuzz $(CMARK_FUZZ)
+
clang-check: all
${CLANG_CHECK} -p build -analyze src/*.c
diff --git a/README.md b/README.md
index 9aaf32f..1c9dd69 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,13 @@ To do a more systematic fuzz test with [american fuzzy lop]:
AFL_PATH=/path/to/afl_directory make afl
+Fuzzing with [libFuzzer] is also supported but, because libFuzzer is still
+under active development, may not work with your system-installed version of
+clang. Assuming LLVM has been built in `$HOME/src/llvm/build` the fuzzer can be
+run with:
+
+ CC="$HOME/src/llvm/build/bin/clang" LIB_FUZZER_PATH="$HOME/src/llvm/lib/Fuzzer/libFuzzer.a" make libFuzzer
+
To make a release tarball and zip archive:
make archive
@@ -188,3 +195,4 @@ most of the C library's API and its test harness.
[Build Status]: https://img.shields.io/travis/jgm/cmark/master.svg?style=flat
[Windows Build Status]: https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true
[american fuzzy lop]: http://lcamtuf.coredump.cx/afl/
+[libFuzzer]: http://llvm.org/docs/LibFuzzer.html
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f52ded6..3197196 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -186,3 +186,14 @@ endif()
if(CMAKE_BUILD_TYPE STREQUAL "Ubsan")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
endif()
+
+if(CMARK_LIB_FUZZER)
+ set(FUZZ_HARNESS "cmark-fuzz")
+ add_executable(${FUZZ_HARNESS} ../test/cmark-fuzz.c ${LIBRARY_SOURCES})
+ target_link_libraries(${FUZZ_HARNESS} "${CMAKE_LIB_FUZZER_PATH}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-coverage=trace-pc-guard")
+
+ # cmark is written in C but the libFuzzer runtime is written in C++ which
+ # needs to link against the C++ runtime. Explicitly link it into cmark-fuzz
+ set_target_properties(${FUZZ_HARNESS} PROPERTIES LINK_FLAGS "-lstdc++")
+endif()
diff --git a/test/cmark-fuzz.c b/test/cmark-fuzz.c
new file mode 100644
index 0000000..f09db52
--- /dev/null
+++ b/test/cmark-fuzz.c
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include "cmark.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ int options = 0;
+ if (size > sizeof(options)) {
+ /* First 4 bytes of input are treated as options */
+ int options = *(const int *)data;
+
+ /* Mask off valid option bits */
+ options = options & (CMARK_OPT_SOURCEPOS | CMARK_OPT_HARDBREAKS | CMARK_OPT_SAFE | CMARK_OPT_NOBREAKS | CMARK_OPT_NORMALIZE | CMARK_OPT_VALIDATE_UTF8 | CMARK_OPT_SMART);
+
+ /* Remainder of input is the markdown */
+ const char *markdown = (const char *)(data + sizeof(options));
+ const size_t markdown_size = size - sizeof(options);
+ cmark_node *doc = cmark_parse_document(markdown, markdown_size, options);
+
+ free(cmark_render_commonmark(doc, options, 80));
+ free(cmark_render_html(doc, options));
+ free(cmark_render_latex(doc, options, 80));
+ free(cmark_render_man(doc, options, 80));
+ free(cmark_render_xml(doc, options));
+
+ cmark_node_free(doc);
+ }
+ return 0;
+}
diff --git a/test/run-cmark-fuzz b/test/run-cmark-fuzz
new file mode 100755
index 0000000..75100b8
--- /dev/null
+++ b/test/run-cmark-fuzz
@@ -0,0 +1,4 @@
+#!/bin/bash -eu
+CMARK_FUZZ="$1"
+shift
+ASAN_OPTIONS="quarantine_size_mb=10:detect_leaks=1" "${CMARK_FUZZ}" -max_len=256 -timeout=1 -dict=test/fuzzing_dictionary "$@"