changeset 1557:61a793b6e471 fuzz

merge from main
author Matt Johnston <matt@ucc.asn.au>
date Wed, 28 Feb 2018 21:28:59 +0800
parents bb8eaa26bc93 (diff) 4c382cbb19e6 (current diff)
children 2f64cb3d3007
files Makefile.in configure.ac runopts.h svr-auth.c svr-runopts.c
diffstat 36 files changed, 1300 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,2 @@
+.*\.o
+.*~
--- a/Makefile.in	Tue Feb 27 22:49:06 2018 +0800
+++ b/Makefile.in	Wed Feb 28 21:28:59 2018 +0800
@@ -36,6 +36,7 @@
 		queue.o \
 		atomicio.o compat.o fake-rfc2553.o \
 		ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
+		dbmalloc.o \
 		gensignkey.o gendss.o genrsa.o
 
 SVROBJS=svr-kex.o svr-auth.o sshpty.o \
@@ -59,6 +60,10 @@
 
 SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
 
+ifeq (@DROPBEAR_FUZZ@, 1)
+	COMMONOBJS += fuzz-common.o  fuzz-wrapfd.o
+endif
+
 dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
 dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
 dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
@@ -236,3 +241,53 @@
 
 tidy:
 	-rm -f *~ *.gcov */*~
+
+## Fuzzing targets
+
+# list of fuzz targets
+FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths
+
+FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
+
+list-fuzz-targets:
+	@echo $(FUZZ_TARGETS)
+
+# fuzzers that don't use libfuzzer, just a standalone harness that feeds inputs
+fuzzstandalone: FUZZLIB=fuzz-harness.o
+fuzzstandalone: fuzz-harness.o fuzz-targets
+
+# exclude svr-main.o to avoid duplicate main
+svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
+
+# build all the fuzzers. This will require fail to link unless built with
+# make fuzzers LIBS=-lFuzzer.a 
+# or similar - the library provides main().
+fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
+
+fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+
+fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+
+
+fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+
+fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+
+fuzzer-%.options: Makefile
+	echo "[libfuzzer]"               > $@
+	echo "max_len = 50000"          >> $@
+
+# run this to update hardcoded hostkeys for for fuzzing. 
+# hostkeys.c is checked in to hg.
+fuzz-hostkeys:
+	dropbearkey -t rsa -f keyr
+	dropbearkey -t dss -f keyd
+	dropbearkey -t ecdsa -size 256 -f keye
+	echo > hostkeys.c
+	/usr/bin/xxd -i -a keyr >> hostkeys.c
+	/usr/bin/xxd -i -a keye >> hostkeys.c
+	/usr/bin/xxd -i -a keyd >> hostkeys.c
--- a/buffer.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/buffer.c	Wed Feb 28 21:28:59 2018 +0800
@@ -209,6 +209,7 @@
 
 	unsigned int len;
 	char* ret;
+	void* src = NULL;
 	len = buf_getint(buf);
 	if (len > MAX_STRING_LEN) {
 		dropbear_exit("String too long");
@@ -217,8 +218,9 @@
 	if (retlen != NULL) {
 		*retlen = len;
 	}
+	src = buf_getptr(buf, len);
 	ret = m_malloc(len+1);
-	memcpy(ret, buf_getptr(buf, len), len);
+	memcpy(ret, src, len);
 	buf_incrpos(buf, len);
 	ret[len] = '\0';
 
--- a/common-kex.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/common-kex.c	Wed Feb 28 21:28:59 2018 +0800
@@ -48,7 +48,6 @@
 /* helper function for gen_new_keys */
 static void hashkeys(unsigned char *out, unsigned int outlen, 
 		const hash_state * hs, const unsigned char X);
-static void finish_kexhashbuf(void);
 
 
 /* Send our list of algorithms we can use */
@@ -391,6 +390,14 @@
 			&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
 }
 
+static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) {
+	return m_calloc(items, size);
+}
+
+static void dropbear_zfree(void* UNUSED(opaque), void* ptr) {
+	m_free(ptr);
+}
+
 /* Set up new zlib compression streams, close the old ones. Only
  * called from gen_new_keys() */
 static void gen_new_zstream_recv() {
@@ -399,8 +406,8 @@
 	if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
 			|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
 		ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
-		ses.newkeys->recv.zstream->zalloc = Z_NULL;
-		ses.newkeys->recv.zstream->zfree = Z_NULL;
+		ses.newkeys->recv.zstream->zalloc = dropbear_zalloc;
+		ses.newkeys->recv.zstream->zfree = dropbear_zfree;
 		
 		if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
 			dropbear_exit("zlib error");
@@ -423,8 +430,8 @@
 	if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
 			|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
 		ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
-		ses.newkeys->trans.zstream->zalloc = Z_NULL;
-		ses.newkeys->trans.zstream->zfree = Z_NULL;
+		ses.newkeys->trans.zstream->zalloc = dropbear_zalloc;
+		ses.newkeys->trans.zstream->zfree = dropbear_zfree;
 	
 		if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
 					Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS, 
@@ -761,8 +768,7 @@
 #endif /* DROPBEAR_CURVE25519 */
 
 
-
-static void finish_kexhashbuf(void) {
+void finish_kexhashbuf(void) {
 	hash_state hs;
 	const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
 
@@ -943,6 +949,12 @@
 		ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
 	}
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		fuzz_kex_fakealgos();
+	}
+#endif
+
 	/* reserved for future extensions */
 	buf_getint(ses.payload);
 
--- a/common-session.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/common-session.c	Wed Feb 28 21:28:59 2018 +0800
@@ -75,14 +75,18 @@
 	ses.last_packet_time_any_sent = 0;
 	ses.last_packet_time_keepalive_sent = 0;
 	
+#ifdef DROPBEAR_FUZZ
+	if (!fuzz.fuzzing)
+#endif
+	{
 	if (pipe(ses.signal_pipe) < 0) {
 		dropbear_exit("Signal pipe failed");
 	}
 	setnonblocking(ses.signal_pipe[0]);
 	setnonblocking(ses.signal_pipe[1]);
-
 	ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
 	ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
+	}
 	
 	ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
 	ses.transseq = 0;
@@ -154,7 +158,12 @@
 
 		/* We get woken up when signal handlers write to this pipe.
 		   SIGCHLD in svr-chansession is the only one currently. */
+#ifdef DROPBEAR_FUZZ
+		if (!fuzz.fuzzing) 
+#endif
+		{
 		FD_SET(ses.signal_pipe[0], &readfd);
+		}
 
 		/* set up for channels which can be read/written */
 		setchannelfds(&readfd, &writefd, writequeue_has_space);
@@ -298,6 +307,16 @@
 		buf_free(dequeue(&ses.writequeue));
 	}
 
+	m_free(ses.newkeys);
+#ifndef DISABLE_ZLIB
+	if (ses.keys->recv.zstream != NULL) {
+		if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
+			dropbear_exit("Crypto error");
+		}
+		m_free(ses.keys->recv.zstream);
+	}
+#endif
+
 	m_free(ses.remoteident);
 	m_free(ses.authstate.pw_dir);
 	m_free(ses.authstate.pw_name);
--- a/configure.ac	Tue Feb 27 22:49:06 2018 +0800
+++ b/configure.ac	Wed Feb 28 21:28:59 2018 +0800
@@ -9,6 +9,12 @@
 AC_INIT
 AC_CONFIG_SRCDIR(buffer.c)
 
+# Record which revision is being built
+if which -s hg && test -d "$srcdir/.hg"; then
+	hgrev=`hg id -i -R "$srcdir"`
+	echo "Source directory Mercurial base revision $hgrev"
+fi
+
 # Checks for programs.
 AC_PROG_CC
 
@@ -315,7 +321,20 @@
 		AC_MSG_NOTICE(Using shadow passwords if available)
 	]
 )
-			
+
+AC_ARG_ENABLE(fuzz,
+	[  --enable-fuzz           Build fuzzing],
+	[
+		AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
+		AC_MSG_NOTICE(Enabling fuzzing)
+		DROPBEAR_FUZZ=1
+	],
+	[
+		DROPBEAR_FUZZ=0
+	]
+
+)
+AC_SUBST(DROPBEAR_FUZZ)
 
 # Checks for header files.
 AC_HEADER_STDC
--- a/dbhelpers.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/dbhelpers.c	Wed Feb 28 21:28:59 2018 +0800
@@ -9,16 +9,8 @@
 #elif defined(HAVE_EXPLICIT_BZERO)
 	explicit_bzero(data, len);
 #else
