diff --git a/.travis.yml b/.travis.yml index a3e0733a7..65a32951a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ before_script: # TODO remove built in cmocka compile and use system cmocka (including brewfile) once xenial is default - git clone https://git.cryptomilk.org/projects/cmocka.git suite/cstest/cmocka - chmod +x suite/cstest/build_cstest.sh + - if [[ ${TRAVIS_OS_NAME} = linux ]]; then export PATH="/usr/lib/llvm-9/bin:${PATH}"; fi script: - ./make.sh - make check @@ -18,6 +19,7 @@ script: - if [[ "$NOPYTEST" != "true" ]]; then cd suite/cstest && ./build_cstest.sh; fi - if [[ "$NOPYTEST" != "true" ]]; then python cstest_report.py -D -t build/cstest -d ../MC; fi - if [[ "$NOPYTEST" != "true" ]]; then python cstest_report.py -D -t build/cstest -f issues.cs; fi + - if [ -n "$QA_FUZZIT" ]; then suite/fuzz/fuzzit.sh; fi compiler: - clang - gcc @@ -43,14 +45,22 @@ matrix: packages: - libcmocka-dev - name: fuzza - env: ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address" LDFLAGS="-fsanitize=address" NOPYTEST=true + env: ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=address" NOPYTEST=true QA_FUZZIT=asan compiler: clang os: linux - name: fuzzm - env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory" LDFLAGS="-fsanitize=memory" NOPYTEST=true + env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=memory" NOPYTEST=true QA_FUZZIT=msan compiler: clang os: linux - name: fuzzu - env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fno-sanitize-recover=undefined,integer" LDFLAGS="-fsanitize=undefined" NOPYTEST=true + env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fno-sanitize-recover=undefined,integer -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=undefined" NOPYTEST=true QA_FUZZIT=ubsan compiler: clang os: linux + +addons: + apt: + sources: + - llvm-toolchain-trusty + - ubuntu-toolchain-r-test + packages: + - clang-9 diff --git a/README.md b/README.md index b7fa58cd3..812578977 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Capstone Engine [![Build status](https://ci.appveyor.com/api/projects/status/a4wvbn89wu3pinas/branch/next?svg=true)](https://ci.appveyor.com/project/aquynh/capstone/branch/next) [![pypi package](https://badge.fury.io/py/capstone.svg)](https://pypi.python.org/pypi/capstone) [![pypi downloads](https://pepy.tech/badge/capstone)](https://pepy.tech/project/capstone) +[![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=ANOh0D48gSLBxNZcDQMI&branch=master)](https://app.fuzzit.dev/admin/ANOh0D48gSLBxNZcDQMI/dashboard)
Capstone is a disassembly framework with the target of becoming the ultimate disasm engine for binary analysis and reversing in the security community. @@ -61,6 +62,12 @@ Hack See HACK.TXT file for the structure of the source code. +Fuzz +---- + +See suite/fuzz/README.md for more information. + + License ------- diff --git a/suite/fuzz/Makefile b/suite/fuzz/Makefile index dc45644d2..4cd958690 100644 --- a/suite/fuzz/Makefile +++ b/suite/fuzz/Makefile @@ -27,6 +27,7 @@ LDFLAGS += -L$(LIBDIR) CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) +FUZZLDFLAGS = LIBNAME = capstone @@ -40,16 +41,20 @@ ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) SOURCES = fuzz_disasm.c drivermc.c fuzz_harness.c driverbin.c platform.c OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) -BINARY = $(addprefix $(TESTDIR)/,fuzz_disasm$(BIN_EXT)) -BINARYBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm$(BIN_EXT)) +# reproducer using MC file as input +REPRODUCERMC = $(addprefix $(TESTDIR)/,fuzz_disasm$(BIN_EXT)) +# reproducer using raw binary file as input (as produced by fuzzer) +REPRODUCERBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm$(BIN_EXT)) +# fuzzer +FUZZERBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm2$(BIN_EXT)) PLATFORMDECODE = $(addprefix $(TESTDIR)/,fuzz_decode_platform$(BIN_EXT)) -all: $(BINARY) $(BINARYBIN) $(PLATFORMDECODE) +all: $(REPRODUCERMC) $(REPRODUCERBIN) $(FUZZERBIN) $(PLATFORMDECODE) clean: - rm -rf fuzz_harness $(OBJS) $(PLATFORMDECODE) $(BINARY) $(BINARYBIN) $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).* + rm -rf fuzz_harness $(OBJS) $(PLATFORMDECODE) $(REPRODUCERMC) $(REPRODUCERBIN) $(FUZZERBIN) $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).* -$(BINARY): fuzz_disasm.o drivermc.o platform.o +$(REPRODUCERMC): fuzz_disasm.o drivermc.o platform.o @mkdir -p $(@D) ifeq ($(V),0) $(call log,LINK,$(notdir $@)) @@ -58,7 +63,7 @@ else $(link-static) endif -$(BINARYBIN): fuzz_disasm.o driverbin.o platform.o +$(REPRODUCERBIN): fuzz_disasm.o driverbin.o platform.o @mkdir -p $(@D) ifeq ($(V),0) $(call log,LINK,$(notdir $@)) @@ -67,6 +72,17 @@ else $(link-static) endif +$(FUZZERBIN): FUZZLDFLAGS="-fsanitize=fuzzer" + +$(FUZZERBIN): fuzz_disasm.o platform.o + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,LINK,$(notdir $@)) + @$(link-static) || touch $(FUZZERBIN) +else + $(link-static) || touch $(FUZZERBIN) +endif + $(PLATFORMDECODE): fuzz_decode_platform.o platform.o @mkdir -p $(@D) ifeq ($(V),0) @@ -88,7 +104,7 @@ endif define link-static - $(CC) $(LDFLAGS) $^ $(ARCHIVE) -o $@ + $(CC) $(LDFLAGS) $(FUZZLDFLAGS) $^ $(ARCHIVE) -o $@ endef fuzz_harness: fuzz_harness.o diff --git a/suite/fuzz/README.md b/suite/fuzz/README.md new file mode 100644 index 000000000..27c1c0c36 --- /dev/null +++ b/suite/fuzz/README.md @@ -0,0 +1,34 @@ +Fuzzing +=============== + + +Build the fuzz target +------- + +To build the fuzz target, you can simply run `make` with appropriate flags set : +``` +ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=address" make +``` +You can replace `address` with another sanitizer : `memory` or `undefined` +The fuzz target is then `suite/fuzz/fuzz_bindisasm2` + +You can find this in travis configuration `.travis.yml` + +Another way is to use oss-fuzz, see https://github.com/google/oss-fuzz/blob/master/projects/capstone/build.sh + +Fuzz drivers +------ + +There are custom drivers : +- driverbin.c : prints cstool command before running one input +- drivermc.c : converts MC test data to raw binary data before running as many inputs as there are lines in a file +- onefile.c : simple one file driver + +For libfuzzer, the preferred main function is now to use linker option `-fsanitize=fuzzer` + +Fuzzit integration +------ + +Travis will build the fuzz target with the different sanitizers. +Then, Travis will launch sanity fuzzit jobs as part of continuous integration (for each of the sanitizers) +The fuzzit target ids are stored in a configuration file fuzzitid.txt and used by fuzzit.sh diff --git a/suite/fuzz/fuzzit.sh b/suite/fuzz/fuzzit.sh new file mode 100755 index 000000000..b962b773e --- /dev/null +++ b/suite/fuzz/fuzzit.sh @@ -0,0 +1,27 @@ +FUZZIT_API_KEY=f10b19a56d96b29dfdfe459d41b3d82e475e49c737095c74c99d65a032d5c2ab84d44dad510886bc824f101a860b1754 + +[ -s ./suite/fuzz/fuzz_bindisasm2 ] || exit 0 + +if [ ${TRAVIS_EVENT_TYPE} -eq 'cron' ]; then + FUZZING_TYPE=fuzzing +else + FUZZING_TYPE=sanity +fi +if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then + FUZZIT_BRANCH="${TRAVIS_BRANCH}" +else + FUZZIT_BRANCH="PR-${TRAVIS_PULL_REQUEST}" +fi + +FUZZIT_ARGS="--type ${FUZZING_TYPE} --branch ${FUZZIT_BRANCH} --revision ${TRAVIS_COMMIT}" +if [ -n "$UBSAN_OPTIONS" ]; then + FUZZIT_ARGS+=" --ubsan_options ${UBSAN_OPTIONS}" +fi +wget -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v1.2.5/fuzzit_1.2.5_Linux_x86_64 +chmod +x fuzzit +./fuzzit auth ${FUZZIT_API_KEY} +set -x +grep "$QA_FUZZIT" suite/fuzz/fuzzitid.txt | cut -d" " -f2 | while read i; do + ./fuzzit c job ${FUZZIT_ARGS} ${i} ./suite/fuzz/fuzz_bindisasm2 +done +set +x diff --git a/suite/fuzz/fuzzitid.txt b/suite/fuzz/fuzzitid.txt new file mode 100644 index 000000000..57bbe73ca --- /dev/null +++ b/suite/fuzz/fuzzitid.txt @@ -0,0 +1,3 @@ +asan A1NqPndmOVrguCNj95LZ +msan JchjH3j58fOnB8ZXGyWl +ubsan JqHqVabfDEqitOusrPFx \ No newline at end of file