From f41c6aaf630292720780a2f59ced25706aab35e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20R=C3=BChsen?= Date: Fri, 9 Jun 2017 16:27:37 +0200 Subject: [PATCH] Add fuzzing architecture --- Makefile.am | 26 +++-- configure.ac | 1 + fuzz/Makefile.am | 42 ++++++++ fuzz/README.md | 63 +++++++++++ fuzz/coverage.sh | 5 + fuzz/fuzzer.h | 28 +++++ fuzz/libpsl_fuzzer.c | 56 ++++++++++ fuzz/libpsl_fuzzer.in/com | 1 + fuzz/libpsl_fuzzer.in/multibyte | 1 + fuzz/libpsl_fuzzer.in/tld | 1 + fuzz/libpsl_load_dafsa_fuzzer.c | 59 ++++++++++ fuzz/libpsl_load_dafsa_fuzzer.in/dafsa | 1 + fuzz/main.c | 144 +++++++++++++++++++++++++ fuzz/run-afl.sh | 67 ++++++++++++ fuzz/run-clang.sh | 49 +++++++++ fuzz/view-coverage.sh | 21 ++++ 16 files changed, 559 insertions(+), 6 deletions(-) create mode 100644 fuzz/Makefile.am create mode 100644 fuzz/README.md create mode 100755 fuzz/coverage.sh create mode 100644 fuzz/fuzzer.h create mode 100644 fuzz/libpsl_fuzzer.c create mode 100644 fuzz/libpsl_fuzzer.in/com create mode 100644 fuzz/libpsl_fuzzer.in/multibyte create mode 100644 fuzz/libpsl_fuzzer.in/tld create mode 100644 fuzz/libpsl_load_dafsa_fuzzer.c create mode 100644 fuzz/libpsl_load_dafsa_fuzzer.in/dafsa create mode 100644 fuzz/main.c create mode 100755 fuzz/run-afl.sh create mode 100755 fuzz/run-clang.sh create mode 100755 fuzz/view-coverage.sh diff --git a/Makefile.am b/Makefile.am index 2dd232f..6cbb334 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ # got some hints from https://gitorious.org/openismus-playground/examplelib/source -SUBDIRS = po include src tools $(LIBPSL_DOCS) tests +SUBDIRS = po include src tools $(LIBPSL_DOCS) fuzz tests ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} @@ -23,17 +23,20 @@ dist-hook: clean-local: rm -rf */*.gc?? */*/*.gc?? libpsl.info lcov -check-coverage: +LCOV_INFO=libpsl.info +check-coverage: clean if test -z "$(XLIB)"; then \ CFLAGS=$$CFLAGS" --coverage -O0" LDFLAGS=$$LDFLAGS" --coverage" ./configure --disable-runtime --disable-builtin; \ else \ CFLAGS=$$CFLAGS" --coverage -O0" LDFLAGS=$$LDFLAGS" --coverage" ./configure --enable-runtime=$(XLIB) --enable-builtin=$(XLIB); \ fi - $(MAKE) clean && $(MAKE) - lcov --capture --initial --directory src --output-file libpsl.info + $(MAKE) + lcov --capture --initial --directory src --output-file $(LCOV_INFO) $(MAKE) check - lcov --capture --directory src --output-file libpsl.info - genhtml --prefix . libpsl.info --legend --title "libpsl" --output-directory=lcov + lcov --capture --directory src --output-file $(LCOV_INFO) + genhtml --prefix . $(LCOV_INFO) --legend --title "libpsl" --output-directory=lcov + @echo + @echo "You can now view the coverage report with 'xdg-open lcov/index.html'" check-coverage-libidn: XLIB=libidn $(MAKE) check-coverage @@ -43,3 +46,14 @@ check-coverage-libidn2: check-coverage-libicu: XLIB=libicu $(MAKE) check-coverage + +fuzz-coverage: clean + $(MAKE) -C src CFLAGS="$(CFLAGS) --coverage" LDFLAGS="$(LDFLAGS) --coverage" + $(MAKE) -C fuzz fuzz-coverage CFLAGS="$(CFLAGS) --coverage" LDFLAGS="$(LDFLAGS) --coverage" + lcov --capture --initial --directory src --directory fuzz --output-file $(LCOV_INFO) + lcov --capture --directory src --directory fuzz --output-file $(LCOV_INFO) +# lcov --remove $(LCOV_INFO) '*/test_linking.c' '*/css_tokenizer.lex' '*/' -o $(LCOV_INFO) + genhtml --prefix . --ignore-errors source $(LCOV_INFO) --legend --title "libpsl-fuzz" --output-directory=lcov + @echo + @echo "You can now view the coverage report with 'xdg-open lcov/index.html'" + diff --git a/configure.ac b/configure.ac index 2e2b3fa..f8a2583 100644 --- a/configure.ac +++ b/configure.ac @@ -273,6 +273,7 @@ AC_CONFIG_FILES([Makefile src/Makefile tools/Makefile po/Makefile.in + fuzz/Makefile tests/Makefile libpsl.pc:libpsl.pc.in]) AC_OUTPUT diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am new file mode 100644 index 0000000..584d07a --- /dev/null +++ b/fuzz/Makefile.am @@ -0,0 +1,42 @@ +AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS) -Wno-unused-parameter +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(srcdir) -DSRCDIR=\"$(abs_srcdir)\" -DTEST_RUN +AM_LDFLAGS = -static +LDADD = ../src/libpsl.la + +PSL_TESTS = \ + libpsl_fuzzer$(EXEEXT) \ + libpsl_load_dafsa_fuzzer$(EXEEXT) + +check_PROGRAMS = $(PSL_TESTS) + +libpsl_fuzzer_SOURCES = libpsl_fuzzer.c main.c fuzzer.h +libpsl_load_dafsa_fuzzer_SOURCES = libpsl_load_dafsa_fuzzer.c main.c fuzzer.h + +dist-hook: + find . -name '*.options' -exec cp -v '{}' $(distdir) ';' + find . -name '*.dict' -exec cp -v '{}' $(distdir) ';' + find . -name '*.in' -exec cp -vr '{}' $(distdir) ';' + find . -name '*.repro' -exec cp -vr '{}' $(distdir) ';' + +TESTS_ENVIRONMENT = TESTS_VALGRIND="@VALGRIND_ENVIRONMENT@" +TESTS = $(PSL_TESTS) + +clean-local: + rm -rf *.gc?? *.log lcov coverage.info + +fuzz-coverage: $(PSL_TESTS) + find . -name '*_fuzzer' -exec ./coverage.sh '{}' ';' + +oss-fuzz: + if test "$$OUT" != ""; then \ + for ccfile in *_fuzzer.c; do \ + fuzzer=$$(basename $$ccfile .c); \ + $$CXX $$CXXFLAGS -I$(top_srcdir)/include -I$(top_srcdir) \ + "$${fuzzer}.c" -o "$${fuzzer}" \ + ../src/.libs/libpsl.a $${LIB_FUZZING_ENGINE} -Wl,-Bstatic \ + -lidn2 -lunistring \ + -Wl,-Bdynamic; \ + done; \ + fi + +.PHONY: oss-fuzz diff --git a/fuzz/README.md b/fuzz/README.md new file mode 100644 index 0000000..5f709e4 --- /dev/null +++ b/fuzz/README.md @@ -0,0 +1,63 @@ +# Fuzzers + +These are fuzzers designed for use with `libFuzzer` or `afl`. They can +be used to run on Google's OSS-Fuzz (https://github.com/google/oss-fuzz/). + +The convention used here is that the initial values for each parser fuzzer +are taken from the $NAME.in directory. + +Crash reproducers from OSS-Fuzz are put into $NAME.repro directory for +regression testing with top dir 'make check' or 'make check-valgrind'. + + +# Running a fuzzer using clang + +Use the following commands on top dir: +``` +export CC=clang-5.0 +export CXX=clang++-5.0 +export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize-coverage=trace-pc-guard,trace-cmp" +export CXXFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize-coverage=trace-pc-guard,trace-cmp -stdlib=libc++" +./configure --enable-static --disable-gtk-doc +make clean +make -j$(nproc) +cd fuzz + +# build and run libpsl_fuzzer +./run-clang.sh libpsl_fuzzer +``` + + +# Running a fuzzer using AFL + +Use the following commands on top dir: + +``` +$ CC=afl-clang-fast ./configure --disable-gtk-doc +$ make -j$(nproc) clean all +$ cd fuzz +$ ./run-afl.sh libpsl_fuzzer +``` + +# Fuzz code coverage using the corpus directories *.in/ + +Code coverage reports currently work best with gcc+lcov+genhtml. + +In the top directory: +``` +CC=gcc CFLAGS="-O0 -g" ./configure --disable-gtk-doc +make fuzz-coverage +xdg-open lcov/index.html +``` + +Each fuzzer target has it's own functions to cover, e.g. +`libpsl_fuzzer` covers psl_is_public_suffix. + +To work on corpora for better coverage, `cd fuzz` and use e.g. +`./view-coverage.sh libpsl_fuzzer`. + + +# Enhancing the testsuite for issues found + +Each reproducer file should be dropped into the appropriate *.repro/ +directory. diff --git a/fuzz/coverage.sh b/fuzz/coverage.sh new file mode 100755 index 0000000..539aa8c --- /dev/null +++ b/fuzz/coverage.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +for f in $1.in/*; do + $1 < $f >/dev/null +done diff --git a/fuzz/fuzzer.h b/fuzz/fuzzer.h new file mode 100644 index 0000000..0f18740 --- /dev/null +++ b/fuzz/fuzzer.h @@ -0,0 +1,28 @@ +/* + * Copyright(c) 2017 Tim Ruehsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of libpsl. + */ + +#include // size_t +#include // uint8_t + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); diff --git a/fuzz/libpsl_fuzzer.c b/fuzz/libpsl_fuzzer.c new file mode 100644 index 0000000..0e8c09a --- /dev/null +++ b/fuzz/libpsl_fuzzer.c @@ -0,0 +1,56 @@ +/* + * Copyright(c) 2017 Tim Ruehsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of libpsl. + */ + +#include + +#include // assert +#include // uint8_t +#include // malloc, free +#include // memcpy + +#include "libpsl.h" +#include "fuzzer.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *domain = (char *) malloc(size + 1); + + assert(domain != NULL); + + // 0 terminate + memcpy(domain, data, size); + domain[size] = 0; + + psl_ctx_t *psl; + psl = (psl_ctx_t *) psl_builtin(); + psl_is_public_suffix(NULL, domain); + psl_is_public_suffix(psl, domain); + psl_is_public_suffix2(psl, domain, PSL_TYPE_PRIVATE); + psl_is_public_suffix2(psl, domain, PSL_TYPE_ICANN); + psl_free(psl); + + free(domain); + + return 0; +} diff --git a/fuzz/libpsl_fuzzer.in/com b/fuzz/libpsl_fuzzer.in/com new file mode 100644 index 0000000..4b9c176 --- /dev/null +++ b/fuzz/libpsl_fuzzer.in/com @@ -0,0 +1 @@ +x.com diff --git a/fuzz/libpsl_fuzzer.in/multibyte b/fuzz/libpsl_fuzzer.in/multibyte new file mode 100644 index 0000000..7e5bb96 --- /dev/null +++ b/fuzz/libpsl_fuzzer.in/multibyte @@ -0,0 +1 @@ +.äöü.de diff --git a/fuzz/libpsl_fuzzer.in/tld b/fuzz/libpsl_fuzzer.in/tld new file mode 100644 index 0000000..587be6b --- /dev/null +++ b/fuzz/libpsl_fuzzer.in/tld @@ -0,0 +1 @@ +x diff --git a/fuzz/libpsl_load_dafsa_fuzzer.c b/fuzz/libpsl_load_dafsa_fuzzer.c new file mode 100644 index 0000000..9bf0080 --- /dev/null +++ b/fuzz/libpsl_load_dafsa_fuzzer.c @@ -0,0 +1,59 @@ +/* + * Copyright(c) 2017 Tim Ruehsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of libpsl. + */ + +#include + +#include // assert +#include // uint8_t +#include // malloc, free +#include // memcpy + +#include "libpsl.h" +#include "fuzzer.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *in = (char *) malloc(size + 16); + + assert(in != NULL); + + // create a valid DAFSA input file + memcpy(in, ".DAFSA@PSL_0 \n", 16); + memcpy(in + 16, data, size); + + FILE *fp = fmemopen(in, size + 16, "r"); + assert(fp != NULL); + + psl_ctx_t *psl; + psl = psl_load_fp(fp); + + psl_is_public_suffix(NULL, NULL); + psl_is_public_suffix(psl, ".ü.com"); + psl_free(psl); + + fclose(fp); + free(in); + + return 0; +} diff --git a/fuzz/libpsl_load_dafsa_fuzzer.in/dafsa b/fuzz/libpsl_load_dafsa_fuzzer.in/dafsa new file mode 100644 index 0000000..18a27c1 --- /dev/null +++ b/fuzz/libpsl_load_dafsa_fuzzer.in/dafsa @@ -0,0 +1 @@ +aguchDuzzo.io.khazia.srko.chieno.osakashiri.hokkaido.jy.ctrborte.a.pr` NsRprod.fastly.neutilitie000.hkapp.comemm.com.bg \ No newline at end of file diff --git a/fuzz/main.c b/fuzz/main.c new file mode 100644 index 0000000..ac4caaf --- /dev/null +++ b/fuzz/main.c @@ -0,0 +1,144 @@ +/* + * Copyright(c) 2017 Tim Ruehsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of libpsl. + */ + +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fuzzer.h" + +#ifdef TEST_RUN + +#include + +static void test_all_from(const char *dirname) +{ + DIR *dirp; + struct dirent *dp; + + if ((dirp = opendir(dirname))) { + while ((dp = readdir(dirp))) { + if (*dp->d_name == '.') continue; + + char fname[strlen(dirname) + strlen(dp->d_name) + 2]; + snprintf(fname, sizeof(fname), "%s/%s", dirname, dp->d_name); + + int fd; + if ((fd = open(fname, O_RDONLY)) == -1) { + fprintf(stderr, "Failed to open %s (%d)\n", fname, errno); + continue; + } + + struct stat st; + if (fstat(fd, &st) != 0) { + fprintf(stderr, "Failed to stat %d (%d)\n", fd, errno); + close(fd); + continue; + } + + uint8_t *data = malloc(st.st_size); + ssize_t n; + if ((n = read(fd, data, st.st_size)) == st.st_size) { + printf("testing %zu bytes from '%s'\n", st.st_size, fname); + LLVMFuzzerTestOneInput(data, st.st_size); + } else + fprintf(stderr, "Failed to read %zu bytes from %s (%d), got %zd\n", st.st_size, fname, errno, n); + + free(data); + close(fd); + } + closedir(dirp); + } +} + +int main(int argc, char **argv) +{ + /* if VALGRIND testing is enabled, we have to call ourselves with valgrind checking */ + if (argc == 1) { + const char *valgrind = getenv("TESTS_VALGRIND"); + + if (valgrind && *valgrind) { + size_t cmdsize = strlen(valgrind) + strlen(argv[0]) + 32; + char *cmd = alloca(cmdsize); + + snprintf(cmd, cmdsize, "TESTS_VALGRIND="" %s %s", valgrind, argv[0]); + return system(cmd) != 0; + } + } + + const char *target = strrchr(argv[0], '/'); + target = target ? target + 1 : argv[0]; + + char corporadir[sizeof(SRCDIR) + 1 + strlen(target) + 8]; + snprintf(corporadir, sizeof(corporadir), SRCDIR "/%s.in", target); + + test_all_from(corporadir); + + snprintf(corporadir, sizeof(corporadir), SRCDIR "/%s.repro", target); + + test_all_from(corporadir); + + return 0; +} + +#else + +#ifndef __AFL_LOOP +static int __AFL_LOOP(int n) +{ + static int first = 1; + + if (first) { + first = 0; + return 1; + } + + return 0; +} +#endif + +int main(int argc, char **argv) +{ + int ret; + unsigned char buf[64 * 1024]; + + while (__AFL_LOOP(10000)) { // only works with afl-clang-fast + ret = fread(buf, 1, sizeof(buf), stdin); + if (ret < 0) + return 0; + + LLVMFuzzerTestOneInput(buf, ret); + } + + return 0; +} + +#endif /* TEST_RUN */ diff --git a/fuzz/run-afl.sh b/fuzz/run-afl.sh new file mode 100755 index 0000000..41d9aea --- /dev/null +++ b/fuzz/run-afl.sh @@ -0,0 +1,67 @@ +#!/bin/sh -eu +# +# Copyright(c) 2017 Tim Ruehsen +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# This file is part of libpsl. + +srcdir="${srcdir:-.}" +export LD_LIBRARY_PATH=${srcdir}/../lib/.libs/ + +cat ${srcdir}/../config.log|grep afl-clang-fast >/dev/null 2>&1 +if test $? != 0; then + echo "compile first library as:" + echo "CC=afl-clang-fast ./configure" + exit 1 +fi + +if test -z "$1"; then + echo "Usage: $0 test-case" + echo "Example: $0 libpsl_fuzzer" + exit 1 +fi + +rm -f $1 +CFLAGS="-g -O2" CC=afl-clang-fast make "$1" || exit 1 + +### minimize test corpora +if test -d ${fuzzer}.in; then + mkdir -p ${fuzzer}.min + for i in `ls ${fuzzer}.in`; do + fin="${fuzzer}.in/$i" + fmin="${fuzzer}.min/$i" + if ! test -e $fmin || test $fin -nt $fmin; then + afl-tmin -i $fin -o $fmin -- ./${fuzzer} + fi + done +fi + +TMPOUT=${fuzzer}.$$.out +mkdir -p ${TMPOUT} + +if test -f ${fuzzer}.dict; then + afl-fuzz -i ${fuzzer}.min -o ${TMPOUT} -x ${fuzzer}.dict -- ./${fuzzer} +else + afl-fuzz -i ${fuzzer}.min -o ${TMPOUT} -- ./${fuzzer} +fi + +echo "output was stored in $TMPOUT" + +exit 0 diff --git a/fuzz/run-clang.sh b/fuzz/run-clang.sh new file mode 100755 index 0000000..70c9122 --- /dev/null +++ b/fuzz/run-clang.sh @@ -0,0 +1,49 @@ +#!/bin/sh -eu +# +# Copyright(c) 2017 Tim Ruehsen +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# This file is part of libpsl. + +if test -z "$1"; then + echo "Usage: $0 " + echo "Example: $0 libpsl_fuzzer" + exit 1 +fi + +fuzzer=$1 +workers=4 + +clang-5.0 \ + $CFLAGS -I../include -I.. \ + ${fuzzer}.c -o ${fuzzer} \ + -Wl,-Bstatic ../src/.libs/libpsl.a -lFuzzer \ + -Wl,-Bdynamic -lidn2 -lunistring -lclang-5.0 -lstdc++ + +# create directory for NEW test corpora (covering new areas of code) +mkdir -p ${fuzzer}.new + +if test -f ${fuzzer}.dict; then + ./${fuzzer} -workers=$workers -dict=${fuzzer}.dict ${fuzzer}.new ${fuzzer}.in +else + ./${fuzzer} -workers=$workers ${fuzzer}.new ${fuzzer}.in +fi + +exit 0 diff --git a/fuzz/view-coverage.sh b/fuzz/view-coverage.sh new file mode 100755 index 0000000..08c63cf --- /dev/null +++ b/fuzz/view-coverage.sh @@ -0,0 +1,21 @@ +#!/bin/bash -eu + +# 1. execute 'make fuzz-coverage' in the top directory +# 2. execute './view-coverage.sh +# example: ./view-coverage.sh libpsl_fuzzer + +if test -z "$1"; then + echo "Usage: $0 " + echo "Example: $0 libpsl_fuzzer" + exit 1 +fi + +fuzzer="./"$1 +LCOV_INFO=coverage.info +#make fuzz-coverage CFLAGS="$(CFLAGS) --coverage" LDFLAGS="$(LDFLAGS) --coverage" +./coverage.sh $fuzzer +lcov --capture --initial --directory ../src --directory . --output-file $LCOV_INFO +lcov --capture --directory ../src --output-file $LCOV_INFO +#lcov --remove $LCOV_INFO '*/test_linking.c' '*/css_tokenizer.lex' '*/' '*/*.h' -o $LCOV_INFO +genhtml --prefix . --ignore-errors source $LCOV_INFO --legend --title "$1" --output-directory=lcov +xdg-open lcov/index.html