1diff --git a/configure.ac b/configure.ac 2index 7b398f3df..ee69b3063 100644 3--- a/configure.ac 4+++ b/configure.ac 5@@ -991,6 +991,15 @@ if test x"$use_tofu" = xyes ; then 6 fi 7 fi 8 9+# TODO choose when to build fuzzing with option ? 10+AC_CHECK_LIB(FuzzingEngine, main, 11+ [ LIB_FUZZING_ENGINE="$LIB_FUZZING_ENGINE" 12+ have_fuzz=yes 13+ ]) 14+AC_SUBST(LIB_FUZZING_ENGINE) 15+AC_CHECK_PROG(HAVE_CLANGXX, clang++, 1) 16+AM_CONDITIONAL(HAVE_LIB_FUZZING_ENGINE, [test "$have_fuzz" = yes -a "$HAVE_CLANGXX" = 1]) 17+ 18 AM_CONDITIONAL(SQLITE3, test "$have_sqlite" = "yes") 19 20 if test x"$use_tofu" = xyes ; then 21@@ -2149,6 +2158,7 @@ tests/migrations/Makefile 22 tests/tpm2dtests/Makefile 23 tests/gpgme/Makefile 24 tests/pkits/Makefile 25+tests/fuzz/Makefile 26 g10/gpg.w32-manifest 27 tools/gpg-connect-agent.w32-manifest 28 tools/gpgconf.w32-manifest 29diff --git a/g10/Makefile.am b/g10/Makefile.am 30index eb23573b7..785ac2b4b 100644 31--- a/g10/Makefile.am 32+++ b/g10/Makefile.am 33@@ -47,6 +47,7 @@ endif 34 # NB: We use noinst_ for gpg and gpgv so that we can install them with 35 # the install-hook target under the name gpg2/gpgv2. 36 noinst_PROGRAMS = gpg 37+noinst_LIBRARIES = libgpg.a 38 if !HAVE_W32CE_SYSTEM 39 noinst_PROGRAMS += gpgv 40 endif 41@@ -164,6 +165,9 @@ gpg_sources = server.c \ 42 gpg_SOURCES = gpg.c \ 43 keyedit.c keyedit.h \ 44 $(gpg_sources) 45+libgpg_a_SOURCES = keyedit.c keyedit.h \ 46+ $(gpg_sources) 47+ 48 49 gpgv_SOURCES = gpgv.c \ 50 $(common_source) \ 51diff --git a/g10/armor.c b/g10/armor.c 52index eb2d28bca..594f5bd2d 100644 53--- a/g10/armor.c 54+++ b/g10/armor.c 55@@ -313,7 +313,9 @@ static void 56 invalid_armor(void) 57 { 58 write_status(STATUS_BADARMOR); 59+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 60 g10_exit(1); /* stop here */ 61+#endif 62 } 63 64 65diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h 66index c0f1e0cec..52652a0e0 100644 67--- a/g10/call-dirmngr.h 68+++ b/g10/call-dirmngr.h 69@@ -19,6 +19,8 @@ 70 #ifndef GNUPG_G10_CALL_DIRMNGR_H 71 #define GNUPG_G10_CALL_DIRMNGR_H 72 73+#include "options.h" 74+ 75 void gpg_dirmngr_deinit_session_data (ctrl_t ctrl); 76 77 gpg_error_t gpg_dirmngr_ks_list (ctrl_t ctrl, char **r_keyserver); 78diff --git a/g10/compress-bz2.c b/g10/compress-bz2.c 79index 45aa40dfc..1a74a89d7 100644 80--- a/g10/compress-bz2.c 81+++ b/g10/compress-bz2.c 82@@ -155,8 +155,15 @@ do_uncompress( compress_filter_context_t *zfx, bz_stream *bzs, 83 (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, zrc); 84 if( zrc == BZ_STREAM_END ) 85 rc = -1; /* eof */ 86- else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR ) 87- log_fatal("bz2lib inflate problem: rc=%d\n", zrc ); 88+ else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR ) { 89+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 90+ log_error("bz2lib inflate problem: rc=%d\n", zrc ); 91+ rc = GPG_ERR_BAD_DATA; 92+ break; 93+#else 94+ log_fatal("bz2lib inflate problem: rc=%d\n", zrc ); 95+#endif 96+ } 97 else if (zrc == BZ_OK && eofseen 98 && !bzs->avail_in && bzs->avail_out > 0) 99 { 100diff --git a/g10/compress.c b/g10/compress.c 101index e7a6f2b11..9a9ab5460 100644 102--- a/g10/compress.c 103+++ b/g10/compress.c 104@@ -204,10 +204,19 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs, 105 if( zrc == Z_STREAM_END ) 106 rc = -1; /* eof */ 107 else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) { 108+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 109+ rc = -1; 110+ zrc = Z_BUF_ERROR; 111+ if( zs->msg ) 112+ log_error("zlib inflate problem: %s\n", zs->msg ); 113+ else 114+ log_error("zlib inflate problem: rc=%d\n", zrc ); 115+#else 116 if( zs->msg ) 117 log_fatal("zlib inflate problem: %s\n", zs->msg ); 118 else 119 log_fatal("zlib inflate problem: rc=%d\n", zrc ); 120+#endif 121 } 122 } while (zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR 123 && !leave); 124diff --git a/g10/parse-packet.c b/g10/parse-packet.c 125index bb05eabb7..638d895d0 100644 126--- a/g10/parse-packet.c 127+++ b/g10/parse-packet.c 128@@ -806,7 +806,12 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, 129 * the uncompressing layer - in some error cases it just loops 130 * and spits out 0xff bytes. */ 131 log_error ("%s: garbled packet detected\n", iobuf_where (inp)); 132+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 133+ rc = gpg_error (GPG_ERR_INV_PACKET); 134+ goto leave; 135+#else 136 g10_exit (2); 137+#endif 138 } 139 140 if (out && pkttype) 141diff --git a/g10/plaintext.c b/g10/plaintext.c 142index 3e169d93f..aa83ffbe0 100644 143--- a/g10/plaintext.c 144+++ b/g10/plaintext.c 145@@ -617,10 +617,16 @@ ask_for_detached_datafile (gcry_md_hd_t md, gcry_md_hd_t md2, 146 147 if (!fp) 148 { 149+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 150+ errno = ENOENT; 151+ rc = gpg_error_from_syserror (); 152+ goto leave; 153+#else 154 if (opt.verbose) 155 log_info (_("reading stdin ...\n")); 156 fp = iobuf_open (NULL); 157 log_assert (fp); 158+#endif 159 } 160 do_hash (md, md2, fp, textmode); 161 iobuf_close (fp); 162diff --git a/g10/sig-check.c b/g10/sig-check.c 163index 8dd18b2e2..9f5db89f9 100644 164--- a/g10/sig-check.c 165+++ b/g10/sig-check.c 166@@ -783,8 +783,9 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig) 167 { 168 gcry_md_hd_t md; 169 170- if (gcry_md_open (&md, sig->digest_algo, 0)) 171- BUG (); 172+ rc = gcry_md_open (&md, sig->digest_algo, 0); 173+ if (rc) 174+ return rc; 175 hash_public_key(md,pk); 176 /* Note: check_signature only checks that the signature 177 is good. It does not fail if the key is revoked. */ 178diff --git a/tests/Makefile.am b/tests/Makefile.am 179index f29b68a53..e788c9916 100644 180--- a/tests/Makefile.am 181+++ b/tests/Makefile.am 182@@ -24,7 +24,13 @@ else 183 tpm2dtests = 184 endif 185 186-SUBDIRS = gpgscm openpgp cms migrations gpgme pkits $(tpm2dtests) . 187+SUBDIRS = gpgscm openpgp cms migrations gpgme pkits $(tpm2dtests) 188+ 189+if MAINTAINER_MODE 190+SUBDIRS += fuzz 191+endif 192+ 193+SUBDIRS += . 194 195 GPGSM = ../sm/gpgsm 196 197diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am 198new file mode 100644 199index 000000000..eb2216d3e 200--- /dev/null 201+++ b/tests/fuzz/Makefile.am 202@@ -0,0 +1,84 @@ 203+# Makefile.am - For tests/fuzz 204+# Copyright (C) 2018 Free Software Foundation, Inc. 205+# 206+# This file is part of GnuPG. 207+# 208+# GnuPG is free software; you can redistribute it and/or modify 209+# it under the terms of the GNU General Public License as published by 210+# the Free Software Foundation; either version 3 of the License, or 211+# (at your option) any later version. 212+# 213+# GnuPG is distributed in the hope that it will be useful, 214+# but WITHOUT ANY WARRANTY; without even the implied warranty of 215+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 216+# GNU General Public License for more details. 217+# 218+# You should have received a copy of the GNU General Public License 219+# along with this program; if not, see <https://www.gnu.org/licenses/>. 220+# Process this file with automake to create Makefile.in 221+ 222+ 223+# Programs required before we can run these tests. 224+required_pgms = ../../g10/gpg$(EXEEXT) 225+ 226+ 227+# Force linking with clang++ even if we have pure C fuzzing targets 228+CCLD = clang++ 229+AM_LDFLAGS = -stdlib=libc++ 230+ 231+AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/g10 232+include $(top_srcdir)/am/cmacros.am 233+ 234+noinst_PROGRAMS = fuzz_verify fuzz_import fuzz_decrypt fuzz_list 235+ 236+fuzz_verify_SOURCES = fuzz_verify.c 237+ 238+fuzz_verify_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE) \ 239+ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ 240+ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ 241+ $(LIBICONV) $(resource_objs) $(extra_sys_libs) 242+ 243+fuzz_verify_DEPENDENCIES = fuzz_verify_seed_corpus.zip 244+ 245+fuzz_verify_seed_corpus.zip: 246+ cd .. && zip -r fuzz/fuzz_verify_seed_corpus.zip openpgp/tofu/conflicting/* openpgp/tofu/cross-sigs/* openpgp/samplemsgs/* 247+ 248+fuzz_import_SOURCES = fuzz_import.c 249+ 250+fuzz_import_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE)\ 251+ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ 252+ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ 253+ $(LIBICONV) $(resource_objs) $(extra_sys_libs) 254+ 255+fuzz_import_DEPENDENCIES = fuzz_import_seed_corpus.zip 256+ 257+fuzz_import_seed_corpus.zip: 258+ cd .. && zip -r fuzz/fuzz_import_seed_corpus.zip openpgp/samplekeys/* openpgp/key-selection/* openpgp/*.asc openpgp/trust-pgp/*.asc openpgp/tofu/conflicting/* openpgp/tofu/cross-sigs/* 259+ 260+fuzz_decrypt_SOURCES = fuzz_decrypt.c 261+ 262+fuzz_decrypt_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE)\ 263+ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ 264+ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ 265+ $(LIBICONV) $(resource_objs) $(extra_sys_libs) 266+ 267+fuzz_decrypt_DEPENDENCIES = fuzz_decrypt_seed_corpus.zip 268+ 269+fuzz_decrypt_seed_corpus.zip: 270+ cd .. && zip -r fuzz/fuzz_decrypt_seed_corpus.zip openpgp/tofu/conflicting/* openpgp/tofu/cross-sigs/* openpgp/samplemsgs/* 271+ 272+fuzz_list_SOURCES = fuzz_list.c 273+ 274+fuzz_list_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE)\ 275+$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ 276+$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ 277+$(LIBICONV) $(resource_objs) $(extra_sys_libs) 278+ 279+fuzz_list_DEPENDENCIES = fuzz_list_seed_corpus.zip 280+ 281+fuzz_list_seed_corpus.zip: 282+ cd .. && zip -r fuzz/fuzz_list_seed_corpus.zip openpgp/ 283+ 284+# We need to depend on a couple of programs so that the tests don't 285+# start before all programs are built. 286+all-local: $(required_pgms) 287