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.
This commit is contained in:
Phil Turnbull 2017-06-26 15:05:30 -04:00
parent 70a6a16814
commit c1dea4ee50
6 changed files with 60 additions and 0 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

28
test/cmark-fuzz.c Normal file
View File

@ -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;
}

4
test/run-cmark-fuzz Executable file
View File

@ -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 "$@"