-/* Based on the method in David Wheeler's
- * "Secure Programming for Linux and Unix HOWTO". May not be safe
- * against link-time optimisation. */
-	volatile char *p = data;
-
-	if (data == NULL)
-		return;
-	while (len--) {
-		*p++ = 0x0;
-	}
+	volatile void *p = data;
+    memset(p, 0x0, len);
 #endif
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbmalloc.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,144 @@
+#include "dbmalloc.h"
+#include "dbutil.h"
+
+struct dbmalloc_header {
+    unsigned int epoch;
+    struct dbmalloc_header *prev;
+    struct dbmalloc_header *next;
+};
+
+static void put_alloc(struct dbmalloc_header *header);
+static void remove_alloc(struct dbmalloc_header *header);
+
+/* end of the linked list */
+static struct dbmalloc_header* staple;
+
+unsigned int current_epoch = 0;
+
+void m_malloc_set_epoch(unsigned int epoch) {
+    current_epoch = epoch;
+}
+
+void m_malloc_free_epoch(unsigned int epoch, int dofree) {
+    struct dbmalloc_header* header;
+    struct dbmalloc_header* nextheader = NULL;
+    struct dbmalloc_header* oldstaple = staple;
+    staple = NULL;
+    /* free allocations from this epoch, create a new staple-anchored list from
+    the remainder */
+    for (header = oldstaple; header; header = nextheader)
+    {
+        nextheader = header->next;
+        if (header->epoch == epoch) {
+            if (dofree) {
+                free(header);
+            }
+        } else {
+            header->prev = NULL;
+            header->next = NULL;
+            put_alloc(header);
+        }
+    }
+}
+
+static void put_alloc(struct dbmalloc_header *header) {
+    assert(header->next == NULL);
+    assert(header->prev == NULL);
+    if (staple) {
+        staple->prev = header;
+    }
+    header->next = staple;
+    staple = header;
+}
+
+static void remove_alloc(struct dbmalloc_header *header) {
+    if (header->prev) {
+        header->prev->next = header->next;
+    }
+    if (header->next) {
+        header->next->prev = header->prev;
+    }
+    if (staple == header) {
+        staple = header->next;
+    }
+    header->prev = NULL;
+    header->next = NULL;
+}
+
+static struct dbmalloc_header* get_header(void* ptr) {
+    char* bptr = ptr;
+    return (struct dbmalloc_header*)&bptr[-sizeof(struct dbmalloc_header)];
+}
+
+void * m_malloc(size_t size) {
+    char* mem = NULL;
+    struct dbmalloc_header* header = NULL;
+
+    if (size == 0 || size > 1e9) {
+        dropbear_exit("m_malloc failed");
+    }
+
+    size = size + sizeof(struct dbmalloc_header);
+
+    mem = calloc(1, size);
+    if (mem == NULL) {
+        dropbear_exit("m_malloc failed");
+    }
+    header = (struct dbmalloc_header*)mem;
+    put_alloc(header);
+    header->epoch = current_epoch;
+    return &mem[sizeof(struct dbmalloc_header)];
+}
+
+void * m_calloc(size_t nmemb, size_t size) {
+    if (SIZE_T_MAX / nmemb < size) {
+        dropbear_exit("m_calloc failed");
+    }
+    return m_malloc(nmemb*size);
+}
+
+void * m_realloc(void* ptr, size_t size) {
+    char* mem = NULL;
+    struct dbmalloc_header* header = NULL;
+    if (size == 0 || size > 1e9) {
+        dropbear_exit("m_realloc failed");
+    }
+
+    header = get_header(ptr);
+    remove_alloc(header);
+
+    size = size + sizeof(struct dbmalloc_header);
+    mem = realloc(header, size);
+    if (mem == NULL) {
+        dropbear_exit("m_realloc failed");
+    }
+
+    header = (struct dbmalloc_header*)mem;
+    put_alloc(header);
+    return &mem[sizeof(struct dbmalloc_header)];
+}
+
+void m_free_direct(void* ptr) {
+    struct dbmalloc_header* header = NULL;
+    if (!ptr) {
+        return;
+    }
+    header = get_header(ptr);
+    remove_alloc(header);
+    free(header);
+}
+
+void * m_strdup(const char * str) {
+    char* ret;
+    unsigned int len;
+    len = strlen(str);
+
+    ret = m_malloc(len+1);
+    if (ret == NULL) {
+        dropbear_exit("m_strdup failed");
+    }
+    memcpy(ret, str, len+1);
+    return ret;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbmalloc.h	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,16 @@
+#ifndef DBMALLOC_H_
+#define DBMALLOC_H_
+
+#include "includes.h"
+
+void * m_malloc(size_t size);
+void * m_calloc(size_t nmemb, size_t size);
+void * m_strdup(const char * str);
+void * m_realloc(void* ptr, size_t size);
+void m_free_direct(void* ptr);
+#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
+
+void m_malloc_set_epoch(unsigned int epoch);
+void m_malloc_free_epoch(unsigned int epoch, int dofree);
+
+#endif /* DBMALLOC_H_ */
--- a/dbrandom.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/dbrandom.c	Wed Feb 28 21:28:59 2018 +0800
@@ -27,7 +27,7 @@
 #include "dbutil.h"
 #include "bignum.h"
 #include "dbrandom.h"
-
+#include "runopts.h"
 
 /* this is used to generate unique output from the same hashpool */
 static uint32_t counter = 0;
@@ -145,6 +145,12 @@
 {
 	hash_state hs;
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing || fuzz.recordf) {
+		return;
+	}
+#endif
+
 	/* hash in the new seed data */
 	sha1_init(&hs);
 	/* existing state (zeroes on startup) */
@@ -157,6 +163,11 @@
 
 static void write_urandom()
 {
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing || fuzz.recordf) {
+		return;
+	}
+#endif
 #if !DROPBEAR_USE_PRNGD
 	/* This is opportunistic, don't worry about failure */
 	unsigned char buf[INIT_SEED_SIZE];
@@ -170,6 +181,18 @@
 #endif
 }
 
+#ifdef DROPBEAR_FUZZ
+void fuzz_seed(void) {
+	hash_state hs;
+	sha1_init(&hs);
+	sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
+	sha1_done(&hs, hashpool);
+
+	counter = 0;
+	donerandinit = 1;
+}
+#endif
+
 /* Initialise the prng from /dev/urandom or prngd. This function can
  * be called multiple times */
 void seedrandom() {
@@ -180,8 +203,15 @@
 	struct timeval tv;
 	clock_t clockval;
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing || fuzz.recordf) {
+		return;
+	}
+#endif
+
 	/* hash in the new seed data */
 	sha1_init(&hs);
+
 	/* existing state */
 	sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
 
--- a/dbutil.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/dbutil.c	Wed Feb 28 21:28:59 2018 +0800
@@ -120,6 +120,13 @@
 
 	_dropbear_log(LOG_INFO, fmtbuf, param);
 
+#ifdef DROPBEAR_FUZZ
+	// longjmp before cleaning up svr_opts
+    if (fuzz.do_jmp) {
+        longjmp(fuzz.jmp, 1);
+    }
+#endif
+
 	exit(exitcode);
 }
 
@@ -392,6 +399,7 @@
 void printmpint(const char *label, mp_int *mp) {
 	buffer *buf = buf_new(1000);
 	buf_putmpint(buf, mp);
+	fprintf(stderr, "%d bits ", mp_count_bits(mp));
 	printhex(label, buf->data, buf->len);
 	buf_free(buf);
 
@@ -520,57 +528,26 @@
 	}
 }
 	
-void * m_malloc(size_t size) {
-
-	void* ret;
-
-	if (size == 0) {
-		dropbear_exit("m_malloc failed");
-	}
-	ret = calloc(1, size);
-	if (ret == NULL) {
-		dropbear_exit("m_malloc failed");
-	}
-	return ret;
-
-}
-
-void * m_strdup(const char * str) {
-	char* ret;
-
-	ret = strdup(str);
-	if (ret == NULL) {
-		dropbear_exit("m_strdup failed");
-	}
-	return ret;
-}
-
-void * m_realloc(void* ptr, size_t size) {
-
-	void *ret;
-
-	if (size == 0) {
-		dropbear_exit("m_realloc failed");
-	}
-	ret = realloc(ptr, size);
-	if (ret == NULL) {
-		dropbear_exit("m_realloc failed");
-	}
-	return ret;
-}
-
 void setnonblocking(int fd) {
 
 	TRACE(("setnonblocking: %d", fd))
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		return;
+	}
+#endif
+
 	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
 		if (errno == ENODEV) {
 			/* Some devices (like /dev/null redirected in)
 			 * can't be set to non-blocking */
 			TRACE(("ignoring ENODEV for setnonblocking"))
 		} else {
+		{
 			dropbear_exit("Couldn't set nonblocking");
 		}
+		}
 	}
 	TRACE(("leave setnonblocking"))
 }
