diff options
author | Jack Lloyd <[email protected]> | 2017-07-31 15:13:15 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-08-25 17:36:51 -0400 |
commit | 3baa546d70bcd078b23be07069d755a5f130fb0f (patch) | |
tree | d626d73fdf845987e2d1783e8493593501378a07 | |
parent | 41e1e7cbc1e4e864ad5d15dd0c09227b04940a91 (diff) |
Create new fuzzer build mode
-rw-r--r-- | .travis.yml | 12 | ||||
-rwxr-xr-x | configure.py | 109 | ||||
-rw-r--r-- | src/build-data/buildh.in | 1 | ||||
-rw-r--r-- | src/build-data/makefile/gmake.in | 2 | ||||
-rw-r--r-- | src/build-data/makefile/gmake_fuzzers.in | 18 | ||||
-rw-r--r-- | src/extra_tests/fuzzers/.gitignore | 10 | ||||
-rw-r--r-- | src/extra_tests/fuzzers/GNUmakefile | 88 | ||||
-rw-r--r-- | src/extra_tests/fuzzers/readme.txt | 49 | ||||
-rw-r--r-- | src/fuzzer/asn1.cpp (renamed from src/extra_tests/fuzzers/jigs/ber_decode.cpp) | 13 | ||||
-rw-r--r-- | src/fuzzer/bn_sqr.cpp (renamed from src/extra_tests/fuzzers/jigs/bn_sqr.cpp) | 2 | ||||
-rw-r--r-- | src/fuzzer/cert.cpp (renamed from src/extra_tests/fuzzers/jigs/cert.cpp) | 8 | ||||
-rw-r--r-- | src/fuzzer/crl.cpp (renamed from src/extra_tests/fuzzers/jigs/crl.cpp) | 11 | ||||
-rw-r--r-- | src/fuzzer/divide.cpp (renamed from src/extra_tests/fuzzers/jigs/divide.cpp) | 10 | ||||
-rw-r--r-- | src/fuzzer/ecc_bp256.cpp (renamed from src/extra_tests/fuzzers/jigs/ecc_bp256.cpp) | 4 | ||||
-rw-r--r-- | src/fuzzer/ecc_helper.h (renamed from src/extra_tests/fuzzers/jigs/ecc_helper.h) | 29 | ||||
-rw-r--r-- | src/fuzzer/ecc_p256.cpp (renamed from src/extra_tests/fuzzers/jigs/ecc_p256.cpp) | 4 | ||||
-rw-r--r-- | src/fuzzer/ecc_p384.cpp (renamed from src/extra_tests/fuzzers/jigs/ecc_p384.cpp) | 4 | ||||
-rw-r--r-- | src/fuzzer/ecc_p521.cpp (renamed from src/extra_tests/fuzzers/jigs/ecc_p521.cpp) | 4 | ||||
-rw-r--r-- | src/fuzzer/fuzzers.h (renamed from src/extra_tests/fuzzers/jigs/driver.h) | 104 | ||||
-rw-r--r-- | src/fuzzer/invert.cpp (renamed from src/extra_tests/fuzzers/jigs/invert.cpp) | 21 | ||||
-rw-r--r-- | src/fuzzer/ocsp.cpp (renamed from src/extra_tests/fuzzers/jigs/ocsp.cpp) | 4 | ||||
-rw-r--r-- | src/fuzzer/os2ecp.cpp (renamed from src/extra_tests/fuzzers/jigs/os2ecp.cpp) | 24 | ||||
-rw-r--r-- | src/fuzzer/pkcs1.cpp (renamed from src/extra_tests/fuzzers/jigs/pkcs1.cpp) | 25 | ||||
-rw-r--r-- | src/fuzzer/pkcs8.cpp (renamed from src/extra_tests/fuzzers/jigs/pkcs8.cpp) | 7 | ||||
-rw-r--r-- | src/fuzzer/pow_mod.cpp (renamed from src/extra_tests/fuzzers/jigs/pow_mod.cpp) | 25 | ||||
-rw-r--r-- | src/fuzzer/redc_helper.h | 33 | ||||
-rw-r--r-- | src/fuzzer/redc_p192.cpp (renamed from src/extra_tests/fuzzers/jigs/redc_p192.cpp) | 8 | ||||
-rw-r--r-- | src/fuzzer/redc_p224.cpp (renamed from src/extra_tests/fuzzers/jigs/redc_p224.cpp) | 8 | ||||
-rw-r--r-- | src/fuzzer/redc_p256.cpp (renamed from src/extra_tests/fuzzers/jigs/redc_p256.cpp) | 8 | ||||
-rw-r--r-- | src/fuzzer/redc_p384.cpp (renamed from src/extra_tests/fuzzers/jigs/redc_p384.cpp) | 8 | ||||
-rw-r--r-- | src/fuzzer/redc_p521.cpp (renamed from src/extra_tests/fuzzers/jigs/redc_p521.cpp) | 8 | ||||
-rw-r--r-- | src/fuzzer/ressol.cpp (renamed from src/extra_tests/fuzzers/jigs/ressol.cpp) | 14 | ||||
-rw-r--r-- | src/fuzzer/tls_client.cpp (renamed from src/extra_tests/fuzzers/jigs/tls_client.cpp) | 24 | ||||
-rw-r--r-- | src/fuzzer/tls_client_hello.cpp (renamed from src/extra_tests/fuzzers/jigs/tls_client_hello.cpp) | 3 | ||||
-rw-r--r-- | src/fuzzer/tls_server.cpp (renamed from src/extra_tests/fuzzers/jigs/tls_server.cpp) | 32 | ||||
-rwxr-xr-x | src/scripts/ci/travis/build.sh | 13 | ||||
-rwxr-xr-x | src/scripts/create_corpus_zip.py | 48 | ||||
-rwxr-xr-x | src/scripts/test_fuzzers.py | 78 |
38 files changed, 475 insertions, 398 deletions
diff --git a/.travis.yml b/.travis.yml index d7092f01a..8431729b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ env: - BUILD_MODE="static" - BUILD_MODE="bsi" - BUILD_MODE="nist" + - BUILD_MODE="fuzzers" - BUILD_MODE="sanitizer" - BUILD_MODE="coverage" - BUILD_MODE="cross-arm32" @@ -52,10 +53,11 @@ matrix: - os: osx compiler: gcc - # Run docs, lint, bsi, nist, coverage, valgrind, sonarqube, sanitizer, - # minimized and non-ARM cross builds on Linux/gcc only. The - # sanitizer builds under Clang run the tests very slowly and cause - # CI timeouts. + # Run docs, lint, bsi, nist, fuzzers, coverage, valgrind, sonarqube, sanitizer, + # minimized and non-ARM cross builds on Linux/gcc only. + + # The sanitizer builds under Clang run the tests very slowly and + # cause CI timeouts. - compiler: clang env: BUILD_MODE="bsi" @@ -72,6 +74,8 @@ matrix: - compiler: clang env: BUILD_MODE="sanitizer" - compiler: clang + env: BUILD_MODE="fuzzers" + - compiler: clang env: BUILD_MODE="valgrind" - compiler: clang env: BUILD_MODE="mini-shared" diff --git a/configure.py b/configure.py index 58a4f19d2..f9bf90fc9 100755 --- a/configure.py +++ b/configure.py @@ -183,6 +183,13 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes self.cli_headers = list(find_headers_in(source_paths.src_dir, 'cli')) self.test_sources = list(find_sources_in(source_paths.src_dir, 'tests')) + if options.build_fuzzers: + self.fuzzer_sources = list(find_sources_in(source_paths.src_dir, 'fuzzer')) + self.fuzzer_output_dir = os.path.join(self.build_dir, 'fuzzer') + else: + self.fuzzer_sources = None + self.fuzzer_output_dir = None + def build_dirs(self): out = [ self.libobj_dir, @@ -195,6 +202,8 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes ] if self.doc_output_dir_doxygen: out += [self.doc_output_dir_doxygen] + if self.fuzzer_output_dir: + out += [self.fuzzer_output_dir] return out def src_info(self, typ): @@ -204,6 +213,10 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes return (self.cli_sources, self.cliobj_dir) elif typ == 'test': return (self.test_sources, self.testobj_dir) + elif typ == 'fuzzer': + return (self.fuzzer_sources, self.fuzzer_output_dir) + else: + raise InternalError("Unknown src info type '%s'" % (typ)) PKG_CONFIG_FILENAME = 'botan-%d.pc' % (Version.major) @@ -409,7 +422,14 @@ def process_command_line(args): # pylint: disable=too-many-locals help='Generate CMakeLists.txt which can be used to create many IDEs project files') build_group.add_option('--unsafe-fuzzer-mode', action='store_true', default=False, - help='disable essential checks for testing') + help='Disable essential checks for testing') + + build_group.add_option('--build-fuzzers=', dest='build_fuzzers', + metavar='TYPE', default=None, + help='Build fuzzers (afl, libfuzzer, test)') + + build_group.add_option('--with-fuzzer-lib=', metavar='LIB', default=None, dest='fuzzer_lib', + help='additionally link in LIB') mods_group = optparse.OptionGroup(parser, 'Module selection') @@ -1711,13 +1731,14 @@ class MakefileListsGenerator(object): for src in sources: (directory, filename) = os.path.split(os.path.normpath(src)) + obj_suffix = '.' + self._osinfo.obj_suffix + parts = directory.split(os.sep) + if 'fuzzer' in parts: + obj_suffix = '' + if 'src' in parts: parts = parts[parts.index('src')+2:] - elif 'tests' in parts: - parts = parts[parts.index('tests')+2:] - elif 'cli' in parts: - parts = parts[parts.index('cli'):] elif filename.find('botan_all') != -1: parts = [] else: @@ -1744,8 +1765,7 @@ class MakefileListsGenerator(object): else: name = filename - for src_suffix in ['.cpp', '.S']: - name = name.replace(src_suffix, '.' + self._osinfo.obj_suffix) + name = name.replace('.cpp', obj_suffix) yield os.path.join(obj_dir, name) @@ -1760,21 +1780,29 @@ class MakefileListsGenerator(object): if self._options.with_external_includedir: includes += ' ' + self._cc.add_include_dir_option + self._options.with_external_includedir - for (obj_file, src) in zip(self._objectfile_list(sources, obj_dir), sources): - isa_specific_flags_str = "".join([" %s" % flagset for flagset in sorted(self._isa_specific_flags(src))]) - yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s %s %s %s$@\n' % ( - obj_file, - src, - isa_specific_flags_str, - flags, - includes, - self._cc.compile_flags, - src, - self._cc.output_to_option) + is_fuzzer = obj_dir.find('fuzzer') != -1 + + if is_fuzzer: + for (obj_file, src) in zip(self._objectfile_list(sources, obj_dir), sources): + + yield '%s: %s\n\t$(CXX) %s $(%s_FLAGS) %s -L. -lbotan-2 $(FUZZER_LINKS_TO) %s$@\n' % ( + obj_file, src, includes, flags, src, self._cc.output_to_option) + else: + for (obj_file, src) in zip(self._objectfile_list(sources, obj_dir), sources): + isa_specific_flags_str = "".join([" %s" % flagset for flagset in sorted(self._isa_specific_flags(src))]) + + yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s %s %s %s$@\n' % ( + obj_file, src, isa_specific_flags_str, flags, + includes, self._cc.compile_flags, src, self._cc.output_to_option) def generate(self): out = {} - for t in ['lib', 'cli', 'test']: + + targets = ['lib', 'cli', 'test'] + if self._options.build_fuzzers: + targets += ['fuzzer'] + + for t in targets: obj_key = '%s_objs' % (t) src_list, src_dir = self._build_paths.src_info(t) src_list.sort() @@ -1817,7 +1845,7 @@ class HouseEccCurve(object): return "\\\n" + ' \\\n'.join(lines) -def create_template_vars(source_paths, build_config, options, modules, cc, arch, osinfo): +def create_template_vars(source_paths, build_config, options, modules, cc, arch, osinfo): #pylint: disable=too-many-locals,too-many-branches """ Create the template variables needed to process the makefile, build.h, etc """ @@ -1846,6 +1874,7 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, exceptions = match.group(1).split(',') if osinfo.basename not in exceptions: libs |= set(module_link_to) + return sorted(libs) def choose_mp_bits(): @@ -1909,6 +1938,7 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, 'libobj_dir': build_config.libobj_dir, 'cliobj_dir': build_config.cliobj_dir, 'testobj_dir': build_config.testobj_dir, + 'fuzzobj_dir': build_config.fuzzer_output_dir if build_config.fuzzer_output_dir else '', 'doc_output_dir': build_config.doc_output_dir, @@ -1938,6 +1968,7 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, 'lib_link_cmd': cc.so_link_command_for(osinfo.basename, options) + external_link_cmd(), 'cli_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(), 'test_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(), + 'fuzzer_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(), 'link_to': ' '.join( [cc.add_lib_option + lib for lib in link_to('libs')] + @@ -1956,7 +1987,9 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, 'include_files': makefile_list(build_config.public_headers), - 'unsafe_fuzzer_mode_define': '' if not options.unsafe_fuzzer_mode else '#define BOTAN_UNSAFE_FUZZER_MODE', + 'unsafe_fuzzer_mode_define': '#define BOTAN_UNSAFE_FUZZER_MODE' if options.unsafe_fuzzer_mode else '', + 'fuzzer_type': '#define BOTAN_FUZZER_IS_%s' % (options.build_fuzzers.upper()) if options.build_fuzzers else '', + 'fuzzer_libs': '' if options.fuzzer_lib is None else '%s%s' % (cc.add_lib_option, options.fuzzer_lib), 'ar_command': cc.ar_command or osinfo.ar_command, 'ranlib_command': osinfo.ranlib_command(), @@ -2026,17 +2059,22 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, variables["header_in"] = process_template(os.path.join(source_paths.makefile_dir, 'header.in'), variables) if variables["makefile_style"] == "gmake": - variables["gmake_commands_in"] = process_template( - os.path.join(source_paths.makefile_dir, 'gmake_commands.in'), - variables) - variables["gmake_dso_in"] = process_template( - os.path.join(source_paths.makefile_dir, 'gmake_dso.in'), - variables - ) if options.build_shared_lib else '' - variables["gmake_coverage_in"] = process_template( - os.path.join(source_paths.makefile_dir, 'gmake_coverage.in'), - variables - ) if options.with_coverage_info else '' + templates = [ + ('gmake_commands.in', True), + ('gmake_dso.in', options.build_shared_lib), + ('gmake_coverage.in', options.with_coverage_info), + ('gmake_fuzzers.in', options.build_fuzzers) + ] + + for (template, build_it) in templates: + template_file = os.path.join(source_paths.makefile_dir, template) + + var_name = template.replace('.', '_') + + if build_it: + variables[var_name] = process_template(template_file, variables) + else: + variables[var_name] = '' return variables @@ -3006,6 +3044,13 @@ def main(argv): source_paths = SourcePaths(os.path.dirname(argv[0])) + if options.build_fuzzers != None: + if options.build_fuzzers not in ['libfuzzer', 'afl', 'test']: + raise UserError('Bad value to --build-fuzzers') + + if options.build_fuzzers == 'libfuzzer' and options.fuzzer_lib is None: + options.fuzzer_lib = 'Fuzzer' + info_modules = load_info_files(source_paths.lib_dir, 'Modules', "info.txt", ModuleInfo) info_arch = load_build_data_info_files(source_paths, 'CPU info', 'arch', ArchInfo) info_os = load_build_data_info_files(source_paths, 'OS info', 'os', OsInfo) diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 2376b056e..6e60718ee 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -25,6 +25,7 @@ /* How many bits per limb in a BigInt */ #define BOTAN_MP_WORD_BITS %{mp_bits} %{unsafe_fuzzer_mode_define} +%{fuzzer_type} #define BOTAN_INSTALL_PREFIX R"(%{prefix})" #define BOTAN_INSTALL_HEADER_DIR "%{includedir}/botan-%{version_major}" diff --git a/src/build-data/makefile/gmake.in b/src/build-data/makefile/gmake.in index 22e4ef778..c77c1908c 100644 --- a/src/build-data/makefile/gmake.in +++ b/src/build-data/makefile/gmake.in @@ -53,6 +53,8 @@ $(STATIC_LIB): $(LIBOBJS) %{gmake_coverage_in} +%{gmake_fuzzers_in} + SPHINX_CONFIG = %{sphinx_config_dir} SPHINX_OPTS = -b html diff --git a/src/build-data/makefile/gmake_fuzzers.in b/src/build-data/makefile/gmake_fuzzers.in new file mode 100644 index 000000000..82fa8b256 --- /dev/null +++ b/src/build-data/makefile/gmake_fuzzers.in @@ -0,0 +1,18 @@ + +# Fuzzer build commands + +FUZZER_LINK_CMD = %{fuzzer_link_cmd} +FUZZER_LINKS_TO = $(LIB_LINKS_TO) %{fuzzer_libs} +FUZZER_FLAGS = $(CXXFLAGS) $(WARN_FLAGS) + +%{fuzzer_build_cmds} + +FUZZERS=%{fuzzer_objs} + +fuzzers: libs $(FUZZERS) + +fuzzer_corpus: + git clone --depth=1 https://github.com/randombit/crypto-corpus.git fuzzer_corpus + +fuzzer_corpus_zip: fuzzer_corpus + ./src/scripts/create_corpus_zip.py fuzzer_corpus %{fuzzobj_dir} diff --git a/src/extra_tests/fuzzers/.gitignore b/src/extra_tests/fuzzers/.gitignore deleted file mode 100644 index f7ce206a2..000000000 --- a/src/extra_tests/fuzzers/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*.log - -/libFuzzer -libFuzzer.a - -/output -/botan -/bin -callgrind.out.* -/corpus/ diff --git a/src/extra_tests/fuzzers/GNUmakefile b/src/extra_tests/fuzzers/GNUmakefile deleted file mode 100644 index 32b353d17..000000000 --- a/src/extra_tests/fuzzers/GNUmakefile +++ /dev/null @@ -1,88 +0,0 @@ - -FUZZERS=$(patsubst jigs/%.cpp,%,$(wildcard jigs/*.cpp)) - -AFL_SAN_FLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -CLANG_SAN_FLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -#CLANG_SAN_FLAGS=-fsanitize=address - -CLANG_COV_FLAGS=-fsanitize-coverage=edge,indirect-calls,8bit-counters -SHARED_FLAGS=-O3 -g -std=c++11 -pthread -CFG_FLAGS=--with-debug-info --unsafe-fuzzer-mode - -LIBFUZZER_FLAGS=-Illvm-build/build/include $(SHARED_FLAGS) $(CLANG_COV_FLAGS) $(CLANG_SAN_FLAGS) -AFL_FLAGS=-Iafl-build/build/include $(SHARED_FLAGS) -DINCLUDE_AFL_MAIN - -LIBFUZZER_LIBS=llvm-build/libbotan-2.a libFuzzer.a -AFL_LIBS=afl-build/libbotan-2.a - -#AFL_CXX=AFL_USE_ASAN=1 afl-g++ -m32 -AFL_CXX=afl-g++ -AFL_CXX_TYPE=gcc -CLANG_CXX=clang++ - -LIBFUZZER_PROGS=$(patsubst %,bin/llvm_fuzz_%,$(FUZZERS)) -AFL_PROGS=$(patsubst %,bin/afl_fuzz_%,$(FUZZERS)) - -all: - @echo "make afl for AFL, llvm for libFuzzer" - -afl: dirs afl-build $(AFL_PROGS) - -llvm: dirs llvm-build $(LIBFUZZER_PROGS) - -bin/llvm_fuzz_%: jigs/%.cpp $(LIBFUZZER_LIBS) - $(CLANG_CXX) $(LIBFUZZER_FLAGS) $< $(LIBFUZZER_LIBS) -o $@ - -bin/afl_fuzz_%: jigs/%.cpp $(AFL_LIBS) - $(AFL_CXX) $(AFL_FLAGS) $< $(AFL_LIBS) -o $@ - - -dirs: - mkdir -p bin - mkdir -p output - mkdir -p corpus - -afl-build: - ../../../configure.py $(CFG_FLAGS) --with-build-dir=afl-build --cc=$(AFL_CXX_TYPE) --cc-bin=$(AFL_CXX) - make -j2 -f afl-build/Makefile afl-build/libbotan-2.a - -llvm-build: - ../../../configure.py $(CFG_FLAGS) --with-build-dir=llvm-build --cc=clang --cc-bin=$(CLANG_CXX) --cc-abi-flags="$(CLANG_COV_FLAGS) $(CLANG_SAN_FLAGS)" - make -j2 -f llvm-build/Makefile llvm-build/libbotan-2.a - -# libFuzzer default is max_len 64 this sets 140 but allows override via args= -run_llvm_%: bin/llvm_fuzz_% - $(eval FUZZER = $(subst bin/llvm_fuzz_,,$<)) - mkdir -p output/$(FUZZER)/llvm/queue - mkdir -p output/$(FUZZER)/llvm/outputs - $< -max_len=140 -artifact_prefix=output/$(FUZZER)/llvm/outputs/ output/$(FUZZER)/llvm/queue corpus/$(FUZZER) $(args) - -run_afl_%: bin/afl_fuzz_% - $(eval FUZZER = $(subst bin/afl_fuzz_,,$<)) - mkdir -p output/$(FUZZER)/afl - afl-fuzz $(args) -o output/$(FUZZER)/afl -i corpus/$(FUZZER) $< - -cmin_%: bin/afl_fuzz_% - $(eval FUZZER = $(subst bin/afl_fuzz_,,$<)) - rm -rf cmin-dir - mv corpus/$(FUZZER) cmin-dir - -cp -n output/$(FUZZER)/afl/queue/* cmin-dir - -cp -n output/$(FUZZER)/llvm/queue/* cmin-dir - afl-cmin -i cmin-dir -o corpus/$(FUZZER) $< - rm -rf cmin-dir - -clean: - rm -f $(LIBFUZZER_PROGS) $(AFL_PROGS) - -clean_builds: clean - rm -rf afl-build llvm-build - -libFuzzer: - svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libFuzzer - -libFuzzer.a: libFuzzer - cd libFuzzer && clang -c -g -O2 -std=c++11 *.cpp - ar cr libFuzzer.a libFuzzer/*.o - -update: - svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libFuzzer diff --git a/src/extra_tests/fuzzers/readme.txt b/src/extra_tests/fuzzers/readme.txt deleted file mode 100644 index 1bee1a785..000000000 --- a/src/extra_tests/fuzzers/readme.txt +++ /dev/null @@ -1,49 +0,0 @@ - -The code in this directory is for testing various message decoders and -math functions using the fuzzers AFL (http://lcamtuf.coredump.cx/afl/) -and libFuzzer (http://llvm.org/docs/LibFuzzer.html). - -To build for AFL, run - - make afl - -For libFuzzer - - make llvm - -To add a new fuzzer, create a new file in jigs/, include "driver.h", -and implement the function with the signature - -void fuzz(const uint8_t buf[], size_t len); - -This function should abort/crash if something is incorrect. - -Run it with - -make run_{llvm,afl}_{what} - -like in - -make run_llvm_crl -make run_afl_tls_client - -You can pass args to the fuzzer process using args= - -make args=-max_len=4000 run_llvm_tls_client - -The fuzzer entry point assumes no more than 4K of input. The base -libFuzzer default max len is 64 bytes, the makefile sets it to 140 as -default. - -Use - -make cmin_redc_p384 - -to run afl-cmin to minimize and merge the LLVM and AFL outputs back to -the corpus directory. - -TODO: - -- KLEE (https://klee.github.io) -- DFSan (http://clang.llvm.org/docs/DataFlowSanitizer.html) -- More jigs diff --git a/src/extra_tests/fuzzers/jigs/ber_decode.cpp b/src/fuzzer/asn1.cpp index 6ec9cadba..b0ea553e5 100644 --- a/src/extra_tests/fuzzers/jigs/ber_decode.cpp +++ b/src/fuzzer/asn1.cpp @@ -1,25 +1,22 @@ /* -* (C) 2016 Jack Lloyd +* (C) 2016,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/ber_dec.h> void fuzz(const uint8_t in[], size_t len) { - if(len > 4096) - return; - try { - DataSource_Memory input(in, len); - BER_Decoder dec(input); + Botan::DataSource_Memory input(in, len); + Botan::BER_Decoder dec(input); while(dec.more_items()) { - BER_Object obj; + Botan::BER_Object obj; dec.get_next(obj); } } diff --git a/src/extra_tests/fuzzers/jigs/bn_sqr.cpp b/src/fuzzer/bn_sqr.cpp index aa76067f7..f507c4a79 100644 --- a/src/extra_tests/fuzzers/jigs/bn_sqr.cpp +++ b/src/fuzzer/bn_sqr.cpp @@ -4,7 +4,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/bigint.h> #include <botan/numthry.h> diff --git a/src/extra_tests/fuzzers/jigs/cert.cpp b/src/fuzzer/cert.cpp index 5620a4700..3b40020df 100644 --- a/src/extra_tests/fuzzers/jigs/cert.cpp +++ b/src/fuzzer/cert.cpp @@ -3,19 +3,19 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/x509cert.h> void fuzz(const uint8_t in[], size_t len) { - if(len > 8192) + if(len > max_fuzzer_input_size) return; try { - DataSource_Memory input(in, len); - X509_Certificate cert(input); + Botan::DataSource_Memory input(in, len); + Botan::X509_Certificate cert(input); } catch(Botan::Exception& e) { } } diff --git a/src/extra_tests/fuzzers/jigs/crl.cpp b/src/fuzzer/crl.cpp index b3157e5fe..63699b9b3 100644 --- a/src/extra_tests/fuzzers/jigs/crl.cpp +++ b/src/fuzzer/crl.cpp @@ -3,19 +3,16 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/x509_crl.h> void fuzz(const uint8_t in[], size_t len) { - if(len > 4096) - return; - try { - DataSource_Memory input(in, len); - X509_CRL crl(input); + Botan::DataSource_Memory input(in, len); + Botan::X509_CRL crl(input); } - catch(Botan::Exception& e) { } + catch(Botan::Exception& e) {} } diff --git a/src/extra_tests/fuzzers/jigs/divide.cpp b/src/fuzzer/divide.cpp index 4ff50a680..01ec14e28 100644 --- a/src/extra_tests/fuzzers/jigs/divide.cpp +++ b/src/fuzzer/divide.cpp @@ -3,7 +3,7 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/divide.h> void fuzz(const uint8_t in[], size_t len) @@ -11,18 +11,18 @@ void fuzz(const uint8_t in[], size_t len) if(len % 2 == 1 || len > 2*4096/8) return; - const BigInt x = BigInt::decode(in, len / 2); - const BigInt y = BigInt::decode(in + len / 2, len / 2); + const Botan::BigInt x = Botan::BigInt::decode(in, len / 2); + const Botan::BigInt y = Botan::BigInt::decode(in + len / 2, len / 2); if(y == 0) return; - BigInt q, r; + Botan::BigInt q, r; Botan::divide(x, y, q, r); FUZZER_ASSERT_TRUE(r < y); - BigInt z = q*y + r; + Botan::BigInt z = q*y + r; FUZZER_ASSERT_EQUAL(z, x); } diff --git a/src/extra_tests/fuzzers/jigs/ecc_bp256.cpp b/src/fuzzer/ecc_bp256.cpp index 07833c639..4c1186f06 100644 --- a/src/extra_tests/fuzzers/jigs/ecc_bp256.cpp +++ b/src/fuzzer/ecc_bp256.cpp @@ -3,7 +3,7 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include "ecc_helper.h" void fuzz(const uint8_t in[], size_t len) @@ -11,6 +11,6 @@ void fuzz(const uint8_t in[], size_t len) if(len > 2*256/8) return; - static EC_Group bp256("brainpool256r1"); + static Botan::EC_Group bp256("brainpool256r1"); return check_ecc_math(bp256, in, len); } diff --git a/src/extra_tests/fuzzers/jigs/ecc_helper.h b/src/fuzzer/ecc_helper.h index fb502452a..c9b3a6604 100644 --- a/src/extra_tests/fuzzers/jigs/ecc_helper.h +++ b/src/fuzzer/ecc_helper.h @@ -3,37 +3,24 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ + #ifndef ECC_HELPERS_H__ #define ECC_HELPERS_H__ -#include "driver.h" +#include "fuzzers.h" #include <botan/curve_gfp.h> #include <botan/ec_group.h> #include <botan/reducer.h> -void check_redc(std::function<void (BigInt&, secure_vector<word>&)> redc_fn, - const Modular_Reducer& redc, - const BigInt& prime, - const BigInt& x) - { - const Botan::BigInt v1 = x % prime; - const Botan::BigInt v2 = redc.reduce(x); - - Botan::secure_vector<Botan::word> ws; - Botan::BigInt v3 = x; - redc_fn(v3, ws); +namespace { - FUZZER_ASSERT_EQUAL(v1, v2); - FUZZER_ASSERT_EQUAL(v2, v3); - } - -inline std::ostream& operator<<(std::ostream& o, const PointGFp& point) +inline std::ostream& operator<<(std::ostream& o, const Botan::PointGFp& point) { o << point.get_affine_x() << "," << point.get_affine_y(); return o; } -void check_ecc_math(const EC_Group& group, +void check_ecc_math(const Botan::EC_Group& group, const uint8_t in[], size_t len) { // These depend only on the group, which is also static @@ -41,8 +28,8 @@ void check_ecc_math(const EC_Group& group, static Botan::Blinded_Point_Multiply blind(base_point, group.get_order(), 4); const size_t hlen = len / 2; - const BigInt a = BigInt::decode(in, hlen); - const BigInt b = BigInt::decode(in + hlen, len - hlen); + const Botan::BigInt a = Botan::BigInt::decode(in, hlen); + const Botan::BigInt b = Botan::BigInt::decode(in + hlen, len - hlen); const Botan::BigInt c = a + b; @@ -66,4 +53,6 @@ void check_ecc_math(const EC_Group& group, FUZZER_ASSERT_EQUAL(S1, A1); } +} + #endif diff --git a/src/extra_tests/fuzzers/jigs/ecc_p256.cpp b/src/fuzzer/ecc_p256.cpp index f13104fda..c00be71b6 100644 --- a/src/extra_tests/fuzzers/jigs/ecc_p256.cpp +++ b/src/fuzzer/ecc_p256.cpp @@ -3,13 +3,13 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include "ecc_helper.h" void fuzz(const uint8_t in[], size_t len) { if(len > 2*256/8) return; - static EC_Group p256("secp256r1"); + static Botan::EC_Group p256("secp256r1"); return check_ecc_math(p256, in, len); } diff --git a/src/extra_tests/fuzzers/jigs/ecc_p384.cpp b/src/fuzzer/ecc_p384.cpp index 47826e1d6..1b58da958 100644 --- a/src/extra_tests/fuzzers/jigs/ecc_p384.cpp +++ b/src/fuzzer/ecc_p384.cpp @@ -3,13 +3,13 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include "ecc_helper.h" void fuzz(const uint8_t in[], size_t len) { if(len > 2*384/8) return; - static EC_Group p384("secp384r1"); + static Botan::EC_Group p384("secp384r1"); return check_ecc_math(p384, in, len); } diff --git a/src/extra_tests/fuzzers/jigs/ecc_p521.cpp b/src/fuzzer/ecc_p521.cpp index c2d1e36bb..3b9ed2d5c 100644 --- a/src/extra_tests/fuzzers/jigs/ecc_p521.cpp +++ b/src/fuzzer/ecc_p521.cpp @@ -3,13 +3,13 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include "ecc_helper.h" void fuzz(const uint8_t in[], size_t len) { if(len > 2*(521+7)/8) return; - static EC_Group p521("secp521r1"); + static Botan::EC_Group p521("secp521r1"); return check_ecc_math(p521, in, len); } diff --git a/src/extra_tests/fuzzers/jigs/driver.h b/src/fuzzer/fuzzers.h index 08fffd0c1..2f1b1346d 100644 --- a/src/extra_tests/fuzzers/jigs/driver.h +++ b/src/fuzzer/fuzzers.h @@ -1,25 +1,30 @@ /* -* (C) 2015,2016 Jack Lloyd +* (C) 2015,2016,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ -#ifndef FUZZER_DRIVER_H_ -#define FUZZER_DRIVER_H_ +#ifndef BOTAN_FUZZER_DRIVER_H__ +#define BOTAN_FUZZER_DRIVER_H__ #include <stdint.h> +#include <stdlib.h> // for setenv #include <iostream> #include <vector> -#include <stdlib.h> // for setenv #include <botan/exceptn.h> -#include <botan/rng.h> -#include <botan/chacha.h> +#include <botan/chacha_rng.h> + +#if defined(BOTAN_FUZZER_IS_AFL) && !defined(__AFL_COMPILER) + #error "Build configured for AFL but not being compiled by AFL compiler" +#endif -using namespace Botan; +static const size_t max_fuzzer_input_size = 8192; extern void fuzz(const uint8_t in[], size_t len); +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len); -extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) +extern "C" int LLVMFuzzerInitialize(int *, char ***) { /* * This disables the mlock pool, as overwrites within the pool are @@ -32,68 +37,18 @@ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) // Called by main() in libFuzzer or in main for AFL below extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len) { - fuzz(in, len); - return 0; - } - -#if defined(INCLUDE_AFL_MAIN) - -// Read stdin for AFL - -int main(int argc, char* argv[]) - { - const size_t max_read = 4096; - - LLVMFuzzerInitialize(&argc, &argv); - -#if defined(__AFL_LOOP) - while(__AFL_LOOP(1000)) -#endif + if(len <= max_fuzzer_input_size) { - std::vector<uint8_t> buf(max_read); - std::cin.read((char*)buf.data(), buf.size()); - size_t got = std::cin.gcount(); - - buf.resize(got); - buf.shrink_to_fit(); - - fuzz(buf.data(), got); + fuzz(in, len); } + return 0; } -#endif - // Some helpers for the fuzzer jigs inline Botan::RandomNumberGenerator& fuzzer_rng() { - class ChaCha20_RNG : public Botan::RandomNumberGenerator - { - public: - std::string name() const override { return "ChaCha20_RNG"; } - void clear() override { /* ignored */ } - - void randomize(uint8_t out[], size_t len) override - { - Botan::clear_mem(out, len); - m_chacha.cipher1(out, len); - } - - bool is_seeded() const override { return true; } - - void add_entropy(const uint8_t[], size_t) override { /* ignored */ } - - ChaCha20_RNG() - { - std::vector<uint8_t> seed(32, 0x82); - m_chacha.set_key(seed); - } - - private: - Botan::ChaCha m_chacha; - }; - - static ChaCha20_RNG rng; + static Botan::ChaCha_RNG rng(Botan::secure_vector<uint8_t>(32)); return rng; } @@ -112,4 +67,29 @@ inline Botan::RandomNumberGenerator& fuzzer_rng() abort(); \ } } while(0) +#if defined(BOTAN_FUZZER_IS_AFL) || defined(BOTAN_FUZZER_IS_TEST) + +/* Stub for AFL */ + +int main(int argc, char* argv[]) + { + LLVMFuzzerInitialize(&argc, &argv); + +#if defined(__AFL_LOOP) + while(__AFL_LOOP(1000)) +#endif + { + std::vector<uint8_t> buf(max_fuzzer_input_size); + std::cin.read((char*)buf.data(), buf.size()); + const size_t got = std::cin.gcount(); + + buf.resize(got); + buf.shrink_to_fit(); + + LLVMFuzzerTestOneInput(buf.data(), got); + } + } + +#endif + #endif diff --git a/src/extra_tests/fuzzers/jigs/invert.cpp b/src/fuzzer/invert.cpp index 63c140139..08e8229b8 100644 --- a/src/extra_tests/fuzzers/jigs/invert.cpp +++ b/src/fuzzer/invert.cpp @@ -3,16 +3,18 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/numthry.h> -BigInt inverse_mod_ref(const BigInt& n, const BigInt& mod) +namespace { + +Botan::BigInt inverse_mod_ref(const Botan::BigInt& n, const Botan::BigInt& mod) { if(n == 0) return 0; - BigInt u = mod, v = n; - BigInt B = 0, D = 1; + Botan::BigInt u = mod, v = n; + Botan::BigInt B = 0, D = 1; while(u.is_nonzero()) { @@ -48,23 +50,24 @@ BigInt inverse_mod_ref(const BigInt& n, const BigInt& mod) return D; } +} void fuzz(const uint8_t in[], size_t len) { if(len % 2 == 1 || len > 2*4096/8) return; - const BigInt x = BigInt::decode(in, len / 2); - BigInt mod = BigInt::decode(in + len / 2, len / 2); + const Botan::BigInt x = Botan::BigInt::decode(in, len / 2); + Botan::BigInt mod = Botan::BigInt::decode(in + len / 2, len / 2); mod.set_bit(0); if(mod < 3 || x >= mod) return; - BigInt ref = inverse_mod_ref(x, mod); - BigInt ct = ct_inverse_mod_odd_modulus(x, mod); - //BigInt mon = normalized_montgomery_inverse(x, mod); + Botan::BigInt ref = inverse_mod_ref(x, mod); + Botan::BigInt ct = Botan::ct_inverse_mod_odd_modulus(x, mod); + //Botan::BigInt mon = Botan::normalized_montgomery_inverse(x, mod); if(ref != ct) { diff --git a/src/extra_tests/fuzzers/jigs/ocsp.cpp b/src/fuzzer/ocsp.cpp index 7cf2d91b0..0db265b8d 100644 --- a/src/extra_tests/fuzzers/jigs/ocsp.cpp +++ b/src/fuzzer/ocsp.cpp @@ -3,15 +3,15 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/ocsp.h> void fuzz(const uint8_t in[], size_t len) { try { - OCSP::Response response(in, len); + Botan::OCSP::Response response(in, len); } catch(Botan::Exception& e) { } } diff --git a/src/extra_tests/fuzzers/jigs/os2ecp.cpp b/src/fuzzer/os2ecp.cpp index 61ce1bd7b..dba6dbdfe 100644 --- a/src/extra_tests/fuzzers/jigs/os2ecp.cpp +++ b/src/fuzzer/os2ecp.cpp @@ -3,31 +3,35 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/ec_group.h> #include <botan/point_gfp.h> -void check_os2ecp(const EC_Group& group, const uint8_t in[], size_t len) +namespace { + +void check_os2ecp(const Botan::EC_Group& group, const uint8_t in[], size_t len) { try { - PointGFp point = OS2ECP(in, len, group.get_curve()); + Botan::PointGFp point = Botan::OS2ECP(in, len, group.get_curve()); } catch(Botan::Exception& e) {} } +} + void fuzz(const uint8_t in[], size_t len) { if(len >= 256) return; - static EC_Group p192("secp192r1"); - static EC_Group p224("secp224r1"); - static EC_Group p256("secp256r1"); - static EC_Group p384("secp384r1"); - static EC_Group p521("secp521r1"); - static EC_Group bp256("brainpool256r1"); - static EC_Group bp512("brainpool512r1"); + static Botan::EC_Group p192("secp192r1"); + static Botan::EC_Group p224("secp224r1"); + static Botan::EC_Group p256("secp256r1"); + static Botan::EC_Group p384("secp384r1"); + static Botan::EC_Group p521("secp521r1"); + static Botan::EC_Group bp256("brainpool256r1"); + static Botan::EC_Group bp512("brainpool512r1"); check_os2ecp(p192, in, len); check_os2ecp(p224, in, len); diff --git a/src/extra_tests/fuzzers/jigs/pkcs1.cpp b/src/fuzzer/pkcs1.cpp index 8a16d17e5..a0323d2b2 100644 --- a/src/extra_tests/fuzzers/jigs/pkcs1.cpp +++ b/src/fuzzer/pkcs1.cpp @@ -3,12 +3,14 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/eme_pkcs.h> #include <botan/hex.h> -secure_vector<byte> simple_pkcs1_unpad(const byte in[], size_t len) +namespace { + +std::vector<uint8_t> simple_pkcs1_unpad(const uint8_t in[], size_t len) { if(len < 10) throw Botan::Decoding_Error("bad len"); @@ -22,24 +24,27 @@ secure_vector<byte> simple_pkcs1_unpad(const byte in[], size_t len) { if(i < 10) // at least 8 padding bytes required throw Botan::Decoding_Error("insufficient padding bytes"); - return secure_vector<byte>(in + i + 1, in + len); + return std::vector<uint8_t>(in + i + 1, in + len); } } throw Botan::Decoding_Error("delim not found"); } +} + void fuzz(const uint8_t in[], size_t len) { - static EME_PKCS1v15 pkcs1; + static Botan::EME_PKCS1v15 pkcs1; - secure_vector<byte> lib_result, ref_result; + Botan::secure_vector<uint8_t> lib_result; + std::vector<uint8_t> ref_result; bool lib_rejected = false, ref_rejected = false; try { - byte valid_mask = 0; - secure_vector<byte> decoded = ((EME*)&pkcs1)->unpad(valid_mask, in, len); + uint8_t valid_mask = 0; + Botan::secure_vector<uint8_t> decoded = (static_cast<Botan::EME*>(&pkcs1))->unpad(valid_mask, in, len); if(valid_mask == 0) lib_rejected = true; @@ -54,7 +59,7 @@ void fuzz(const uint8_t in[], size_t len) { ref_result = simple_pkcs1_unpad(in, len); } - catch(Botan::Decoding_Error& e) { ref_rejected = true; /*printf("%s\n", e.what());*/ } + catch(Botan::Decoding_Error& e) { ref_rejected = true; } if(lib_rejected == ref_rejected) { @@ -65,12 +70,12 @@ void fuzz(const uint8_t in[], size_t len) if(lib_rejected == true && ref_rejected == false) { std::cerr << "Library rejected input accepted by ref\n"; - std::cerr << "Ref decoded " << hex_encode(ref_result) << "\n"; + std::cerr << "Ref decoded " << Botan::hex_encode(ref_result) << "\n"; } else if(ref_rejected == true && lib_rejected == false) { std::cerr << "Library accepted input reject by ref\n"; - std::cerr << "Lib decoded " << hex_encode(lib_result) << "\n"; + std::cerr << "Lib decoded " << Botan::hex_encode(lib_result) << "\n"; } abort(); diff --git a/src/extra_tests/fuzzers/jigs/pkcs8.cpp b/src/fuzzer/pkcs8.cpp index 47c0068ad..ad43d6f3e 100644 --- a/src/extra_tests/fuzzers/jigs/pkcs8.cpp +++ b/src/fuzzer/pkcs8.cpp @@ -3,7 +3,7 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/pkcs8.h> @@ -11,8 +11,9 @@ void fuzz(const uint8_t in[], size_t len) { try { - DataSource_Memory input(in, len); - std::unique_ptr<Private_Key> key(PKCS8::load_key(input, fuzzer_rng())); + Botan::DataSource_Memory input(in, len); + Botan::Null_RNG null_rng; + std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(input, null_rng)); } catch(Botan::Exception& e) { } } diff --git a/src/extra_tests/fuzzers/jigs/pow_mod.cpp b/src/fuzzer/pow_mod.cpp index c97dd78cd..2244c2004 100644 --- a/src/extra_tests/fuzzers/jigs/pow_mod.cpp +++ b/src/fuzzer/pow_mod.cpp @@ -4,12 +4,17 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/numthry.h> #include <botan/reducer.h> #include <botan/pow_mod.h> -BigInt simple_power_mod(BigInt x, BigInt n, const BigInt& p, const Modular_Reducer& mod_p) +namespace { + +Botan::BigInt simple_power_mod(Botan::BigInt x, + Botan::BigInt n, + const Botan::BigInt& p, + const Botan::Modular_Reducer& mod_p) { if(n == 0) { @@ -18,7 +23,7 @@ BigInt simple_power_mod(BigInt x, BigInt n, const BigInt& p, const Modular_Reduc return 1; } - BigInt y = 1; + Botan::BigInt y = 1; while(n > 1) { @@ -32,22 +37,24 @@ BigInt simple_power_mod(BigInt x, BigInt n, const BigInt& p, const Modular_Reduc return mod_p.multiply(x, y); } +} + void fuzz(const uint8_t in[], size_t len) { static const size_t p_bits = 1024; - static const BigInt p = random_prime(fuzzer_rng(), p_bits); - static Modular_Reducer mod_p(p); + static const Botan::BigInt p = random_prime(fuzzer_rng(), p_bits); + static Botan::Modular_Reducer mod_p(p); if(len == 0 || len > p_bits/8) return; try { - const BigInt g = BigInt::decode(in, len / 2); - const BigInt x = BigInt::decode(in + len / 2, len / 2); + const Botan::BigInt g = Botan::BigInt::decode(in, len / 2); + const Botan::BigInt x = Botan::BigInt::decode(in + len / 2, len / 2); - const BigInt ref = simple_power_mod(g, x, p, mod_p); - const BigInt z = Botan::power_mod(g, x, p); + const Botan::BigInt ref = simple_power_mod(g, x, p, mod_p); + const Botan::BigInt z = Botan::power_mod(g, x, p); if(ref != z) { diff --git a/src/fuzzer/redc_helper.h b/src/fuzzer/redc_helper.h new file mode 100644 index 000000000..4fc33894a --- /dev/null +++ b/src/fuzzer/redc_helper.h @@ -0,0 +1,33 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FUZZ_REDC_HELPERS_H__ +#define BOTAN_FUZZ_REDC_HELPERS_H__ + +#include "fuzzers.h" +#include <botan/reducer.h> + +namespace { + +void check_redc(std::function<void (Botan::BigInt&, Botan::secure_vector<Botan::word>&)> redc_fn, + const Botan::Modular_Reducer& redc, + const Botan::BigInt& prime, + const Botan::BigInt& x) + { + const Botan::BigInt v1 = x % prime; + const Botan::BigInt v2 = redc.reduce(x); + + Botan::secure_vector<Botan::word> ws; + Botan::BigInt v3 = x; + redc_fn(v3, ws); + + FUZZER_ASSERT_EQUAL(v1, v2); + FUZZER_ASSERT_EQUAL(v2, v3); + } + +} + +#endif diff --git a/src/extra_tests/fuzzers/jigs/redc_p192.cpp b/src/fuzzer/redc_p192.cpp index 9bece4595..e1f7c753f 100644 --- a/src/extra_tests/fuzzers/jigs/redc_p192.cpp +++ b/src/fuzzer/redc_p192.cpp @@ -4,8 +4,8 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" -#include "ecc_helper.h" +#include "fuzzers.h" +#include "redc_helper.h" #include <botan/curve_nistp.h> void fuzz(const uint8_t in[], size_t len) @@ -13,8 +13,8 @@ void fuzz(const uint8_t in[], size_t len) if(len > 2*192/8) return; - static const BigInt& prime = Botan::prime_p192(); - static const BigInt prime_2 = prime * prime; + static const Botan::BigInt& prime = Botan::prime_p192(); + static const Botan::BigInt prime_2 = prime * prime; static Botan::Modular_Reducer prime_redc(prime); Botan::BigInt x = Botan::BigInt::decode(in, len); diff --git a/src/extra_tests/fuzzers/jigs/redc_p224.cpp b/src/fuzzer/redc_p224.cpp index 637d9e6fd..a8a4d5d72 100644 --- a/src/extra_tests/fuzzers/jigs/redc_p224.cpp +++ b/src/fuzzer/redc_p224.cpp @@ -4,14 +4,14 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" -#include "ecc_helper.h" +#include "fuzzers.h" +#include "redc_helper.h" #include <botan/curve_nistp.h> void fuzz(const uint8_t in[], size_t len) { - static const BigInt& prime = Botan::prime_p224(); - static const BigInt prime_2 = prime * prime; + static const Botan::BigInt& prime = Botan::prime_p224(); + static const Botan::BigInt prime_2 = prime * prime; static Botan::Modular_Reducer prime_redc(prime); Botan::BigInt x = Botan::BigInt::decode(in, len); diff --git a/src/extra_tests/fuzzers/jigs/redc_p256.cpp b/src/fuzzer/redc_p256.cpp index cbb7f4fef..b8d78e7bb 100644 --- a/src/extra_tests/fuzzers/jigs/redc_p256.cpp +++ b/src/fuzzer/redc_p256.cpp @@ -4,8 +4,8 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" -#include "ecc_helper.h" +#include "fuzzers.h" +#include "redc_helper.h" #include <botan/curve_nistp.h> void fuzz(const uint8_t in[], size_t len) @@ -13,8 +13,8 @@ void fuzz(const uint8_t in[], size_t len) if(len > 2*256/8) return; - static const BigInt& prime = Botan::prime_p256(); - static const BigInt prime_2 = prime * prime; + static const Botan::BigInt& prime = Botan::prime_p256(); + static const Botan::BigInt prime_2 = prime * prime; static Botan::Modular_Reducer prime_redc(prime); Botan::BigInt x = Botan::BigInt::decode(in, len); diff --git a/src/extra_tests/fuzzers/jigs/redc_p384.cpp b/src/fuzzer/redc_p384.cpp index 3b990fb63..35e3ccfee 100644 --- a/src/extra_tests/fuzzers/jigs/redc_p384.cpp +++ b/src/fuzzer/redc_p384.cpp @@ -4,8 +4,8 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" -#include "ecc_helper.h" +#include "fuzzers.h" +#include "redc_helper.h" #include <botan/curve_nistp.h> void fuzz(const uint8_t in[], size_t len) @@ -13,8 +13,8 @@ void fuzz(const uint8_t in[], size_t len) if(len > 2*384/8) return; - static const BigInt& prime = Botan::prime_p384(); - static const BigInt prime_2 = prime * prime; + static const Botan::BigInt& prime = Botan::prime_p384(); + static const Botan::BigInt prime_2 = prime * prime; static Botan::Modular_Reducer prime_redc(prime); Botan::BigInt x = Botan::BigInt::decode(in, len); diff --git a/src/extra_tests/fuzzers/jigs/redc_p521.cpp b/src/fuzzer/redc_p521.cpp index 5142a44c2..c6c5d262b 100644 --- a/src/extra_tests/fuzzers/jigs/redc_p521.cpp +++ b/src/fuzzer/redc_p521.cpp @@ -4,8 +4,8 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" -#include "ecc_helper.h" +#include "fuzzers.h" +#include "redc_helper.h" #include <botan/curve_nistp.h> void fuzz(const uint8_t in[], size_t len) @@ -13,8 +13,8 @@ void fuzz(const uint8_t in[], size_t len) if(len > 2*(521+7)/8) return; - static const BigInt& prime = Botan::prime_p521(); - static const BigInt prime_2 = prime * prime; + static const Botan::BigInt& prime = Botan::prime_p521(); + static const Botan::BigInt prime_2 = prime * prime; static Botan::Modular_Reducer prime_redc(prime); Botan::BigInt x = Botan::BigInt::decode(in, len); diff --git a/src/extra_tests/fuzzers/jigs/ressol.cpp b/src/fuzzer/ressol.cpp index 6fbb85690..17ba88b8b 100644 --- a/src/extra_tests/fuzzers/jigs/ressol.cpp +++ b/src/fuzzer/ressol.cpp @@ -4,7 +4,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/numthry.h> #include <botan/reducer.h> @@ -12,21 +12,21 @@ void fuzz(const uint8_t in[], size_t len) { // Ressol is mostly used for ECC point decompression so best to test smaller sizes static const size_t p_bits = 256; - static const BigInt p = random_prime(fuzzer_rng(), p_bits); - static const Modular_Reducer mod_p(p); + static const Botan::BigInt p = random_prime(fuzzer_rng(), p_bits); + static const Botan::Modular_Reducer mod_p(p); if(len > p_bits / 8) return; try { - const BigInt a = BigInt::decode(in, len); - BigInt a_sqrt = Botan::ressol(a, p); + const Botan::BigInt a = Botan::BigInt::decode(in, len); + Botan::BigInt a_sqrt = Botan::ressol(a, p); if(a_sqrt > 0) { - const BigInt a_redc = mod_p.reduce(a); - const BigInt z = mod_p.square(a_sqrt); + const Botan::BigInt a_redc = mod_p.reduce(a); + const Botan::BigInt z = mod_p.square(a_sqrt); if(z != a_redc) { diff --git a/src/extra_tests/fuzzers/jigs/tls_client.cpp b/src/fuzzer/tls_client.cpp index d3fbd069c..197e97928 100644 --- a/src/extra_tests/fuzzers/jigs/tls_client.cpp +++ b/src/fuzzer/tls_client.cpp @@ -4,17 +4,17 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/tls_client.h> -class Fuzzer_TLS_Client_Creds : public Credentials_Manager +class Fuzzer_TLS_Client_Creds : public Botan::Credentials_Manager { public: std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } - SymmetricKey psk(const std::string&, const std::string&, const std::string&) override + Botan::SymmetricKey psk(const std::string&, const std::string&, const std::string&) override { - return SymmetricKey("AABBCCDDEEFF00112233445566778899"); + return Botan::SymmetricKey("AABBCCDDEEFF00112233445566778899"); } }; @@ -23,18 +23,18 @@ void fuzz(const uint8_t in[], size_t len) if(len == 0) return; - auto dev_null = [](const byte[], size_t) {}; + auto dev_null = [](const uint8_t[], size_t) {}; - auto ignore_alerts = [](TLS::Alert, const byte[], size_t) {}; - auto ignore_hs = [](const TLS::Session&) { abort(); return true; }; + auto ignore_alerts = [](Botan::TLS::Alert, const uint8_t[], size_t) {}; + auto ignore_hs = [](const Botan::TLS::Session&) { abort(); return true; }; - TLS::Session_Manager_Noop session_manager; - TLS::Policy policy; - TLS::Protocol_Version client_offer = TLS::Protocol_Version::TLS_V12; - TLS::Server_Information info("server.name", 443); + Botan::TLS::Session_Manager_Noop session_manager; + Botan::TLS::Policy policy; + Botan::TLS::Protocol_Version client_offer = Botan::TLS::Protocol_Version::TLS_V12; + Botan::TLS::Server_Information info("server.name", 443); Fuzzer_TLS_Client_Creds creds; - TLS::Client client(dev_null, + Botan::TLS::Client client(dev_null, dev_null, ignore_alerts, ignore_hs, diff --git a/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp b/src/fuzzer/tls_client_hello.cpp index 7c95c7db3..28c77c9b6 100644 --- a/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp +++ b/src/fuzzer/tls_client_hello.cpp @@ -3,7 +3,8 @@ * * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" + +#include "fuzzers.h" #include <botan/tls_messages.h> void fuzz(const uint8_t in[], size_t len) diff --git a/src/extra_tests/fuzzers/jigs/tls_server.cpp b/src/fuzzer/tls_server.cpp index a4e0d5f00..54586595f 100644 --- a/src/extra_tests/fuzzers/jigs/tls_server.cpp +++ b/src/fuzzer/tls_server.cpp @@ -4,7 +4,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "driver.h" +#include "fuzzers.h" #include <botan/tls_server.h> const char* fixed_rsa_key = @@ -59,13 +59,13 @@ const char* fixed_rsa_cert = "Dk02a/1AOJZdZReDbgXhlqaUx5pk/rzo4mDzvu5HSCeXmClz\n" "-----END CERTIFICATE-----\n"; -class Fuzzer_TLS_Server_Creds : public Credentials_Manager +class Fuzzer_TLS_Server_Creds : public Botan::Credentials_Manager { public: Fuzzer_TLS_Server_Creds() { - DataSource_Memory cert_in(fixed_rsa_cert); - DataSource_Memory key_in(fixed_rsa_key); + Botan::DataSource_Memory cert_in(fixed_rsa_cert); + Botan::DataSource_Memory key_in(fixed_rsa_key); m_rsa_cert.reset(new Botan::X509_Certificate(cert_in)); //m_rsa_key.reset(Botan::PKCS8::load_key(key_in, fuzzer_rng()); @@ -73,8 +73,8 @@ class Fuzzer_TLS_Server_Creds : public Credentials_Manager std::vector<Botan::X509_Certificate> cert_chain( const std::vector<std::string>& algos, - const std::string& type, - const std::string& hostname) override + const std::string& /*type*/, + const std::string& /*hostname*/) override { std::vector<Botan::X509_Certificate> v; @@ -90,7 +90,7 @@ class Fuzzer_TLS_Server_Creds : public Credentials_Manager return v; } - Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& /*cert*/, const std::string& /*type*/, const std::string& /*context*/) override { @@ -99,9 +99,9 @@ class Fuzzer_TLS_Server_Creds : public Credentials_Manager std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } - SymmetricKey psk(const std::string&, const std::string&, const std::string&) override + Botan::SymmetricKey psk(const std::string&, const std::string&, const std::string&) override { - return SymmetricKey("AABBCCDDEEFF00112233445566778899"); + return Botan::SymmetricKey("AABBCCDDEEFF00112233445566778899"); } private: std::unique_ptr<Botan::X509_Certificate> m_rsa_cert; @@ -113,14 +113,14 @@ void fuzz(const uint8_t in[], size_t len) if(len == 0) return; - auto dev_null = [](const byte[], size_t) {}; + auto dev_null = [](const uint8_t[], size_t) {}; - auto ignore_alerts = [](TLS::Alert, const byte[], size_t) {}; - auto ignore_hs = [](const TLS::Session&) { return true; }; + auto ignore_alerts = [](Botan::TLS::Alert, const uint8_t[], size_t) {}; + auto ignore_hs = [](const Botan::TLS::Session&) { return true; }; - TLS::Session_Manager_Noop session_manager; - TLS::Policy policy; - TLS::Server_Information info("server.name", 443); + Botan::TLS::Session_Manager_Noop session_manager; + Botan::TLS::Policy policy; + Botan::TLS::Server_Information info("server.name", 443); Fuzzer_TLS_Server_Creds creds; auto next_proto_fn = [](const std::vector<std::string>& protos) -> std::string { @@ -132,7 +132,7 @@ void fuzz(const uint8_t in[], size_t len) const bool is_datagram = (len % 2 == 0); - TLS::Server server(dev_null, + Botan::TLS::Server server(dev_null, dev_null, ignore_alerts, ignore_hs, diff --git a/src/scripts/ci/travis/build.sh b/src/scripts/ci/travis/build.sh index 36517738b..d2e35112e 100755 --- a/src/scripts/ci/travis/build.sh +++ b/src/scripts/ci/travis/build.sh @@ -23,6 +23,8 @@ elif [ "$BUILD_MODE" = "nist" ]; then elif [ "$BUILD_MODE" = "sonarqube" ]; then # No special flags required CFG_FLAGS+=() +elif [ "$BUILD_MODE" = "fuzzers" ]; then + CFG_FLAGS+=(--build-fuzzers=test --with-sanitizers --with-debug-info --disable-shared) elif [ "$BUILD_MODE" = "parallel" ]; then if [ "$CC" = "gcc" ]; then @@ -137,6 +139,11 @@ else time "${MAKE_CMD[@]}" fi +if [ "$BUILD_MODE" = "fuzzers" ]; then + make fuzzers + make fuzzer_corpus_zip +fi + # post-build ccache stats ccache --show-stats @@ -171,9 +178,13 @@ if [ "$BUILD_MODE" = "sonarqube" ]; then # When neither on master branch nor on a non-external pull request => nothing to do fi -if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || \ +if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || ( [ "${BUILD_MODE:0:5}" = "cross" ] && [ "$TRAVIS_OS_NAME" = "osx" ] ); then echo "Running tests disabled on this build type" + +elif [ "$BUILD_MODE" = "fuzzers" ]; then + # Test each fuzzer against its corpus + ./src/scripts/test_fuzzers.py fuzzer_corpus build/fuzzer else TEST_CMD=("${TEST_PREFIX[@]}" $TEST_EXE "${TEST_FLAGS[@]}") echo "Running" "${TEST_CMD[@]}" diff --git a/src/scripts/create_corpus_zip.py b/src/scripts/create_corpus_zip.py new file mode 100755 index 000000000..5faee3b52 --- /dev/null +++ b/src/scripts/create_corpus_zip.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# These is used to create fuzzer corpus zip files + +# This is primarily used by OSS-Fuzz but might be useful if you were +# deploying the binaries in a custom fuzzer deployment system. + +import sys +import os +import zipfile +import stat + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 2 and len(args) != 3: + print("Usage: %s corpus_dir <output_dir>" % (args[0])) + return 1 + + root_dir = args[1] + + if len(args) == 3: + output_dir = args[2] + else: + output_dir = '' + + if not os.access(root_dir, os.R_OK): + print("Error could not access directory '%s'" % (root_dir)) + return 1 + + for corpus_dir in os.listdir(root_dir): + if corpus_dir == '.git': + continue + subdir = os.path.join(root_dir, corpus_dir) + if not stat.S_ISDIR(os.stat(subdir).st_mode): + continue + + zipfile_path = os.path.join(output_dir, '%s.zip' % (corpus_dir)) + zf = zipfile.ZipFile(zipfile_path, 'w', zipfile.ZIP_DEFLATED) + for f in os.listdir(subdir): + zf.write(os.path.join(subdir, f), f) + zf.close() + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/scripts/test_fuzzers.py b/src/scripts/test_fuzzers.py new file mode 100755 index 000000000..0d473e00c --- /dev/null +++ b/src/scripts/test_fuzzers.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +import sys +import os +import subprocess + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 3: + print("Usage: %s <corpus_dir> <fuzzers_dir>" % (args[0])) + return 1 + + corpus_dir = args[1] + fuzzer_dir = args[2] + + if not os.access(corpus_dir, os.R_OK): + print("Error could not access corpus directory '%s'" % (corpus_dir)) + return 1 + + if not os.access(fuzzer_dir, os.R_OK): + print("Error could not access fuzzers directory '%s'" % (fuzzer_dir)) + return 1 + + fuzzers = set([]) + for fuzzer in os.listdir(fuzzer_dir): + if fuzzer.endswith('.zip'): + continue + fuzzers.add(fuzzer) + + corpii = set([]) + for corpus in os.listdir(corpus_dir): + if corpus in ['.git', 'readme.txt']: + continue + corpii.add(corpus) + + fuzzers_without_corpus = fuzzers - corpii + corpus_without_fuzzers = corpii - fuzzers + + for f in sorted(list(fuzzers_without_corpus)): + print("Warning: Fuzzer %s has no corpus" % (f)) + for c in sorted(list(corpus_without_fuzzers)): + print("Warning: Corpus %s has no fuzzer" % (c)) + + fuzzers_with_corpus = fuzzers & corpii + + any_crashes = False + + for f in sorted(list(fuzzers_with_corpus)): + fuzzer_bin = os.path.join(fuzzer_dir, f) + corpus_files = os.path.join(corpus_dir, f) + for corpus_file in sorted(list(os.listdir(corpus_files))): + corpus_fd = open(os.path.join(corpus_files, corpus_file), 'r') + fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + (stdout, stderr) = fuzzer_proc.communicate() + corpus_fd.close() + + if fuzzer_proc.returncode != 0: + print("Fuzzer %s crashed with input %s returncode %d" % (f, corpus_file, fuzzer_proc.returncode)) + any_crashes = True + + if len(stdout) != 0: + stdout = stdout.decode('ascii') + print("Fuzzer %s produced stdout on input %s:\n%s" % (f, corpus_file, stdout)) + + if len(stderr) != 0: + stderr = stderr.decode('ascii') + print("Fuzzer %s produced stderr on input %s:\n%s" % (f, corpus_file, stderr)) + + if any_crashes: + return 2 + return 0 + + +if __name__ == '__main__': + sys.exit(main()) |