blob: 226c86c4c76974543fb575a497d8ab57c8c3c75a [file] [log] [blame]
diff --git a/configure.ac b/configure.ac
index 5bb366e76..ee9403149 100644
--- a/configure.ac
+++ b/configure.ac
@@ -991,6 +991,15 @@ AC_CHECK_LIB(util, openpty,
])
AC_SUBST(LIBUTIL_LIBS)
+# TODO choose when to build fuzzing with option ?
+AC_CHECK_LIB(FuzzingEngine, main,
+ [ LIB_FUZZING_ENGINE="$LIB_FUZZING_ENGINE"
+ have_fuzz=yes
+ ])
+AC_SUBST(LIB_FUZZING_ENGINE)
+AC_CHECK_PROG(HAVE_CLANGXX, clang++, 1)
+AM_CONDITIONAL(HAVE_LIB_FUZZING_ENGINE, [test "$have_fuzz" = yes -a "$HAVE_CLANGXX" = 1])
+
# shred is used to clean temporary plain text files.
AC_PATH_PROG(SHRED, shred, /usr/bin/shred)
AC_DEFINE_UNQUOTED(SHRED,
@@ -2094,6 +2103,7 @@ tests/migrations/Makefile
tests/gpgsm/Makefile
tests/gpgme/Makefile
tests/pkits/Makefile
+tests/fuzz/Makefile
g10/gpg.w32-manifest
])
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 2b92daf33..505d98f5e 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -47,6 +47,7 @@ endif
# NB: We use noinst_ for gpg and gpgv so that we can install them with
# the install-hook target under the name gpg2/gpgv2.
noinst_PROGRAMS = gpg
+noinst_LIBRARIES = libgpg.a
if !HAVE_W32CE_SYSTEM
noinst_PROGRAMS += gpgv
endif
@@ -164,6 +165,9 @@ gpg_SOURCES = gpg.c \
keyedit.c keyedit.h \
$(gpg_sources)
+libgpg_a_SOURCES = keyedit.c keyedit.h \
+ $(gpg_sources)
+
#gpgcompose_SOURCES = gpgcompose.c $(gpg_sources)
gpgv_SOURCES = gpgv.c \
$(common_source) \
diff --git a/g10/armor.c b/g10/armor.c
index eb2d28bca..594f5bd2d 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -313,7 +313,9 @@ static void
invalid_armor(void)
{
write_status(STATUS_BADARMOR);
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
g10_exit(1); /* stop here */
+#endif
}
diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h
index 285c4cb4d..7af328c2a 100644
--- a/g10/call-dirmngr.h
+++ b/g10/call-dirmngr.h
@@ -19,6 +19,8 @@
#ifndef GNUPG_G10_CALL_DIRMNGR_H
#define GNUPG_G10_CALL_DIRMNGR_H
+#include "options.h"
+
void gpg_dirmngr_deinit_session_data (ctrl_t ctrl);
gpg_error_t gpg_dirmngr_ks_list (ctrl_t ctrl, char **r_keyserver);
diff --git a/g10/compress-bz2.c b/g10/compress-bz2.c
index 45aa40dfc..1a74a89d7 100644
--- a/g10/compress-bz2.c
+++ b/g10/compress-bz2.c
@@ -155,8 +155,15 @@ do_uncompress( compress_filter_context_t *zfx, bz_stream *bzs,
(unsigned)bzs->avail_in, (unsigned)bzs->avail_out, zrc);
if( zrc == BZ_STREAM_END )
rc = -1; /* eof */
- else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR )
- log_fatal("bz2lib inflate problem: rc=%d\n", zrc );
+ else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR ) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ log_error("bz2lib inflate problem: rc=%d\n", zrc );
+ rc = GPG_ERR_BAD_DATA;
+ break;
+#else
+ log_fatal("bz2lib inflate problem: rc=%d\n", zrc );
+#endif
+ }
else if (zrc == BZ_OK && eofseen
&& !bzs->avail_in && bzs->avail_out > 0)
{
diff --git a/g10/compress.c b/g10/compress.c
index e7a6f2b11..9a9ab5460 100644
--- a/g10/compress.c
+++ b/g10/compress.c
@@ -204,10 +204,19 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
if( zrc == Z_STREAM_END )
rc = -1; /* eof */
else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ rc = -1;
+ zrc = Z_BUF_ERROR;
+ if( zs->msg )
+ log_error("zlib inflate problem: %s\n", zs->msg );
+ else
+ log_error("zlib inflate problem: rc=%d\n", zrc );
+#else
if( zs->msg )
log_fatal("zlib inflate problem: %s\n", zs->msg );
else
log_fatal("zlib inflate problem: rc=%d\n", zrc );
+#endif
}
} while (zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR
&& !leave);
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 2f92c1d2c..41e077a6a 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -738,7 +738,12 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
* the uncompressing layer - in some error cases it just loops
* and spits out 0xff bytes. */
log_error ("%s: garbled packet detected\n", iobuf_where (inp));
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+#else
g10_exit (2);
+#endif
}
if (out && pkttype)
diff --git a/g10/plaintext.c b/g10/plaintext.c
index f9e0a4296..7b9709c08 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -656,10 +656,16 @@ ask_for_detached_datafile (gcry_md_hd_t md, gcry_md_hd_t md2,
if (!fp)
{
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ errno = ENOENT;
+ rc = gpg_error_from_syserror ();
+ goto leave;
+#else
if (opt.verbose)
log_info (_("reading stdin ...\n"));
fp = iobuf_open (NULL);
log_assert (fp);
+#endif
}
do_hash (md, md2, fp, textmode);
iobuf_close (fp);
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 4c172d692..bd87f00ad 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -760,8 +760,9 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
{
gcry_md_hd_t md;
- if (gcry_md_open (&md, sig->digest_algo, 0))
- BUG ();
+ rc = gcry_md_open (&md, sig->digest_algo, 0);
+ if (rc)
+ return rc;
hash_public_key(md,pk);
/* Note: check_signature only checks that the signature
is good. It does not fail if the key is revoked. */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b9be6aaa6..d6659eaf1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -18,7 +18,13 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = gpgscm openpgp migrations gpgsm gpgme pkits .
+SUBDIRS = gpgscm openpgp migrations gpgsm gpgme pkits
+
+if MAINTAINER_MODE
+SUBDIRS += fuzz
+endif
+
+SUBDIRS += .
GPGSM = ../sm/gpgsm
diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am
new file mode 100644
index 000000000..3bf039a54
--- /dev/null
+++ b/tests/fuzz/Makefile.am
@@ -0,0 +1,84 @@
+# Makefile.am - For tests/fuzz
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+# Process this file with automake to create Makefile.in
+
+
+# Programs required before we can run these tests.
+required_pgms = ../../g10/gpg$(EXEEXT)
+
+
+# Force linking with clang++ even if we have pure C fuzzing targets
+CCLD = clang++
+AM_LDFLAGS = -stdlib=libc++
+
+AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/g10
+include $(top_srcdir)/am/cmacros.am
+
+noinst_PROGRAMS = fuzz_verify fuzz_import fuzz_decrypt fuzz_list
+
+fuzz_verify_SOURCES = fuzz_verify.c
+
+fuzz_verify_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE) \
+ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
+ $(LIBICONV) $(resource_objs) $(extra_sys_libs)
+
+fuzz_verify_DEPENDENCIES = fuzz_verify_seed_corpus.zip
+
+fuzz_verify_seed_corpus.zip:
+ cd .. && zip -r fuzz/fuzz_verify_seed_corpus.zip openpgp/tofu/conflicting/* openpgp/tofu/cross-sigs/* openpgp/samplemsgs/*
+
+fuzz_import_SOURCES = fuzz_import.c
+
+fuzz_import_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE)\
+ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
+ $(LIBICONV) $(resource_objs) $(extra_sys_libs)
+
+fuzz_import_DEPENDENCIES = fuzz_import_seed_corpus.zip
+
+fuzz_import_seed_corpus.zip:
+ 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/*
+
+fuzz_decrypt_SOURCES = fuzz_decrypt.c
+
+fuzz_decrypt_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE)\
+ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
+ $(LIBICONV) $(resource_objs) $(extra_sys_libs)
+
+fuzz_decrypt_DEPENDENCIES = fuzz_decrypt_seed_corpus.zip
+
+fuzz_decrypt_seed_corpus.zip:
+ cd .. && zip -r fuzz/fuzz_decrypt_seed_corpus.zip openpgp/tofu/conflicting/* openpgp/tofu/cross-sigs/* openpgp/samplemsgs/*
+
+fuzz_list_SOURCES = fuzz_list.c
+
+fuzz_list_LDADD = $(top_srcdir)/g10/libgpg.a ../../kbx/libkeybox.a ../../common/libcommon.a ../../common/libgpgrl.a $(LIB_FUZZING_ENGINE)\
+$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
+$(LIBICONV) $(resource_objs) $(extra_sys_libs)
+
+fuzz_list_DEPENDENCIES = fuzz_list_seed_corpus.zip
+
+fuzz_list_seed_corpus.zip:
+ cd .. && zip -r fuzz/fuzz_list_seed_corpus.zip openpgp/
+
+# We need to depend on a couple of programs so that the tests don't
+# start before all programs are built.
+all-local: $(required_pgms)