@@ -652,7 +629,14 @@
 #endif 
 
 time_t monotonic_now() {
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		/* time stands still when fuzzing */
+		return 5;
+	}
+#endif
 #if defined(__linux__) && defined(SYS_clock_gettime)
+	{
 	static clockid_t clock_source = -2;
 
 	if (clock_source == -2) {
@@ -669,9 +653,11 @@
 		}
 		return ts.tv_sec;
 	}
+	}
 #endif /* linux clock_gettime */
 
 #if defined(HAVE_MACH_ABSOLUTE_TIME)
+	{
 	/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
 	static mach_timebase_info_data_t timebase_info;
 	if (timebase_info.denom == 0) {
@@ -679,6 +665,7 @@
 	}
 	return mach_absolute_time() * timebase_info.numer / timebase_info.denom
 		/ 1e9;
+	}
 #endif /* osx mach_absolute_time */
 
 	/* Fallback for everything else - this will sometimes go backwards */
--- a/dbutil.h	Tue Feb 27 22:49:06 2018 +0800
+++ b/dbutil.h	Wed Feb 28 21:28:59 2018 +0800
@@ -30,6 +30,7 @@
 #include "buffer.h"
 #include "queue.h"
 #include "dbhelpers.h"
+#include "dbmalloc.h"
 
 #ifndef DISABLE_SYSLOG
 void startsyslog(const char *ident);
@@ -66,10 +67,6 @@
 int buf_getline(buffer * line, FILE * authfile);
 
 void m_close(int fd);
-void * m_malloc(size_t size);
-void * m_strdup(const char * str);
-void * m_realloc(void* ptr, size_t size);
-#define m_free(X) do {free(X); (X) = NULL;} while (0)
 void setnonblocking(int fd);
 void disallow_core(void);
 int m_str_to_uint(const char* str, unsigned int *val);
--- a/debug.h	Tue Feb 27 22:49:06 2018 +0800
+++ b/debug.h	Wed Feb 28 21:28:59 2018 +0800
@@ -39,7 +39,9 @@
 /*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
 		ses.writepayload->pos == 0)*/
 
+#ifndef CHECKCLEARTOWRITE
 #define CHECKCLEARTOWRITE()
+#endif
 
 /* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
  * output when Dropbear forks. This will allow it gprof to be used.
@@ -54,6 +56,7 @@
 
 /* you don't need to touch this block */
 #if DEBUG_TRACE
+extern int debug_trace;
 #define TRACE(X) dropbear_trace X;
 #define TRACE2(X) dropbear_trace2 X;
 #else /*DEBUG_TRACE*/
--- a/dss.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/dss.c	Wed Feb 28 21:28:59 2018 +0800
@@ -73,6 +73,18 @@
 		goto out;
 	}
 
+	/* test 1 < g < p */
+	if (mp_cmp_d(key->g, 1) != MP_GT) {
+		dropbear_log(LOG_WARNING, "Bad DSS g");
+		ret = DROPBEAR_FAILURE;
+		goto out;
+	}
+	if (mp_cmp(key->g, key->p) != MP_LT) {
+		dropbear_log(LOG_WARNING, "Bad DSS g");
+		ret = DROPBEAR_FAILURE;
+		goto out;
+	}
+
 	ret = DROPBEAR_SUCCESS;
 	TRACE(("leave buf_get_dss_pub_key: success"))
 out:
@@ -172,6 +184,13 @@
 		goto out;
 	}
 
+#if DEBUG_DSS_VERIFY
+	printmpint("dss verify p", key->p);
+	printmpint("dss verify q", key->q);
+	printmpint("dss verify g", key->g);
+	printmpint("dss verify y", key->y);
+#endif
+
 	/* hash the data */
 	sha1_init(&hs);
 	sha1_process(&hs, data_buf->data, data_buf->len);
@@ -181,6 +200,9 @@
 	/* w = (s')-1 mod q */
 	/* let val1 = s' */
 	bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
+#if DEBUG_DSS_VERIFY
+	printmpint("dss verify s'", &val1);
+#endif
 
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, s' >= q"))
@@ -198,6 +220,9 @@
 	/* u1 = ((SHA(M')w) mod q */
 	/* let val1 = SHA(M') = msghash */
 	bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
+#if DEBUG_DSS_VERIFY
+	printmpint("dss verify r'", &val1);
+#endif
 
 	/* let val3 = u1 = ((SHA(M')w) mod q */
 	if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz-common.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,188 @@
+#include "includes.h"
+
+#include "includes.h"
+#include "fuzz.h"
+#include "dbutil.h"
+#include "runopts.h"
+#include "crypto_desc.h"
+#include "session.h"
+#include "dbrandom.h"
+#include "bignum.h"
+#include "fuzz-wrapfd.h"
+
+struct dropbear_fuzz_options fuzz;
+
+static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
+static void load_fixed_hostkeys(void);
+
+void fuzz_common_setup(void) {
+    fuzz.fuzzing = 1;
+    fuzz.wrapfds = 1;
+    fuzz.do_jmp = 1;
+    fuzz.input = m_malloc(sizeof(buffer));
+    _dropbear_log = fuzz_dropbear_log;
+    crypto_init();
+    /* let any messages get flushed */
+    setlinebuf(stdout);
+}
+
+int fuzz_set_input(const uint8_t *Data, size_t Size) {
+
+    fuzz.input->data = (unsigned char*)Data;
+    fuzz.input->size = Size;
+    fuzz.input->len = Size;
+    fuzz.input->pos = 0;
+
+    memset(&ses, 0x0, sizeof(ses));
+    memset(&svr_ses, 0x0, sizeof(svr_ses));
+    wrapfd_setup();
+
+    fuzz_seed();
+
+    return DROPBEAR_SUCCESS;
+}
+
+static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
+
+    char printbuf[1024];
+
+#if DEBUG_TRACE
+    if (debug_trace) {
+        vsnprintf(printbuf, sizeof(printbuf), format, param);
+        fprintf(stderr, "%s\n", printbuf);
+    }
+#endif
+}
+
+void fuzz_svr_setup(void) {
+    struct passwd *pw;
+
+    fuzz_common_setup();
+    
+    _dropbear_exit = svr_dropbear_exit;
+
+    char *argv[] = { 
+        "-E", 
+    };
+
+    int argc = sizeof(argv) / sizeof(*argv);
+    svr_getopts(argc, argv);
+
+    /* user lookups might be slow, cache it */
+    fuzz.pw_name = m_strdup("person");
+    fuzz.pw_dir = m_strdup("/tmp");
+    fuzz.pw_shell = m_strdup("/bin/zsh");
+    fuzz.pw_passwd = m_strdup("!!zzznope");
+
+    load_fixed_hostkeys();
+}
+
+static void load_fixed_hostkeys(void) {
+#include "fuzz-hostkeys.c"   
+
+    buffer *b = buf_new(3000);
+    enum signkey_type type;
+
+    TRACE(("load fixed hostkeys"))
+
+    svr_opts.hostkey = new_sign_key();
+
+    buf_setlen(b, 0);
+    buf_putbytes(b, keyr, keyr_len);
+    buf_setpos(b, 0);
+    type = DROPBEAR_SIGNKEY_RSA;
+    if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+        dropbear_exit("failed fixed rsa hostkey");
+    }
+
+    buf_setlen(b, 0);
+    buf_putbytes(b, keyd, keyd_len);
+    buf_setpos(b, 0);
+    type = DROPBEAR_SIGNKEY_DSS;
+    if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+        dropbear_exit("failed fixed dss hostkey");
+    }
+
+    buf_setlen(b, 0);
+    buf_putbytes(b, keye, keye_len);
+    buf_setpos(b, 0);
+    type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+    if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+        dropbear_exit("failed fixed ecdsa hostkey");
+    }
+
+    buf_free(b);
+}
+
+void fuzz_kex_fakealgos(void) {
+    ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
+}
+
+void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
+                        char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
+    if (local_host) {
+        *local_host = m_strdup("fuzzlocalhost");
+    }
+    if (local_port) {
+        *local_port = m_strdup("1234");
+    }
+    if (remote_host) {
+        *remote_host = m_strdup("fuzzremotehost");
+    }
+    if (remote_port) {
+        *remote_port = m_strdup("9876");
+    }
+}
+
+/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
+void fuzz_fake_send_kexdh_reply(void) {
+    assert(!ses.dh_K);
+    m_mp_alloc_init_multi(&ses.dh_K, NULL);
+    mp_set_int(ses.dh_K, 12345678);
+    finish_kexhashbuf();
+}
+
+int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
+    static int once = 0;
+    if (!once) {
+        fuzz_svr_setup();
+        fuzz.skip_kexmaths = skip_kexmaths;
+        once = 1;
+    }
+
+    if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+        return 0;
+    }
+
+    // get prefix. input format is
+    // string prefix
+    //     uint32 wrapfd seed
+    //     ... to be extended later
+    // [bytes] ssh input stream
+
+    // be careful to avoid triggering buffer.c assertions
+    if (fuzz.input->len < 8) {
+        return 0;
+    }
+    size_t prefix_size = buf_getint(fuzz.input);
+    if (prefix_size != 4) {
+        return 0;
+    }
+    uint32_t wrapseed = buf_getint(fuzz.input);
+    wrapfd_setseed(wrapseed);
+
+    int fakesock = 20;
+    wrapfd_add(fakesock, fuzz.input, PLAIN);
+
+    m_malloc_set_epoch(1);
+    if (setjmp(fuzz.jmp) == 0) {
+        svr_session(fakesock, fakesock);
+        m_malloc_free_epoch(1, 0);
+    } else {
+        m_malloc_free_epoch(1, 1);
+        TRACE(("dropbear_exit longjmped"))
+        // dropbear_exit jumped here
+    }
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz-harness.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,41 @@
+#include "includes.h"
+#include "buffer.h"
+#include "dbutil.h"
+
+extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
+
+int main(int argc, char ** argv) {
+    int i;
+    buffer *input = buf_new(100000);
+
+    for (i = 1; i < argc; i++) {
+#if DEBUG_TRACE
+        if (strcmp(argv[i], "-v") == 0) {
+            debug_trace = 1;
+            TRACE(("debug printing on"))
+        }
+#endif
+    }
+
+    for (i = 1; i < argc; i++) {
+        if (argv[i][0] == '-') {
+            // ignore arguments
+            continue;
+        }
+
+        char* fn = argv[i];
+        buf_setlen(input, 0);
+        buf_readfile(input, fn);
+        buf_setpos(input, 0);
+
+        printf("Running %s once \n", fn);
+        LLVMFuzzerTestOneInput(input->data, input->len);
+        printf("Running %s twice \n", fn);
+        LLVMFuzzerTestOneInput(input->data, input->len);
+        printf("Done %s\n", fn);
+    }
+
+    printf("Finished\n");
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz-hostkeys.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,129 @@
+
+unsigned char keyr[] = {
+  0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
+  0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
+  0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
+  0xfa, 0xa4, 0x49, 0xf8, 0x2a, 0x4c, 0x14, 0xbd, 0xb6, 0x85, 0xdb, 0x38,
+  0x99, 0x44, 0xfa, 0xd6, 0xaa, 0x67, 0xef, 0x00, 0x75, 0x2b, 0x6a, 0x5c,
+  0x1b, 0x50, 0xa8, 0x52, 0xf9, 0xa7, 0xee, 0xe2, 0xb3, 0x80, 0x38, 0x92,
+  0x20, 0x86, 0x7c, 0xe5, 0x89, 0xb3, 0x06, 0xe4, 0x3b, 0xd1, 0xe2, 0x45,
+  0xea, 0xc1, 0xd5, 0x8e, 0x05, 0xfb, 0x90, 0x29, 0xd9, 0x41, 0xb3, 0x05,
+  0x31, 0x1e, 0xcc, 0xeb, 0x89, 0xdc, 0xd2, 0x6a, 0x99, 0x23, 0xbd, 0x7a,
+  0xbe, 0x8c, 0xe3, 0x3f, 0xa1, 0xe8, 0xf5, 0xb4, 0x51, 0x40, 0xb4, 0xb1,
+  0xc1, 0x16, 0x9f, 0x07, 0xbb, 0x99, 0xaa, 0x4b, 0x8f, 0x11, 0x19, 0x3c,
+  0x18, 0xbd, 0x6e, 0xce, 0x14, 0x54, 0x2c, 0x16, 0x4a, 0x5f, 0x89, 0xe4,
+  0x6b, 0x9f, 0x55, 0x68, 0xcc, 0x09, 0x8e, 0x4b, 0x92, 0xc8, 0x87, 0xfe,
+  0x09, 0xed, 0x53, 0x6e, 0xff, 0x5f, 0x15, 0x0d, 0x19, 0x9d, 0xa6, 0x54,
+  0xd2, 0xea, 0x59, 0x4f, 0xa1, 0x7c, 0xf6, 0xf5, 0x7f, 0x32, 0x23, 0xed,
+  0x72, 0xa8, 0x96, 0x17, 0x87, 0x06, 0xf2, 0xc7, 0xcd, 0xda, 0x4a, 0x10,
+  0xd1, 0xfd, 0xb8, 0xf1, 0xaf, 0x25, 0x55, 0x32, 0x45, 0x39, 0x95, 0xec,
+  0x0c, 0xa9, 0xf0, 0x47, 0x8b, 0x66, 0xe0, 0xb7, 0xa2, 0xf6, 0x35, 0x50,
+  0x27, 0xe7, 0x2f, 0x90, 0x35, 0x5b, 0xd5, 0x62, 0x19, 0xb4, 0x41, 0xd4,
+  0x52, 0xe7, 0x7f, 0x97, 0xfc, 0x5b, 0x4a, 0x5b, 0x19, 0x06, 0x65, 0x2d,
+  0x23, 0x29, 0x15, 0x8b, 0x05, 0xaf, 0xbe, 0xd3, 0x4a, 0x27, 0x5b, 0xc9,
+  0xc0, 0xd0, 0xd2, 0xba, 0x8b, 0x00, 0x7a, 0x2f, 0x39, 0xa0, 0x13, 0xb9,
+  0xe6, 0xf5, 0x4b, 0x21, 0x54, 0x57, 0xb3, 0xf9, 0x6c, 0x6f, 0xd0, 0x17,
+  0xf4, 0x50, 0x9d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xf2, 0xda, 0x5f, 0xfb,
+  0xe2, 0xda, 0xfc, 0xe0, 0xdf, 0x3a, 0x0e, 0x14, 0x18, 0xc1, 0xd9, 0x1f,
+  0x43, 0xe3, 0x65, 0x3e, 0x07, 0xe7, 0x8d, 0xdc, 0x1d, 0x11, 0xc1, 0xd6,
+  0xc0, 0xd8, 0xda, 0x53, 0xf5, 0x04, 0x73, 0x51, 0x1b, 0x26, 0xef, 0x4e,
+  0xf5, 0xce, 0x3d, 0x77, 0x21, 0x94, 0xd0, 0xc7, 0xc1, 0xda, 0x19, 0x7d,
+  0xf8, 0xc5, 0x4c, 0xc8, 0xee, 0x7d, 0xd1, 0xbb, 0x02, 0x90, 0x2b, 0xff,
+  0x4e, 0x4d, 0xd7, 0x9d, 0x72, 0x0c, 0x60, 0x0f, 0x4b, 0x83, 0xf5, 0xc2,
+  0x26, 0xd6, 0x22, 0xb8, 0x60, 0x3a, 0xf9, 0x2f, 0x92, 0x2a, 0x2e, 0x14,
+  0xa7, 0x56, 0x1c, 0x56, 0x05, 0x41, 0x92, 0xac, 0xb1, 0x4e, 0x44, 0x1e,
+  0x70, 0x42, 0xda, 0xc7, 0xc8, 0x9c, 0xae, 0x29, 0x2d, 0x0c, 0x3a, 0xff,
+  0x9b, 0xb6, 0xad, 0xb4, 0xfb, 0x49, 0x28, 0x96, 0x74, 0xf5, 0x94, 0x74,
+  0xb7, 0x40, 0x93, 0x2b, 0x34, 0x29, 0xd2, 0x8a, 0xf3, 0x99, 0xf9, 0xe9,
+  0xd8, 0xcc, 0x48, 0x1d, 0x3e, 0xc1, 0x82, 0x35, 0x4f, 0xef, 0xb1, 0x81,
+  0x3c, 0xe1, 0xa1, 0x03, 0x65, 0xac, 0x21, 0x21, 0x40, 0x61, 0xfb, 0xd3,
+  0x54, 0xac, 0xa1, 0xf2, 0xf0, 0x61, 0xd9, 0x01, 0x4e, 0xc2, 0x28, 0xb1,
+  0x7c, 0x27, 0x6e, 0x56, 0x68, 0x69, 0x8f, 0xc5, 0xfd, 0xca, 0x39, 0x6e,
+  0x22, 0x09, 0xf1, 0xb4, 0xd5, 0xac, 0xb8, 0xe0, 0x1b, 0x21, 0x86, 0xf4,
+  0xc8, 0x15, 0xc6, 0x1f, 0x21, 0xae, 0xcb, 0xab, 0x5a, 0x09, 0x30, 0x9e,
+  0xdd, 0x6c, 0x38, 0x59, 0xec, 0x59, 0x3a, 0x08, 0xee, 0x46, 0x7b, 0x78,
+  0x23, 0xbc, 0xfc, 0xe2, 0xda, 0xe8, 0x1a, 0x65, 0xe6, 0xe0, 0x78, 0xd3,
+  0xb0, 0x03, 0x2e, 0xf1, 0xb8, 0xca, 0x8e, 0x90, 0x75, 0xaf, 0xf7, 0xa8,
+  0x48, 0xed, 0x82, 0xc9, 0xcf, 0x44, 0x56, 0xfc, 0x05, 0xfd, 0x6b, 0x00,
+  0x00, 0x00, 0x81, 0x00, 0xfc, 0x94, 0xdf, 0x42, 0xc7, 0x9a, 0xa2, 0xff,
+  0x32, 0xdf, 0x06, 0xb6, 0x4d, 0x90, 0x31, 0x28, 0x28, 0xdb, 0x03, 0xf9,
+  0xa6, 0xb3, 0xa2, 0x91, 0x4c, 0xdf, 0x6e, 0xf6, 0xb9, 0x44, 0x3b, 0xdd,
+  0x17, 0xc1, 0xc8, 0x1d, 0xd1, 0xc0, 0xc0, 0x30, 0x22, 0xbe, 0x24, 0x2e,
+  0x0e, 0xdf, 0xe0, 0x18, 0x37, 0x3e, 0xb8, 0x7f, 0xb2, 0x50, 0x34, 0xc4,
+  0x08, 0x5e, 0x69, 0x1f, 0xd5, 0xc9, 0xce, 0x47, 0x7d, 0x75, 0x5e, 0x3b,
+  0x87, 0xdd, 0x46, 0x35, 0x01, 0x0f, 0x17, 0x8a, 0xf1, 0xf1, 0xc4, 0xa9,
+  0x94, 0xa7, 0x6e, 0xce, 0x80, 0xe3, 0x17, 0x2e, 0xb0, 0xef, 0x63, 0xa7,
+  0x11, 0x86, 0x96, 0x4a, 0x63, 0x2d, 0x9e, 0x92, 0x62, 0x43, 0x43, 0x72,
+  0xa5, 0xdc, 0xa0, 0xcd, 0x19, 0x93, 0xd7, 0xe0, 0x80, 0x41, 0x27, 0xea,
+  0xe4, 0xe8, 0xc1, 0x91, 0x9e, 0x13, 0xb3, 0x9c, 0xd1, 0xed, 0xcb, 0xbf,
+  0x00, 0x00, 0x00, 0x81, 0x00, 0xb3, 0x6b, 0xee, 0xa4, 0x70, 0x4e, 0xfb,
+  0xf9, 0x7e, 0x2e, 0x74, 0x5d, 0x3e, 0x8b, 0x3f, 0xff, 0x8c, 0xde, 0x68,
+  0x38, 0xda, 0xce, 0xc0, 0x66, 0x4b, 0xca, 0x35, 0xc3, 0x97, 0xa8, 0xf0,
+  0x00, 0x8e, 0xb3, 0x46, 0x60, 0xd0, 0x4d, 0x7e, 0x7b, 0xdf, 0x17, 0x7b,
+  0x2f, 0xc4, 0x16, 0xee, 0x45, 0xdb, 0xa5, 0x5d, 0xc0, 0x72, 0xe9, 0xc6,
+  0x91, 0x0f, 0xd9, 0x30, 0x74, 0x6c, 0xde, 0x93, 0xb5, 0xb6, 0xaf, 0x52,
+  0x53, 0x3c, 0x08, 0x55, 0xea, 0xb8, 0x66, 0x07, 0xbe, 0xce, 0xf9, 0x80,
+  0x8d, 0xe0, 0xca, 0xdc, 0x63, 0xe8, 0x58, 0x94, 0x22, 0x4f, 0x08, 0x66,
+  0x13, 0x9e, 0x63, 0x2e, 0x92, 0x7a, 0xb6, 0x66, 0x94, 0x9b, 0x71, 0x66,
+  0xd3, 0x08, 0xc9, 0x89, 0xea, 0x78, 0x35, 0x0d, 0xf2, 0x25, 0x55, 0xd4,
+  0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
+  0xa3
+};
+unsigned int keyr_len = 805;
+unsigned char keye[] = {
+  0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
+  0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
+  0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
+  0x00, 0x00, 0x41, 0x04, 0x0a, 0x00, 0x6c, 0x7c, 0x1c, 0xc4, 0x03, 0x44,
+  0x46, 0x70, 0xba, 0x00, 0x7c, 0x79, 0x89, 0x7b, 0xc3, 0xd6, 0x32, 0x98,
+  0x34, 0xe7, 0x1c, 0x60, 0x04, 0x73, 0xd9, 0xb5, 0x7e, 0x94, 0x04, 0x04,
+  0xea, 0xc8, 0xb8, 0xfb, 0xd4, 0x70, 0x9f, 0x29, 0xa7, 0x8d, 0x9a, 0x64,
+  0x3a, 0x8c, 0x45, 0x23, 0x37, 0x5a, 0x2b, 0x4f, 0x54, 0x91, 0x80, 0xf1,
+  0xac, 0x3a, 0xf5, 0x6d, 0xfa, 0xe8, 0x76, 0x20, 0x00, 0x00, 0x00, 0x21,
+  0x00, 0xc2, 0xaf, 0xbe, 0xdc, 0x06, 0xff, 0x3d, 0x08, 0x9b, 0x73, 0xe0,
+  0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
+  0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
+};
+unsigned int keye_len = 141;
+unsigned char keyd[] = {
+  0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x64, 0x73, 0x73, 0x00,
+  0x00, 0x00, 0x81, 0x00, 0xb0, 0x02, 0x19, 0x8b, 0xf3, 0x46, 0xf9, 0xc5,
+  0x47, 0x78, 0x3d, 0x7f, 0x04, 0x10, 0x0a, 0x43, 0x8e, 0x00, 0x9e, 0xa4,
+  0x30, 0xfd, 0x47, 0xb9, 0x05, 0x9e, 0x95, 0xaa, 0x37, 0x9a, 0x91, 0xbf,
+  0xf8, 0xb9, 0xe0, 0x8d, 0x97, 0x49, 0x87, 0xe2, 0xe6, 0x90, 0xc1, 0xe4,
+  0x61, 0x57, 0x77, 0xfd, 0x91, 0x1d, 0xe1, 0x4b, 0xa0, 0xb2, 0xbc, 0xa1,
+  0x6a, 0x6a, 0xdd, 0x31, 0xda, 0xe7, 0x54, 0x03, 0xfd, 0x48, 0x62, 0x8a,
+  0x1d, 0x1d, 0xe2, 0x26, 0x76, 0x29, 0x08, 0xab, 0x65, 0x88, 0x74, 0x02,
+  0x1e, 0xa9, 0x29, 0x1b, 0x69, 0x3b, 0xb4, 0x5f, 0x62, 0x80, 0xa3, 0xa6,
+  0x4b, 0xc3, 0x0e, 0x89, 0x24, 0xe4, 0x8a, 0x31, 0xae, 0x89, 0x7a, 0x7a,
+  0x58, 0x44, 0x46, 0x77, 0x62, 0x33, 0xa2, 0x5d, 0x17, 0x0e, 0x0b, 0x64,
+  0xee, 0x1a, 0x02, 0xbd, 0xf8, 0x27, 0x86, 0xe1, 0x87, 0x92, 0x84, 0xc7,
+  0x00, 0x00, 0x00, 0x15, 0x00, 0xb3, 0x8b, 0x81, 0x39, 0x9c, 0xba, 0xe1,
+  0x1d, 0x9a, 0x8b, 0x89, 0xb3, 0x08, 0x9b, 0x12, 0xa8, 0x7b, 0xea, 0x25,
+  0x8d, 0x00, 0x00, 0x00, 0x80, 0x76, 0x3f, 0x72, 0xb2, 0xef, 0xc3, 0x16,
+  0xd8, 0x09, 0x36, 0x23, 0x03, 0xf9, 0x5c, 0xac, 0x8b, 0x51, 0x35, 0x2e,
+  0x36, 0xba, 0x39, 0xd0, 0x57, 0x19, 0x4f, 0x14, 0x8b, 0xea, 0x32, 0xfc,
+  0x86, 0x41, 0xea, 0x85, 0x71, 0x4d, 0x52, 0x0c, 0xff, 0xc1, 0xd3, 0xd5,
+  0xcd, 0x2e, 0x37, 0xcc, 0xe1, 0xcc, 0x22, 0x38, 0xa8, 0x47, 0x16, 0x34,
+  0x3b, 0x32, 0x9c, 0x2f, 0x0f, 0xcd, 0x5f, 0x7f, 0x06, 0x64, 0x89, 0xc5,
+  0x02, 0x4f, 0x9a, 0x70, 0x11, 0xf0, 0xaa, 0xe1, 0x7a, 0x75, 0x49, 0x8d,
+  0x0f, 0x8d, 0x5b, 0x54, 0xe2, 0xe7, 0x10, 0x6e, 0xe5, 0xbd, 0xb7, 0x62,
+  0xf7, 0x40, 0x59, 0x39, 0x31, 0xd9, 0x13, 0x7b, 0xa3, 0xdf, 0x0d, 0x31,
+  0x52, 0x43, 0xe0, 0xaf, 0x19, 0x12, 0x15, 0x12, 0x34, 0x01, 0x6f, 0xcf,
+  0x62, 0x21, 0xe4, 0xc8, 0x34, 0x69, 0xc9, 0x85, 0xe3, 0xde, 0xd7, 0x0c,
+  0xac, 0x00, 0x00, 0x00, 0x80, 0x41, 0xa3, 0xc5, 0xa4, 0x89, 0x86, 0xc8,
+  0x17, 0xf3, 0x8e, 0x68, 0x72, 0xbe, 0x13, 0x8b, 0x63, 0xe3, 0x07, 0xe3,
+  0xd5, 0xa4, 0xa2, 0xd3, 0x2c, 0x2f, 0xbe, 0x16, 0x71, 0xc9, 0x79, 0x64,
+  0x5a, 0x1e, 0x19, 0x82, 0x07, 0xe2, 0x93, 0xda, 0x22, 0xcf, 0x6d, 0xdd,
+  0x38, 0xcb, 0x6e, 0x6b, 0x0f, 0x95, 0x8d, 0xfa, 0x3f, 0xbb, 0xb8, 0x6a,
+  0x7d, 0xc3, 0x22, 0x1e, 0x49, 0xcf, 0x98, 0x73, 0x05, 0x5d, 0x97, 0xfa,
+  0x4c, 0xf2, 0x82, 0x3d, 0x98, 0x61, 0x4e, 0x96, 0x80, 0x26, 0x79, 0xda,
+  0x24, 0xf8, 0xa1, 0x9c, 0x71, 0x82, 0xe6, 0xc7, 0xdc, 0xc2, 0xa5, 0xd0,
+  0xf4, 0x36, 0xba, 0xaa, 0xee, 0xd3, 0x43, 0x46, 0x1d, 0xaa, 0x53, 0xea,
+  0x85, 0x2c, 0x1b, 0xc8, 0x7c, 0x3c, 0xe7, 0x06, 0x44, 0xab, 0x16, 0xad,
+  0xc6, 0x54, 0x91, 0x9a, 0xb9, 0xc0, 0xeb, 0x93, 0x8c, 0xca, 0x39, 0xcf,
+  0x6f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x90, 0x26, 0x0a, 0xfc, 0x15, 0x99,
+  0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
+  0xf9, 0x39
+};
+unsigned int keyd_len = 458;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz-wrapfd.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,244 @@
+#define FUZZ_SKIP_WRAP 1
+#include "includes.h"
+#include "fuzz-wrapfd.h"
+
+#include "fuzz.h"
+
+#define IOWRAP_MAXFD (FD_SETSIZE-1)
+static const int MAX_RANDOM_IN = 50000;
+static const double CHANCE_CLOSE = 1.0 / 300;
+static const double CHANCE_INTR = 1.0 / 200;
+static const double CHANCE_READ1 = 0.6;
+static const double CHANCE_READ2 = 0.3;
+static const double CHANCE_WRITE1 = 0.8;
+static const double CHANCE_WRITE2 = 0.3;
+
+struct fdwrap {
+	enum wrapfd_mode mode;
+	buffer *buf;
+	int closein;
+	int closeout;
+};
+
+static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
+// for quick selection of in-use descriptors
+static int wrap_used[IOWRAP_MAXFD+1];
+static unsigned int nused;
+static unsigned short rand_state[3];
+
+void wrapfd_setup() {
+	TRACE(("wrapfd_setup"))
+	nused = 0;
+	memset(wrap_fds, 0x0, sizeof(wrap_fds));
+	memset(wrap_used, 0x0, sizeof(wrap_used));
+
+	memset(rand_state, 0x0, sizeof(rand_state));
+	wrapfd_setseed(50);
+}
+
+void wrapfd_setseed(uint32_t seed) {
+	memcpy(rand_state, &seed, sizeof(seed));
+	nrand48(rand_state);
+}
+
+void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
+	TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
+	assert(fd >= 0);
+	assert(fd <= IOWRAP_MAXFD);
+	assert(wrap_fds[fd].mode == UNUSED);
+	assert(buf || mode == RANDOMIN);
+
+	wrap_fds[fd].mode = mode;
+	wrap_fds[fd].buf = buf;
+	wrap_fds[fd].closein = 0;
+	wrap_fds[fd].closeout = 0;
+	wrap_used[nused] = fd;
+
+	nused++;
+}
+
+void wrapfd_remove(int fd) {
+	unsigned int i, j;
+	TRACE(("wrapfd_remove %d", fd))
+	assert(fd >= 0);
+	assert(fd <= IOWRAP_MAXFD);
+	assert(wrap_fds[fd].mode != UNUSED);
+	wrap_fds[fd].mode = UNUSED;
+
+
+	// remove from used list
+	for (i = 0, j = 0; i < nused; i++) {
+		if (wrap_used[i] != fd) {
+			wrap_used[j] = wrap_used[i];
+			j++;
+		}
+	}
+	nused--;
+}
+
+int wrapfd_close(int fd) {
+	if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
+		wrapfd_remove(fd);
+		return 0;
+	} else {
+		return close(fd);
+	}
+}
+
+int wrapfd_read(int fd, void *out, size_t count) {
+	size_t maxread;
+	buffer *buf;
+
+	if (!fuzz.wrapfds) {
+		return read(fd, out, count);
+	}
+
+	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
+		// XXX - assertion failure?
+		TRACE(("Bad read descriptor %d\n", fd))
+		errno = EBADF;
+		return -1;
+	}
+
+	assert(count != 0);
+
+	if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
+		wrap_fds[fd].closein = 1;
+		errno = ECONNRESET;
+		return -1;
+	}
+
+	if (erand48(rand_state) < CHANCE_INTR) {
+		errno = EINTR;
+		return -1;
+	}
+
+	buf = wrap_fds[fd].buf;
+	if (buf) {
+		maxread = MIN(buf->len - buf->pos, count);
+		// returns 0 if buf is EOF, as intended
+		if (maxread > 0) {
+			maxread = nrand48(rand_state) % maxread + 1;
+		}
+		memcpy(out, buf_getptr(buf, maxread), maxread);
+		buf_incrpos(buf, maxread);
+		return maxread;
+	}
+
+	maxread = MIN(MAX_RANDOM_IN, count);
+	maxread = nrand48(rand_state) % maxread + 1;
+	memset(out, 0xef, maxread);
+	return maxread;
+}
+
+int wrapfd_write(int fd, const void* in, size_t count) {
+	unsigned const volatile char* volin = in;
+	unsigned int i;
+
+	if (!fuzz.wrapfds) {
+		return write(fd, in, count);
+	}
+
+	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
+		// XXX - assertion failure?
+		TRACE(("Bad read descriptor %d\n", fd))
+		errno = EBADF;
+		return -1;
+	}
+
+	assert(count != 0);
+
+	// force read to exercise sanitisers
+	for (i = 0; i < count; i++) {
+		(void)volin[i];
+	}
+
+	if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
+		wrap_fds[fd].closeout = 1;
+		errno = ECONNRESET;
+		return -1;
+	}
+
+	if (erand48(rand_state) < CHANCE_INTR) {
+		errno = EINTR;
+		return -1;
+	}
+
+	return nrand48(rand_state) % (count+1);
+}
+
+int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, 
+	fd_set *exceptfds, struct timeval *timeout) {
+	int i, nset, sel;
+	int ret = 0;
+	int fdlist[IOWRAP_MAXFD+1];
+
+	memset(fdlist, 0x0, sizeof(fdlist));
+
+	if (!fuzz.wrapfds) {
+		return select(nfds, readfds, writefds, exceptfds, timeout);
+	}
+
+	assert(nfds <= IOWRAP_MAXFD+1);
+
+	if (erand48(rand_state) < CHANCE_INTR) {
+		errno = EINTR;
+		return -1;
+	}
+
+	// read
+	if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
+		for (i = 0, nset = 0; i < nfds; i++) {
+			if (FD_ISSET(i, readfds)) {
+				assert(wrap_fds[i].mode != UNUSED);
+				fdlist[nset] = i;
+				nset++;
+			}
+		}
+		FD_ZERO(readfds);
+
+		if (nset > 0) {
+			// set one
+			sel = fdlist[nrand48(rand_state) % nset];
+			FD_SET(sel, readfds);
+			ret++;
+
+			if (erand48(rand_state) < CHANCE_READ2) {
+				sel = fdlist[nrand48(rand_state) % nset];
+				if (!FD_ISSET(sel, readfds)) {
+					FD_SET(sel, readfds);
+					ret++;
+				}
+			}
+		}
+	}
+
+	// write
+	if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
+		for (i = 0, nset = 0; i < nfds; i++) {
+			if (FD_ISSET(i, writefds)) {
+				assert(wrap_fds[i].mode != UNUSED);
+				fdlist[nset] = i;
+				nset++;
+			}
+		}
+		FD_ZERO(writefds);
+
+		// set one
+		if (nset > 0) {
+			sel = fdlist[nrand48(rand_state) % nset];
+			FD_SET(sel, writefds);
+			ret++;
+
+			if (erand48(rand_state) < CHANCE_WRITE2) {
+				sel = fdlist[nrand48(rand_state) % nset];
+				if (!FD_ISSET(sel, writefds)) {
+					FD_SET(sel, writefds);
+					ret++;
+				}
+			}
+		}
+	}
+	return ret;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz-wrapfd.h	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,25 @@
+#ifndef FUZZ_WRAPFD_H
+#define FUZZ_WRAPFD_H
+
+#include "buffer.h"
+
+enum wrapfd_mode {
+    UNUSED = 0,
+    PLAIN,
+    INPROGRESS,
+    RANDOMIN,
+};
+
+void wrapfd_setup();
+void wrapfd_setseed(uint32_t seed);
+// doesn't take ownership of buf. buf is optional.
+void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
+
+// called via #defines for read/write/select
+int wrapfd_read(int fd, void *out, size_t count);
+int wrapfd_write(int fd, const void* in, size_t count);
+int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, 
+    fd_set *exceptfds, struct timeval *timeout);
+int wrapfd_close(int fd);
+
+#endif // FUZZ_WRAPFD_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz.h	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,73 @@
+#ifndef DROPBEAR_FUZZ_H
+#define DROPBEAR_FUZZ_H
+
+#include "config.h"
+#ifdef DROPBEAR_FUZZ
+
+#include "includes.h"
+#include "buffer.h"
+#include "algo.h"
+#include "fuzz-wrapfd.h"
+
+// once per process
+void fuzz_common_setup(void);
+void fuzz_svr_setup(void);
+
+// must be called once per fuzz iteration. 
+// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
+int fuzz_set_input(const uint8_t *Data, size_t Size);
+
+int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths);
+
+// fuzzer functions that intrude into general code
+void fuzz_kex_fakealgos(void);
+int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
+        const char* algo, unsigned int algolen,
+        const unsigned char* keyblob, unsigned int keybloblen);
+extern const char * const * fuzz_signkey_names;
+void fuzz_seed(void);
+void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
+                        char **remote_host, char **remote_port, int host_lookup);
+void fuzz_fake_send_kexdh_reply(void);
+
+// fake IO wrappers
+#ifndef FUZZ_SKIP_WRAP
+#define select(nfds, readfds, writefds, exceptfds, timeout) \
+        wrapfd_select(nfds, readfds, writefds, exceptfds, timeout)
+#define write(fd, buf, count) wrapfd_write(fd, buf, count)
+#define read(fd, buf, count) wrapfd_read(fd, buf, count)
+#define close(fd) wrapfd_close(fd)
+#endif // FUZZ_SKIP_WRAP
+
+struct dropbear_fuzz_options {
+    int fuzzing;
+
+    // to record an unencrypted stream
+    FILE* recordf;
+
+    // fuzzing input
+    buffer *input;
+    struct dropbear_cipher recv_cipher;
+    struct dropbear_hash recv_mac;
+    int wrapfds;
+
+    // whether to skip slow bignum maths
+    int skip_kexmaths;
+
+    // dropbear_exit() jumps back
+    int do_jmp;
+    sigjmp_buf jmp;
+
+    uid_t pw_uid;
+    gid_t pw_gid;
+    char* pw_name;
+    char* pw_dir;
+    char* pw_shell;
+    char* pw_passwd;
+};
+
+extern struct dropbear_fuzz_options fuzz;
+
+#endif // DROPBEAR_FUZZ
+
+#endif /* DROPBEAR_FUZZ_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzzer-preauth.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	return fuzz_run_preauth(Data, Size, 0);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzzer-preauth_nomaths.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	return fuzz_run_preauth(Data, Size, 1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzzer-pubkey.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,44 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+
+static void setup_fuzzer(void) {
+	fuzz_common_setup();
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	static int once = 0;
+	if (!once) {
+		setup_fuzzer();
+		once = 1;
+	}
+
+	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+		return 0;
+	}
+
+	m_malloc_set_epoch(1);
+
+	// choose a keytype based on input
+	uint8_t b = 0;
+	size_t i;
+	for (i = 0; i < Size; i++) {
+		b ^= Data[i];
+	}
+	const char* algoname = fuzz_signkey_names[b%DROPBEAR_SIGNKEY_NUM_NAMED];
+	const char* keyblob = "blob"; // keep short
+
+	if (setjmp(fuzz.jmp) == 0) {
+		fuzz_checkpubkey_line(fuzz.input, 5, "/home/me/authorized_keys", 
+			algoname, strlen(algoname),
+			(unsigned char*)keyblob, strlen(keyblob));
+		m_malloc_free_epoch(1, 0);
+	} else {
+		m_malloc_free_epoch(1, 1);
+		TRACE(("dropbear_exit longjmped"))
+		// dropbear_exit jumped here
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzzer-verify.c	Wed Feb 28 21:28:59 2018 +0800
@@ -0,0 +1,64 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+
+static void setup_fuzzer(void) {
+	fuzz_common_setup();
+}
+
+static buffer *verifydata;
+
+/* Tests reading a public key and verifying a signature */
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	static int once = 0;
+	if (!once) {
+		setup_fuzzer();
+		verifydata = buf_new(30);
+		buf_putstring(verifydata, "x", 1);
+		once = 1;
+	}
+
+	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+		return 0;
+	}
+
+	m_malloc_set_epoch(1);
+
+	if (setjmp(fuzz.jmp) == 0) {
+		sign_key *key = new_sign_key();
+		enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
+		if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) {
+			if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) {
+				/* The fuzzer is capable of generating keys with a signature to match.
+				We don't want false positives if the key is bogus, since a client/server 
+				wouldn't be trusting a bogus key anyway */
+				int boguskey = 0;
+
+				if (type == DROPBEAR_SIGNKEY_DSS) {
+					/* So far have seen dss keys with bad p/q/g domain parameters */
+					int pprime, qprime;
+				    assert(mp_prime_is_prime(key->dsskey->p, 5, &pprime) == MP_OKAY);
+				    assert(mp_prime_is_prime(key->dsskey->q, 18, &qprime) == MP_OKAY);
+				    boguskey = !(pprime && qprime);
+				    /* Could also check g**q mod p == 1 */
+				}
+
+				if (!boguskey) {
+					printf("Random key/signature managed to verify!\n");
+					abort();
+				}
+
+
+			}
+		}
+		sign_key_free(key);
+		m_malloc_free_epoch(1, 0);
+	} else {
+		m_malloc_free_epoch(1, 1);
+		TRACE(("dropbear_exit longjmped"))
+		// dropbear_exit jumped here
+	}
+
+	return 0;
+}
--- a/includes.h	Tue Feb 27 22:49:06 2018 +0800
+++ b/includes.h	Wed Feb 28 21:28:59 2018 +0800
@@ -56,6 +56,7 @@
 #include <stdarg.h>
 #include <dirent.h>
 #include <time.h>
+#include <setjmp.h>
 
 #ifdef HAVE_UTMP_H
 #include <utmp.h>
@@ -131,7 +132,6 @@
 #include <tommath.h>
 #endif
 
-
 #include "compat.h"
 
 #ifndef HAVE_U_INT8_T
@@ -155,6 +155,10 @@
 typedef u_int32_t uint32_t;
 #endif /* HAVE_UINT32_T */
 
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ULONG_MAX
+#endif /* SIZE_T_MAX */
+
 #ifdef HAVE_LINUX_PKT_SCHED_H
 #include <linux/types.h>
 #include <linux/pkt_sched.h>
@@ -162,6 +166,8 @@
 
 #include "fake-rfc2553.h"
 
+#include "fuzz.h"
+
 #ifndef LOG_AUTHPRIV
 #define LOG_AUTHPRIV LOG_AUTH
 #endif
--- a/kex.h	Tue Feb 27 22:49:06 2018 +0800
+++ b/kex.h	Wed Feb 28 21:28:59 2018 +0800
@@ -34,6 +34,7 @@
 void send_msg_newkeys(void);
 void recv_msg_newkeys(void);
 void kexfirstinitialise(void);
+void finish_kexhashbuf(void);
 
 struct kex_dh_param *gen_kexdh_param(void);
 void free_kexdh_param(struct kex_dh_param *param);
--- a/libtomcrypt/src/headers/tomcrypt_custom.h	Tue Feb 27 22:49:06 2018 +0800
+++ b/libtomcrypt/src/headers/tomcrypt_custom.h	Wed Feb 28 21:28:59 2018 +0800
@@ -12,6 +12,17 @@
 
 #include "tomcrypt_dropbear.h"
 
+void * m_malloc(size_t size);
+/* m_calloc is limited in size, enough for libtomcrypt */
+void * m_calloc(size_t nmemb, size_t size);
+void * m_realloc(void* ptr, size_t size);
+void m_free_direct(void* ptr);
+
+#define XMALLOC m_malloc
+#define XFREE m_free_direct
+#define XREALLOC m_realloc
+#define XCALLOC m_calloc
+
 /* macros for various libc functions you can change for embedded targets */
 #ifndef XMALLOC
 #define XMALLOC  malloc
--- a/libtommath/tommath_class.h	Tue Feb 27 22:49:06 2018 +0800
+++ b/libtommath/tommath_class.h	Wed Feb 28 21:28:59 2018 +0800
@@ -1062,6 +1062,17 @@
 #undef BN_MP_TOOM_MUL_C
 #undef BN_MP_TOOM_SQR_C
 
+void * m_malloc(size_t size);
+/* m_calloc is limited in size, enough for libtomcrypt */
+void * m_calloc(size_t nmemb, size_t size);
+void * m_realloc(void* ptr, size_t size);
+void m_free_direct(void* ptr);
+
+#define XMALLOC m_malloc
+#define XFREE m_free_direct
+#define XREALLOC m_realloc
+#define XCALLOC m_calloc
+
 /* $Source$ */
 /* $Revision$ */
 /* $Date$ */
--- a/netio.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/netio.c	Wed Feb 28 21:28:59 2018 +0800
@@ -245,6 +245,7 @@
 		}
 		iter = next_iter;
 	}
+	TRACE(("leave set_connect_fds"))
 }
 
 void handle_connect_fds(const fd_set *writefd) {
@@ -360,6 +361,12 @@
 	int so_prio_val = 0;
 #endif
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		TRACE(("fuzzing skips set_sock_prio"))
+		return;
+	}
+#endif
 
 	/* Don't log ENOTSOCK errors so that this can harmlessly be called
 	 * on a client '-J' proxy pipe */
@@ -584,6 +591,13 @@
 {
 	struct sockaddr_storage addr;
 	socklen_t addrlen;
+
+#if DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		fuzz_get_socket_address(fd, local_host, local_port, remote_host, remote_port, host_lookup);
+		return;
+	}
+#endif
 	
 	if (local_host || local_port) {
 		addrlen = sizeof(addr);
--- a/packet.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/packet.c	Wed Feb 28 21:28:59 2018 +0800
@@ -35,6 +35,7 @@
 #include "auth.h"
 #include "channel.h"
 #include "netio.h"
+#include "runopts.h"
 
 static int read_packet_init(void);
 static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
@@ -76,6 +77,15 @@
 	/* This may return EAGAIN. The main loop sometimes
 	calls write_packet() without bothering to test with select() since
 	it's likely to be necessary */
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		// pretend to write one packet at a time
+		// TODO(fuzz): randomise amount written based on the fuzz input
+		written = iov[0].iov_len;
+	}
+	else
+#endif
+	{
 	written = writev(ses.sock_out, iov, iov_count);
 	if (written < 0) {
 		if (errno == EINTR || errno == EAGAIN) {
@@ -85,6 +95,7 @@
 			dropbear_exit("Error writing: %s", strerror(errno));
 		}
 	}
+	}
 
 	packet_queue_consume(&ses.writequeue, written);
 	ses.writequeue_len -= written;
@@ -94,6 +105,9 @@
 	}
 
 #else /* No writev () */
+#ifdef DROPBEAR_FUZZ
+	_Static_assert(0, "No fuzzing code for no-writev writes");
+#endif
 	/* Get the next buffer in the queue of encrypted packets to write*/
 	writebuf = (buffer*)examine(&ses.writequeue);
 
@@ -352,6 +366,18 @@
 	buf_setpos(ses.readbuf, 0);
 	make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		// fail 1 in 2000 times to test error path.
+		// note that mac_bytes is all zero prior to kex, so don't test ==0 !
+		unsigned int value = *((unsigned int*)&mac_bytes);
+		if (value % 2000 == 99) {
+			return DROPBEAR_FAILURE;
+		}
+		return DROPBEAR_SUCCESS;
+	}
+#endif
+
 	/* compare the hash */
 	buf_setpos(ses.readbuf, contents_len);
 	if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
--- a/signkey.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/signkey.c	Wed Feb 28 21:28:59 2018 +0800
@@ -580,6 +580,10 @@
 
 	/* now we have the actual data */
 	len = line->len - line->pos;
+	if (len == 0) {
+		/* base64_decode doesn't like NULL argument */
+		return DROPBEAR_FAILURE;
+	}
 	decodekeylen = len * 2; /* big to be safe */
 	decodekey = buf_new(decodekeylen);
 
@@ -623,3 +627,8 @@
 	return ret;
 }
 #endif
+
+#ifdef DROPBEAR_FUZZ
+const char * const * fuzz_signkey_names = signkey_names;
+
+#endif
--- a/svr-auth.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/svr-auth.c	Wed Feb 28 21:28:59 2018 +0800
@@ -395,7 +395,13 @@
 		genrandom((unsigned char*)&delay, sizeof(delay));
 		/* We delay for 300ms +- 50ms */
 		delay = 250000 + (delay % 100000);
+#ifdef DROPBEAR_FUZZ
+		if (!fuzz.fuzzing) {
+			usleep(delay);
+		}
+#else
 		usleep(delay);
+#endif
 		ses.authstate.failcount++;
 	}
 
--- a/svr-authpubkey.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/svr-authpubkey.c	Wed Feb 28 21:28:59 2018 +0800
@@ -473,4 +473,12 @@
 	return DROPBEAR_SUCCESS;
 }
 
+#ifdef DROPBEAR_FUZZ
+int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
+		const char* algo, unsigned int algolen,
+		const unsigned char* keyblob, unsigned int keybloblen) {
+	return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen);
+}
 #endif
+
+#endif
--- a/svr-kex.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/svr-kex.c	Wed Feb 28 21:28:59 2018 +0800
@@ -179,6 +179,13 @@
 	}
 #endif
 
+#ifdef DROPBEAR_FUZZ
+	if (fuzz.fuzzing && fuzz.skip_kexmaths) {
+		fuzz_fake_send_kexdh_reply();
+		return;
+	}
+#endif
+
 	buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
 	buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
 			ses.newkeys->algo_hostkey);
--- a/svr-runopts.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/svr-runopts.c	Wed Feb 28 21:28:59 2018 +0800
@@ -523,6 +523,7 @@
 	svr_opts.num_hostkey_files++;
 }
 
+
 void load_all_hostkeys() {
 	int i;
 	int disable_unset_keys = 1;
--- a/svr-session.c	Tue Feb 27 22:49:06 2018 +0800
+++ b/svr-session.c	Wed Feb 28 21:28:59 2018 +0800
@@ -40,6 +40,7 @@
 #include "auth.h"
 #include "runopts.h"
 #include "crypto_desc.h"
+#include "fuzz.h"
 
 static void svr_remoteclosed(void);
 static void svr_algos_initialise(void);
@@ -184,6 +185,13 @@
 		session_cleanup();
 	}
 
+#ifdef DROPBEAR_FUZZ
+	// longjmp before cleaning up svr_opts
+    if (fuzz.do_jmp) {
+        longjmp(fuzz.jmp, 1);
+    }
+#endif
+
 	if (svr_opts.hostkey) {
 		sign_key_free(svr_opts.hostkey);
 		svr_opts.hostkey = NULL;
@@ -193,6 +201,7 @@
 		m_free(svr_opts.ports[i]);
 	}
 
+    
 	exit(exitcode);
 
 }
@@ -238,7 +247,9 @@
 static void svr_remoteclosed() {
 
 	m_close(ses.sock_in);
-	m_close(ses.sock_out);
+	if (ses.sock_in != ses.sock_out) {
+		m_close(ses.sock_out);
+	}
 	ses.sock_in = -1;
 	ses.sock_out = -1;
 	dropbear_close("Exited normally");