changeset 1769:0e178f767ada

Merge from main
author Matt Johnston <matt@ucc.asn.au>
date Thu, 29 Oct 2020 21:51:41 +0800
parents 096a66e45212 (diff) c05b76c541c9 (current diff)
children 66b29b054896
files
diffstat 35 files changed, 1492 insertions(+), 1173 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Thu Oct 29 21:40:34 2020 +0800
+++ b/Makefile.in	Thu Oct 29 21:51:41 2020 +0800
@@ -62,7 +62,7 @@
 SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
 
 ifeq (@[email protected], 1)
-	allobjs = $(COMMONOBJS) fuzz-common.o  fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @[email protected]
+	allobjs = $(COMMONOBJS) fuzz/fuzz-common.o  fuzz/fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @[email protected]
 	allobjs:=$(subst svr-main.o, ,$(allobjs))
 	allobjs:=$(subst cli-main.o, ,$(allobjs))
 
@@ -72,6 +72,7 @@
 	dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
 	# CXX only set when fuzzing
 	[email protected]@
+	FUZZ_CLEAN=fuzz-clean
 else
 	dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
 	dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
@@ -246,7 +247,7 @@
 sizes: dropbear
 	objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
 
-clean: $(LIBTOM_CLEAN) thisclean
+clean: $(LIBTOM_CLEAN) $(FUZZ_CLEAN) thisclean
 
 thisclean:
 	-rm -f dropbear$(EXEEXT) dbclient$(EXEEXT) dropbearkey$(EXEEXT) \
@@ -268,50 +269,32 @@
 
 # list of fuzz targets
 FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths \
-	fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 fuzzer-client fuzzer-client_nomaths
+	fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 fuzzer-client fuzzer-client_nomaths \
+	fuzzer-client_mutator fuzzer-client_mutator_nomaths
 
 FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
+FUZZ_OBJS = $(addprefix fuzz/,$(addsuffix .o,$(FUZZ_TARGETS))) \
+	fuzz/fuzz-sshpacketmutator.o
 
 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
+fuzzstandalone: FUZZLIB=fuzz/fuzz-harness.o
+fuzzstandalone: fuzz/fuzz-harness.o fuzz-targets
 
-fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(allobjs) fuzz-common.o
-
-# build all the fuzzers. This will require fail to link unless built with
-# make fuzz-targets FUZZLIB=-lFuzzer.a 
-# or similar - the library provides main().
+# Build all the fuzzers. Usually like
+#   make fuzz-targets FUZZLIB=-lFuzzer.a 
+# the library provides main(). Otherwise
+#   make fuzzstandalone
+# provides a main in fuzz-harness.c
 fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
 
-fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-verify: fuzzer-verify.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
+$(FUZZ_TARGETS): $(FUZZ_OBJS) $(allobjs) $(LIBTOM_DEPS) 
+	$(CXX) $(CXXFLAGS) fuzz/[email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) -lcrypt
 
-fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-client: fuzzer-client.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
-
-fuzzer-client_nomaths: fuzzer-client_nomaths.o fuzz-harness.o
-	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(allobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
+# fuzzers that use the custom mutator
+fuzzer-client_mutator fuzzer-client_mutator_nomaths: allobjs += fuzz/fuzz-sshpacketmutator.o
 
 fuzzer-%.options: Makefile
 	echo "[libfuzzer]"               > [email protected]
@@ -329,3 +312,6 @@
 	/usr/bin/xxd -i -a keye >> hostkeys.c
 	/usr/bin/xxd -i -a keyd >> hostkeys.c
 	/usr/bin/xxd -i -a keyed25519 >> hostkeys.c
+
+fuzz-clean:
+	-rm -f fuzz/*.o $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
--- a/buffer.c	Thu Oct 29 21:40:34 2020 +0800
+++ b/buffer.c	Thu Oct 29 21:51:41 2020 +0800
@@ -188,6 +188,7 @@
 unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len) {
 
 	if (len > BUF_MAX_INCR || buf->pos + len > buf->size) {
+		abort();
 		dropbear_exit("Bad buf_getwriteptr");
 	}
 	return &buf->data[buf->pos];
--- a/configure.ac	Thu Oct 29 21:40:34 2020 +0800
+++ b/configure.ac	Thu Oct 29 21:51:41 2020 +0800
@@ -347,6 +347,7 @@
             DROPBEAR_FUZZ=1
             # libfuzzer needs linking with c++ libraries
             AC_PROG_CXX
+			mkdir -pv fuzz
         else
             AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
             AC_MSG_NOTICE(Disabling fuzzing)
--- a/dbrandom.c	Thu Oct 29 21:40:34 2020 +0800
+++ b/dbrandom.c	Thu Oct 29 21:51:41 2020 +0800
@@ -150,10 +150,11 @@
 }
 
 #if DROPBEAR_FUZZ
-void fuzz_seed(void) {
+void fuzz_seed(const unsigned char* dat, unsigned int len) {
 	hash_state hs;
 	sha1_init(&hs);
 	sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
+	sha1_process(&hs, dat, len);
 	sha1_done(&hs, hashpool);
 
 	counter = 0;
--- a/dbutil.c	Thu Oct 29 21:40:34 2020 +0800
+++ b/dbutil.c	Thu Oct 29 21:51:41 2020 +0800
@@ -385,20 +385,37 @@
 
 #if DEBUG_TRACE
 void printhex(const char * label, const unsigned char * buf, int len) {
-
-	int i;
+	int i, j;
 
 	fprintf(stderr, "%s\n", label);
-	for (i = 0; i < len; i++) {
-		fprintf(stderr, "%02x", buf[i]);
-		if (i % 16 == 15) {
-			fprintf(stderr, "\n");
+	/* for each 16 byte line */
+	for (j = 0; j < len; j += 16) {
+		const int linelen = MIN(16, len - j);
+
+		/* print hex digits */
+		for (i = 0; i < 16; i++) {
+			if (i < linelen) {
+				fprintf(stderr, "%02x", buf[j+i]);
+			} else {
+				fprintf(stderr, "  ");
+			}
+			// separator between pairs
+			if (i % 2 ==1) {
+				fprintf(stderr, " ");
+			}
 		}
-		else if (i % 2 == 1) {
-			fprintf(stderr, " ");
+
+		/* print characters */
+		fprintf(stderr, "  ");
+		for (i = 0; i < linelen; i++) {
+			char c = buf[j+i];
+			if (!isprint(c)) {
+				c = '.';
+			}
+			fputc(c, stderr);
 		}
+		fprintf(stderr, "\n");
 	}
-	fprintf(stderr, "\n");
 }
 
 void printmpint(const char *label, mp_int *mp) {
--- a/fuzz-common.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,311 +0,0 @@
-#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 "atomicio.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);
-static void load_fixed_client_key(void);
-
-void fuzz_common_setup(void) {
-	disallow_core();
-    fuzz.fuzzing = 1;
-    fuzz.wrapfds = 1;
-    fuzz.do_jmp = 1;
-    fuzz.input = m_malloc(sizeof(buffer));
-    _dropbear_log = fuzz_dropbear_log;
-    crypto_init();
-    fuzz_seed();
-    /* 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));
-    memset(&cli_ses, 0x0, sizeof(cli_ses));
-    wrapfd_setup(fuzz.input);
-
-    fuzz_seed();
-
-    return DROPBEAR_SUCCESS;
-}
-
-#if DEBUG_TRACE
-static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
-    if (debug_trace) {
-        char printbuf[1024];
-        vsnprintf(printbuf, sizeof(printbuf), format, param);
-        fprintf(stderr, "%s\n", printbuf);
-    }
-}
-#else
-static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
-    /* No print */
-}
-#endif /* DEBUG_TRACE */
-
-void fuzz_svr_setup(void) {
-    fuzz_common_setup();
-    
-    _dropbear_exit = svr_dropbear_exit;
-
-    char *argv[] = { 
-		"dropbear",
-        "-E", 
-    };
-
-    int argc = sizeof(argv) / sizeof(*argv);
-    svr_getopts(argc, argv);
-
-    load_fixed_hostkeys();
-}
-
-void fuzz_cli_setup(void) {
-    fuzz_common_setup();
-    
-	_dropbear_exit = cli_dropbear_exit;
-	_dropbear_log = cli_dropbear_log;
-
-    char *argv[] = { 
-		"dbclient",
-		"-y",
-        "localhost",
-        "uptime"
-    };
-
-    int argc = sizeof(argv) / sizeof(*argv);
-    cli_getopts(argc, argv);
-
-    load_fixed_client_key();
-    /* Avoid password prompt */
-    setenv(DROPBEAR_PASSWORD_ENV, "password", 1);
-}
-
-#include "fuzz-hostkeys.c"   
-
-static void load_fixed_client_key(void) {
-
-    buffer *b = buf_new(3000);
-    sign_key *key;
-    enum signkey_type keytype;
-
-    key = new_sign_key();
-    keytype = DROPBEAR_SIGNKEY_ANY;
-    buf_putbytes(b, keyed25519, keyed25519_len);
-    buf_setpos(b, 0);
-    if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) {
-        dropbear_exit("failed fixed ed25519 hostkey");
-    }
-    list_append(cli_opts.privkeys, key);
-
-    buf_free(b);
-}
-
-static void load_fixed_hostkeys(void) {
-
-    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_setlen(b, 0);
-    buf_putbytes(b, keyed25519, keyed25519_len);
-    buf_setpos(b, 0);
-    type = DROPBEAR_SIGNKEY_ED25519;
-    if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
-        dropbear_exit("failed fixed ed25519 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_ul(ses.dh_K, 12345678uL);
-    finish_kexhashbuf();
-}
-
-/* fake version of spawn_command() */
-int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
-    *ret_writefd = wrapfd_new();
-    *ret_readfd = wrapfd_new();
-    if (ret_errfd) {
-        *ret_errfd = wrapfd_new();
-    }
-    *ret_pid = 999;
-    return DROPBEAR_SUCCESS;
-}
-
-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, allowing for future extensibility. 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 = wrapfd_new();
-
-    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;
-}
-
-int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) {
-    static int once = 0;
-    if (!once) {
-        fuzz_cli_setup();
-        fuzz.skip_kexmaths = skip_kexmaths;
-        once = 1;
-    }
-
-    if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
-        return 0;
-    }
-
-    /*
-      get prefix, allowing for future extensibility. 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 = wrapfd_new();
-
-    m_malloc_set_epoch(1);
-    if (setjmp(fuzz.jmp) == 0) {
-        cli_session(fakesock, fakesock, NULL, 0);
-        m_malloc_free_epoch(1, 0);
-    } else {
-        m_malloc_free_epoch(1, 1);
-        TRACE(("dropbear_exit longjmped"))
-        /* dropbear_exit jumped here */
-    }
-
-    return 0;
-}
-
-const void* fuzz_get_algo(const algo_type *algos, const char* name) {
-    const algo_type *t;
-    for (t = algos; t->name; t++) {
-        if (strcmp(t->name, name) == 0) {
-            return t->data;
-        }
-    }
-    assert(0);
-}
-
-void fuzz_dump(const unsigned char* data, size_t len) {
-    TRACE(("dump %zu", len))
-    if (fuzz.dumping) {
-        assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len);
-    }
-}
--- a/fuzz-harness.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#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
-    }
-
-    int old_fuzz_wrapfds = 0;
-    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);
-
-		/* Run twice to catch problems with statefulness */
-        fuzz.wrapfds = old_fuzz_wrapfds;
-        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);
-
-        /* Disable wrapfd so it won't interfere with buf_readfile() above */
-        old_fuzz_wrapfds = fuzz.wrapfds;
-        fuzz.wrapfds = 0;
-    }
-
-    printf("Finished\n");
-
-    return 0;
-}
--- a/fuzz-hostkeys.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/* To be included in fuzz-common.c */
-
-static 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
-};
-static unsigned int keyr_len = 805;
-static 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
-};
-static unsigned int keye_len = 141;
-static 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
-};
-static unsigned int keyd_len = 458;
-static unsigned char keyed25519[] = {
-  0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
-  0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
-  0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
-  0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
-  0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
-  0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
-  0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
-};
-static unsigned int keyed25519_len = 83;
--- a/fuzz-wrapfd.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-#define FUZZ_SKIP_WRAP 1
-#include "includes.h"
-#include "fuzz-wrapfd.h"
-
-#include "dbutil.h"
-
-#include "fuzz.h"
-
-#define IOWRAP_MAXFD (FD_SETSIZE-1)
-static const int MAX_RANDOM_IN = 50000;
-static const double CHANCE_CLOSE = 1.0 / 600;
-static const double CHANCE_INTR = 1.0 / 900;
-static const double CHANCE_READ1 = 0.96;
-static const double CHANCE_READ2 = 0.5;
-static const double CHANCE_WRITE1 = 0.96;
-static const double CHANCE_WRITE2 = 0.5;
-
-struct fdwrap {
-	enum wrapfd_mode mode;
-	int closein;
-	int closeout;
-};
-
-static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
-static int wrapfd_maxfd = -1;
-static unsigned short rand_state[3];
-static buffer *input_buf;
-static int devnull_fd = -1;
-
-static void wrapfd_remove(int fd);
-
-void wrapfd_setup(buffer *buf) {
-	TRACE(("wrapfd_setup"))
-
-	// clean old ones
-	int i;
-	for (i = 0; i <= wrapfd_maxfd; i++) {
-		if (wrap_fds[i].mode == COMMONBUF) {
-			wrapfd_remove(i);
-		}
-	}
-	wrapfd_maxfd = -1;
-
-	memset(rand_state, 0x0, sizeof(rand_state));
-	wrapfd_setseed(50);
-	input_buf = buf;
-}
-
-void wrapfd_setseed(uint32_t seed) {
-	memcpy(rand_state, &seed, sizeof(seed));
-	nrand48(rand_state);
-}
-
-int wrapfd_new() {
-	if (devnull_fd == -1) {
-		devnull_fd = open("/dev/null", O_RDONLY);
-		assert(devnull_fd != -1);
-	}
-
-	int fd = dup(devnull_fd);
-	assert(fd != -1);
-	assert(wrap_fds[fd].mode == UNUSED);
-	wrap_fds[fd].mode = COMMONBUF;
-	wrap_fds[fd].closein = 0;
-	wrap_fds[fd].closeout = 0;
-	wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
-
-	return fd;
-}
-
-static void wrapfd_remove(int fd) {
-	TRACE(("wrapfd_remove %d", fd))
-	assert(fd >= 0);
-	assert(fd <= IOWRAP_MAXFD);
-	assert(wrap_fds[fd].mode != UNUSED);
-	wrap_fds[fd].mode = UNUSED;
-	m_close(fd);
-}
-
-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;
-
-	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;
-	}
-
-	if (input_buf) {
-		maxread = MIN(input_buf->len - input_buf->pos, count);
-		/* returns 0 if buf is EOF, as intended */
-		if (maxread > 0) {
-			maxread = nrand48(rand_state) % maxread + 1;
-		}
-		memcpy(out, buf_getptr(input_buf, maxread), maxread);
-		buf_incrpos(input_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];
-
-	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++;
-			}
-		}
-		DROPBEAR_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++;
-			}
-		}
-		DROPBEAR_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;
-}
-
--- a/fuzz.h	Thu Oct 29 21:40:34 2020 +0800
+++ b/fuzz.h	Thu Oct 29 21:51:41 2020 +0800
@@ -15,6 +15,10 @@
 void fuzz_svr_setup(void);
 void fuzz_cli_setup(void);
 
+// constructor attribute so it runs before main(), including
+// in non-fuzzing mode.
+void fuzz_early_setup(void) __attribute__((constructor));
+
 // must be called once per fuzz iteration. 
 // returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
 int fuzz_set_input(const uint8_t *Data, size_t Size);
@@ -29,7 +33,7 @@
         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_seed(const unsigned char* dat, unsigned int len);
 
 // helpers
 void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
@@ -68,10 +72,27 @@
     int dumping;
     // the file descriptor
     int recv_dumpfd;
+
+    // avoid filling fuzzing logs, this points to /dev/null
+    FILE *fake_stderr;
 };
 
 extern struct dropbear_fuzz_options fuzz;
 
+/* guard for when fuzz.h is included by fuzz-common.c */
+#ifndef FUZZ_NO_REPLACE_STDERR
+
+/* This is a bodge but seems to work.
+ glibc stdio.h has the comment 
+ "C89/C99 say they're macros.  Make them happy." */
+/* OS X has it as a macro */
+#ifdef stderr
+#undef stderr
+#endif
+#define stderr (fuzz.fake_stderr)
+
+#endif /* FUZZ_NO_REPLACE_STDERR */
+
 #endif // DROPBEAR_FUZZ
 
 #endif /* DROPBEAR_FUZZ_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzz-common.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,345 @@
+#include "includes.h"
+
+#include "includes.h"
+#include "dbutil.h"
+#include "runopts.h"
+#include "crypto_desc.h"
+#include "session.h"
+#include "dbrandom.h"
+#include "bignum.h"
+#include "atomicio.h"
+#include "fuzz-wrapfd.h"
+
+#define FUZZ_NO_REPLACE_STDERR
+#include "fuzz.h"
+
+/* fuzz.h redefines stderr, we don't want that here */
+#ifdef origstderr
+#undef stderr
+#define stderr origstderr
+#endif // origstderr
+
+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);
+static void load_fixed_client_key(void);
+
+// This runs automatically before main, due to contructor attribute in fuzz.h
+void fuzz_early_setup(void) {
+    /* Set stderr to point to normal stderr by default */
+    fuzz.fake_stderr = stderr;
+}
+
+void fuzz_common_setup(void) {
+	disallow_core();
+    fuzz.fuzzing = 1;
+    fuzz.wrapfds = 1;
+    fuzz.do_jmp = 1;
+    fuzz.input = m_malloc(sizeof(buffer));
+    _dropbear_log = fuzz_dropbear_log;
+    crypto_init();
+    fuzz_seed("start", 5);
+    /* let any messages get flushed */
+    setlinebuf(stdout);
+#if DEBUG_TRACE
+    if (debug_trace)
+    {
+        fprintf(stderr, "Dropbear fuzzer: -v specified, not disabling stderr output\n");
+    }
+    else
+#endif
+    if (getenv("DROPBEAR_KEEP_STDERR")) {
+        fprintf(stderr, "Dropbear fuzzer: DROPBEAR_KEEP_STDERR, not disabling stderr output\n");
+    } 
+    else 
+    {
+        fprintf(stderr, "Dropbear fuzzer: Disabling stderr output\n");
+        fuzz.fake_stderr = fopen("/dev/null", "w");
+        assert(fuzz.fake_stderr);
+    }
+}
+
+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));
+    memset(&cli_ses, 0x0, sizeof(cli_ses));
+    wrapfd_setup(fuzz.input);
+
+    fuzz_seed(fuzz.input->data, MIN(fuzz.input->len, 16));
+
+    return DROPBEAR_SUCCESS;
+}
+
+#if DEBUG_TRACE
+static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
+    if (debug_trace) {
+        char printbuf[1024];
+        vsnprintf(printbuf, sizeof(printbuf), format, param);
+        fprintf(stderr, "%s\n", printbuf);
+    }
+}
+#else
+static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
+    /* No print */
+}
+#endif /* DEBUG_TRACE */
+
+void fuzz_svr_setup(void) {
+    fuzz_common_setup();
+    
+    _dropbear_exit = svr_dropbear_exit;
+
+    char *argv[] = { 
+		"dropbear",
+        "-E", 
+    };
+
+    int argc = sizeof(argv) / sizeof(*argv);
+    svr_getopts(argc, argv);
+
+    load_fixed_hostkeys();
+}
+
+void fuzz_cli_setup(void) {
+    fuzz_common_setup();
+    
+	_dropbear_exit = cli_dropbear_exit;
+	_dropbear_log = cli_dropbear_log;
+
+    char *argv[] = { 
+		"dbclient",
+		"-y",
+        "localhost",
+        "uptime"
+    };
+
+    int argc = sizeof(argv) / sizeof(*argv);
+    cli_getopts(argc, argv);
+
+    load_fixed_client_key();
+    /* Avoid password prompt */
+    setenv(DROPBEAR_PASSWORD_ENV, "password", 1);
+}
+
+#include "fuzz-hostkeys.c"   
+
+static void load_fixed_client_key(void) {
+
+    buffer *b = buf_new(3000);
+    sign_key *key;
+    enum signkey_type keytype;
+
+    key = new_sign_key();
+    keytype = DROPBEAR_SIGNKEY_ANY;
+    buf_putbytes(b, keyed25519, keyed25519_len);
+    buf_setpos(b, 0);
+    if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) {
+        dropbear_exit("failed fixed ed25519 hostkey");
+    }
+    list_append(cli_opts.privkeys, key);
+
+    buf_free(b);
+}
+
+static void load_fixed_hostkeys(void) {
+
+    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_setlen(b, 0);
+    buf_putbytes(b, keyed25519, keyed25519_len);
+    buf_setpos(b, 0);
+    type = DROPBEAR_SIGNKEY_ED25519;
+    if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+        dropbear_exit("failed fixed ed25519 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_ul(ses.dh_K, 12345678uL);
+    finish_kexhashbuf();
+}
+
+/* fake version of spawn_command() */
+int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
+    *ret_writefd = wrapfd_new();
+    *ret_readfd = wrapfd_new();
+    if (ret_errfd) {
+        *ret_errfd = wrapfd_new();
+    }
+    *ret_pid = 999;
+    return DROPBEAR_SUCCESS;
+}
+
+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, allowing for future extensibility. 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 = wrapfd_new();
+
+    m_malloc_set_epoch(1);
+    fuzz.do_jmp = 1;
+    if (setjmp(fuzz.jmp) == 0) {
+        svr_session(fakesock, fakesock);
+        m_malloc_free_epoch(1, 0);
+    } else {
+        fuzz.do_jmp = 0;
+        m_malloc_free_epoch(1, 1);
+        TRACE(("dropbear_exit longjmped"))
+        /* dropbear_exit jumped here */
+    }
+
+    return 0;
+}
+
+int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) {
+    static int once = 0;
+    if (!once) {
+        fuzz_cli_setup();
+        fuzz.skip_kexmaths = skip_kexmaths;
+        once = 1;
+    }
+
+    if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+        return 0;
+    }
+
+    /*
+      get prefix, allowing for future extensibility. 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 = wrapfd_new();
+
+    m_malloc_set_epoch(1);
+    fuzz.do_jmp = 1;
+    if (setjmp(fuzz.jmp) == 0) {
+        cli_session(fakesock, fakesock, NULL, 0);
+        m_malloc_free_epoch(1, 0);
+    } else {
+        fuzz.do_jmp = 0;
+        m_malloc_free_epoch(1, 1);
+        TRACE(("dropbear_exit longjmped"))
+        /* dropbear_exit jumped here */
+    }
+
+    return 0;
+}
+
+const void* fuzz_get_algo(const algo_type *algos, const char* name) {
+    const algo_type *t;
+    for (t = algos; t->name; t++) {
+        if (strcmp(t->name, name) == 0) {
+            return t->data;
+        }
+    }
+    assert(0);
+}
+
+void fuzz_dump(const unsigned char* data, size_t len) {
+    TRACE(("dump %zu", len))
+    if (fuzz.dumping) {
+        assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzz-harness.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,54 @@
+#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
+    }
+
+    int old_fuzz_wrapfds = 0;
+    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);
+
+		/* Run twice to catch problems with statefulness */
+        fuzz.wrapfds = old_fuzz_wrapfds;
+        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);
+
+        /* Disable wrapfd so it won't interfere with buf_readfile() above */
+        old_fuzz_wrapfds = fuzz.wrapfds;
+        fuzz.wrapfds = 0;
+    }
+
+    printf("Finished\n");
+
+    return 0;
+}
+
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+    printf("standalone fuzzer harness shouldn't call LLVMFuzzerMutate");
+    abort();
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzz-hostkeys.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,140 @@
+/* To be included in fuzz-common.c */
+
+static 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
+};
+static unsigned int keyr_len = 805;
+static 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
+};
+static unsigned int keye_len = 141;
+static 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
+};
+static unsigned int keyd_len = 458;
+static unsigned char keyed25519[] = {
+  0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
+  0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
+  0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
+  0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
+  0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
+  0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
+  0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
+};
+static unsigned int keyed25519_len = 83;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzz-sshpacketmutator.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,240 @@
+#include "fuzz.h"
+#include "dbutil.h"
+
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+/* out_packets an array of num_out_packets*buffer, each of size RECV_MAX_PACKET_LEN */
+static void fuzz_get_packets(buffer *inp, buffer **out_packets, unsigned int *num_out_packets) {
+    /* Skip any existing banner. Format is
+          SSH-protoversion-softwareversion SP comments CR LF
+    so we look for SSH-2. then a subsequent LF */
+    unsigned char* version = memmem(inp->data, inp->len, "SSH-2.", strlen("SSH-2."));
+    if (version) {
+        buf_incrpos(inp, version - inp->data);
+        unsigned char* newline = memchr(&inp->data[inp->pos], '\n', inp->len - inp->pos);
+        if (newline) {
+            buf_incrpos(inp, newline - &inp->data[inp->pos]+1);
+        } else {
+            /* Give up on any version string */
+            buf_setpos(inp, 0);
+        }
+    }
+
+    const unsigned int max_out_packets = *num_out_packets;
+    *num_out_packets = 0;
+    while (1) {
+        if (inp->pos + 4 > inp->len) {
+            /* End of input */
+            break;
+        }
+
+        if (*num_out_packets >= max_out_packets) {
+            /* End of output */
+            break;
+        }
+
+        /* Read packet */
+        unsigned int packet_len = buf_getint(inp);
+        if (packet_len > RECV_MAX_PACKET_LEN-4) {
+            /* Bad length, try skipping a single byte */
+            buf_decrpos(inp, 3);
+            continue;
+        }
+        packet_len = MIN(packet_len, inp->len - inp->pos);
+
+        /* Copy to output buffer. We're reusing buffers */
+        buffer* new_packet = out_packets[*num_out_packets];
+        (*num_out_packets)++;
+        buf_setlen(new_packet, 0);
+        buf_putint(new_packet, packet_len);
+        buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len);
+        buf_incrpos(inp, packet_len);
+    }
+}
+
+/* Mutate in-place */
+void buf_llvm_mutate(buffer *buf) {
+    /* Position it after packet_length and padding_length */
+    const unsigned int offset = 5;
+    if (buf->len < offset) {
+        return;
+    }
+    buf_setpos(buf, offset);
+    size_t max_size = buf->size - buf->pos;
+    size_t new_size = LLVMFuzzerMutate(buf_getwriteptr(buf, max_size),
+        buf->len - buf->pos, max_size);
+    buf_setpos(buf, 0);
+    buf_putint(buf, new_size);
+    buf_setlen(buf, offset + new_size);
+}
+
+
+static const char* FIXED_VERSION = "SSH-2.0-dbfuzz\r\n";
+static const size_t MAX_FUZZ_PACKETS = 500;
+/* XXX This might need tuning */
+static const size_t MAX_OUT_SIZE = 50000;
+
+/* Persistent buffers to avoid constant allocations */
+static buffer *oup;
+static buffer *alloc_packetA;
+static buffer *alloc_packetB;
+buffer* packets1[MAX_FUZZ_PACKETS];
+buffer* packets2[MAX_FUZZ_PACKETS];
+
+/* Allocate buffers once at startup.
+   'constructor' here so it runs before dbmalloc's interceptor */
+static void alloc_static_buffers() __attribute__((constructor));
+static void alloc_static_buffers() {
+
+    int i;
+    oup = buf_new(MAX_OUT_SIZE);
+    alloc_packetA = buf_new(RECV_MAX_PACKET_LEN);
+    alloc_packetB = buf_new(RECV_MAX_PACKET_LEN);
+
+    for (i = 0; i < MAX_FUZZ_PACKETS; i++) {
+        packets1[i] = buf_new(RECV_MAX_PACKET_LEN);
+    }
+    for (i = 0; i < MAX_FUZZ_PACKETS; i++) {
+        packets2[i] = buf_new(RECV_MAX_PACKET_LEN);
+    }
+}
+
+size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
+              size_t MaxSize, unsigned int Seed) {
+
+    buf_setlen(alloc_packetA, 0);
+    buf_setlen(alloc_packetB, 0);
+    buf_setlen(oup, 0);
+
+    unsigned int i;
+    unsigned short randstate[3] = {0,0,0};
+    memcpy(randstate, &Seed, sizeof(Seed));
+
+    // printhex("mutator input", Data, Size);
+    #if 0
+    /* 1% chance straight llvm mutate */
+    if (nrand48(randstate) % 100 == 0) {
+        return LLVMFuzzerMutate(Data, Size, MaxSize);
+    }
+    #endif
+
+    buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0};
+    buffer *inp = &inp_buf;
+
+    /* Parse packets */
+    unsigned int num_packets = MAX_FUZZ_PACKETS;
+    buffer **packets = packets1;
+    fuzz_get_packets(inp, packets, &num_packets);
+
+    if (num_packets == 0) {
+        // gotta do something
+        memcpy(Data, FIXED_VERSION, MIN(strlen(FIXED_VERSION), MaxSize));
+        return LLVMFuzzerMutate(Data, Size, MaxSize);
+    }
+
+    /* Start output */
+    /* Put a new banner to output */
+    buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION));
+
+    /* Iterate output */
+    for (i = 0; i < num_packets+1; i++) {
+        // These are pointers to output
+        buffer *out_packetA = NULL, *out_packetB = NULL;
+        buf_setlen(alloc_packetA, 0);
+        buf_setlen(alloc_packetB, 0);
+
+        /* 5% chance each */
+        const int optA = nrand48(randstate) % 20;
+        if (optA == 0) {
+            /* Copy another */
+            unsigned int other = nrand48(randstate) % num_packets;
+            out_packetA = packets[other];
+        }
+        if (optA == 1) {
+            /* Mutate another */
+            unsigned int other = nrand48(randstate) % num_packets;
+            buffer *from = packets[other];
+            buf_putbytes(alloc_packetA, from->data, from->len);
+            out_packetA = alloc_packetA;
+            buf_llvm_mutate(out_packetA);
+        }
+
+        if (i < num_packets) {
+            int optB = nrand48(randstate) % 10;
+            if (optB == 1) {
+                /* 10% chance of drop */
+                /* Drop it */
+                // printf("%d drop\n", i);
+            } else if (optB <= 6) {
+                /* Mutate it, 50% chance */
+                // printf("%d mutate\n", i);
+                buffer *from = packets[nrand48(randstate) % num_packets];
+                buf_putbytes(alloc_packetB, from->data, from->len);
+                out_packetB = alloc_packetB;
+                buf_llvm_mutate(out_packetB);
+            } else {
+                /* Copy as-is */
+                out_packetB = packets[i];
+                // printf("%d as-is\n", i);
+            } 
+        }
+
+        if (out_packetA && oup->len + out_packetA->len <= oup->size) {
+            buf_putbytes(oup, out_packetA->data, out_packetA->len);
+        }
+        if (out_packetB && oup->len + out_packetB->len <= oup->size) {
+            buf_putbytes(oup, out_packetB->data, out_packetB->len);
+        }
+    }
+
+    size_t ret_len = MIN(MaxSize, oup->len);
+    memcpy(Data, oup->data, ret_len);
+    // printhex("mutator done", Data, ret_len);
+    return ret_len;
+}
+
+size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
+                                            const uint8_t *Data2, size_t Size2,
+                                            uint8_t *Out, size_t MaxOutSize,
+                                            unsigned int Seed) {
+    unsigned short randstate[3] = {0,0,0};
+    memcpy(randstate, &Seed, sizeof(Seed));
+
+    unsigned int i;
+    buffer inp_buf1 = {.data = (void*)Data1, .size = Size1, .len = Size1, .pos = 0};
+    buffer *inp1 = &inp_buf1;
+    buffer inp_buf2 = {.data = (void*)Data2, .size = Size2, .len = Size2, .pos = 0};
+    buffer *inp2 = &inp_buf2;
+
+    unsigned int num_packets1 = MAX_FUZZ_PACKETS;
+    fuzz_get_packets(inp1, packets1, &num_packets1);
+    unsigned int num_packets2 = MAX_FUZZ_PACKETS;
+    fuzz_get_packets(inp2, packets2, &num_packets2);
+
+    buf_setlen(oup, 0);
+    /* Put a new banner to output */
+    buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION));
+
+    for (i = 0; i < num_packets1+1; i++) {
+        if (num_packets2 > 0 && nrand48(randstate) % 10 == 0) {
+            /* 10% chance of taking another packet at each position */
+            int other = nrand48(randstate) % num_packets2;
+            // printf("inserted other packet %d at %d\n", other, i);
+            buffer *otherp = packets2[other];
+            if (oup->len + otherp->len <= oup->size) {
+                buf_putbytes(oup, otherp->data, otherp->len);
+            }
+        }
+        if (i < num_packets1) {
+            buffer *thisp = packets1[i];
+            if (oup->len + thisp->len <= oup->size) {
+                buf_putbytes(oup, thisp->data, thisp->len);
+            }
+        }
+    }
+
+    size_t ret_len = MIN(MaxOutSize, oup->len);
+    memcpy(Out, oup->data, ret_len);
+    return ret_len;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzz-wrapfd.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,241 @@
+#define FUZZ_SKIP_WRAP 1
+#include "includes.h"
+#include "fuzz-wrapfd.h"
+
+#include "dbutil.h"
+
+#include "fuzz.h"
+
+#define IOWRAP_MAXFD (FD_SETSIZE-1)
+static const int MAX_RANDOM_IN = 50000;
+static const double CHANCE_CLOSE = 1.0 / 600;
+static const double CHANCE_INTR = 1.0 / 900;
+static const double CHANCE_READ1 = 0.96;
+static const double CHANCE_READ2 = 0.5;
+static const double CHANCE_WRITE1 = 0.96;
+static const double CHANCE_WRITE2 = 0.5;
+
+struct fdwrap {
+	enum wrapfd_mode mode;
+	int closein;
+	int closeout;
+};
+
+static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
+static int wrapfd_maxfd = -1;
+static unsigned short rand_state[3];
+static buffer *input_buf;
+static int devnull_fd = -1;
+
+static void wrapfd_remove(int fd);
+
+void wrapfd_setup(buffer *buf) {
+	TRACE(("wrapfd_setup"))
+
+	// clean old ones
+	int i;
+	for (i = 0; i <= wrapfd_maxfd; i++) {
+		if (wrap_fds[i].mode == COMMONBUF) {
+			wrapfd_remove(i);
+		}
+	}
+	wrapfd_maxfd = -1;
+
+	memset(rand_state, 0x0, sizeof(rand_state));
+	wrapfd_setseed(50);
+	input_buf = buf;
+}
+
+void wrapfd_setseed(uint32_t seed) {
+	memcpy(rand_state, &seed, sizeof(seed));
+	nrand48(rand_state);
+}
+
+int wrapfd_new() {
+	if (devnull_fd == -1) {
+		devnull_fd = open("/dev/null", O_RDONLY);
+		assert(devnull_fd != -1);
+	}
+
+	int fd = dup(devnull_fd);
+	assert(fd != -1);
+	assert(wrap_fds[fd].mode == UNUSED);
+	wrap_fds[fd].mode = COMMONBUF;
+	wrap_fds[fd].closein = 0;
+	wrap_fds[fd].closeout = 0;
+	wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
+
+	return fd;
+}
+
+static void wrapfd_remove(int fd) {
+	TRACE(("wrapfd_remove %d", fd))
+	assert(fd >= 0);
+	assert(fd <= IOWRAP_MAXFD);
+	assert(wrap_fds[fd].mode != UNUSED);
+	wrap_fds[fd].mode = UNUSED;
+	m_close(fd);
+}
+
+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;
+
+	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;
+	}
+
+	if (input_buf) {
+		maxread = MIN(input_buf->len - input_buf->pos, count);
+		/* returns 0 if buf is EOF, as intended */
+		if (maxread > 0) {
+			maxread = nrand48(rand_state) % maxread + 1;
+		}
+		memcpy(out, buf_getptr(input_buf, maxread), maxread);
+		buf_incrpos(input_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];
+
+	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++;
+			}
+		}
+		DROPBEAR_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++;
+			}
+		}
+		DROPBEAR_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/fuzzer-client.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	return fuzz_run_client(Data, Size, 0);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzzer-client_mutator.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	return fuzz_run_client(Data, Size, 0);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzzer-client_mutator_nomaths.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	return fuzz_run_client(Data, Size, 0);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzzer-client_nomaths.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	return fuzz_run_client(Data, Size, 1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzzer-kexcurve25519.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,72 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "runopts.h"
+#include "algo.h"
+#include "bignum.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	static int once = 0;
+	static struct key_context* keep_newkeys = NULL;
+	/* number of generated parameters is limited by the timeout for the first run.
+	   TODO move this to the libfuzzer initialiser function instead if the timeout
+	   doesn't apply there */
+	#define NUM_PARAMS 20
+	static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
+
+	if (!once) {
+		fuzz_common_setup();
+		fuzz_svr_setup();
+
+		keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+		keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
+		keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
+		ses.newkeys = keep_newkeys;
+
+		/* Pre-generate parameters */
+		int i;
+		for (i = 0; i < NUM_PARAMS; i++) {
+			curve25519_params[i] = gen_kexcurve25519_param();
+		}
+
+		once = 1;
+	}
+
+	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+		return 0;
+	}
+
+	m_malloc_set_epoch(1);
+
+	if (setjmp(fuzz.jmp) == 0) {
+		/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() 
+		with DROPBEAR_KEX_CURVE25519 */
+		ses.newkeys = keep_newkeys;
+
+		/* Choose from the collection of curve25519 params */
+		unsigned int e = buf_getint(fuzz.input);
+		struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
+
+		buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
+
+		ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
+		kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
+
+		mp_clear(ses.dh_K);
+		m_free(ses.dh_K);
+		buf_free(ecdh_qs);
+
+		buf_free(ses.hash);
+		buf_free(ses.session_id);
+		/* kexhashbuf is freed in kexdh_comb_key */
+
+		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/fuzzer-kexdh.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,76 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "runopts.h"
+#include "algo.h"
+#include "bignum.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	static int once = 0;
+	static struct key_context* keep_newkeys = NULL;
+	/* number of generated parameters is limited by the timeout for the first run.
+	   TODO move this to the libfuzzer initialiser function instead if the timeout
+	   doesn't apply there */
+	#define NUM_PARAMS 20
+	static struct kex_dh_param *dh_params[NUM_PARAMS];
+
+	if (!once) {
+		fuzz_common_setup();
+		fuzz_svr_setup();
+
+		keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+		keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
+		keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+		ses.newkeys = keep_newkeys;
+
+		/* Pre-generate parameters */
+		int i;
+		for (i = 0; i < NUM_PARAMS; i++) {
+			dh_params[i] = gen_kexdh_param();
+		}
+
+		once = 1;
+	}
+
+	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+		return 0;
+	}
+
+	m_malloc_set_epoch(1);
+
+	if (setjmp(fuzz.jmp) == 0) {
+		/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() 
+		with DROPBEAR_KEX_NORMAL_DH */
+		ses.newkeys = keep_newkeys;
+
+		/* Choose from the collection of ecdh params */
+		unsigned int e = buf_getint(fuzz.input);
+		struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
+
+		DEF_MP_INT(dh_e);
+		m_mp_init(&dh_e);
+		if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
+			dropbear_exit("Bad kex value");
+		}
+
+		ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
+		kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
+
+		mp_clear(ses.dh_K);
+		m_free(ses.dh_K);
+		mp_clear(&dh_e);
+
+		buf_free(ses.hash);
+		buf_free(ses.session_id);
+		/* kexhashbuf is freed in kexdh_comb_key */
+
+		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/fuzzer-kexecdh.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,82 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "runopts.h"
+#include "algo.h"
+#include "bignum.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+	static int once = 0;
+	static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
+	static struct key_context* keep_newkeys = NULL;
+	/* number of generated parameters is limited by the timeout for the first run */
+	#define NUM_PARAMS 80
+	static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
+
+	if (!once) {
+		fuzz_common_setup();
+		fuzz_svr_setup();
+
+		/* ses gets zeroed by fuzz_set_input */
+		keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+		ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
+		ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
+		ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
+		assert(ecdh[0]);
+		assert(ecdh[1]);
+		assert(ecdh[2]);
+		keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+		ses.newkeys = keep_newkeys;
+
+		/* Pre-generate parameters */
+		int i;
+		for (i = 0; i < NUM_PARAMS; i++) {
+			ses.newkeys->algo_kex = ecdh[i % 3];
+			ecdh_params[i] = gen_kexecdh_param();
+		}
+
+		once = 1;
+	}
+
+	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+		return 0;
+	}
+
+	m_malloc_set_epoch(1);
+
+	if (setjmp(fuzz.jmp) == 0) {
+		/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() 
+		with DROPBEAR_KEX_ECDH */
+		ses.newkeys = keep_newkeys;
+
+		/* random choice of ecdh 256, 384, 521 */
+		unsigned char b = buf_getbyte(fuzz.input);
+		ses.newkeys->algo_kex = ecdh[b % 3];
+
+		/* Choose from the collection of ecdh params */
+		unsigned int e = buf_getint(fuzz.input);
+		struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
+
+		buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
+
+		ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
+		kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
+
+		mp_clear(ses.dh_K);
+		m_free(ses.dh_K);
+		buf_free(ecdh_qs);
+
+		buf_free(ses.hash);
+		buf_free(ses.session_id);
+		/* kexhashbuf is freed in kexdh_comb_key */
+
+		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/fuzzer-preauth.c	Thu Oct 29 21:51:41 2020 +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/fuzz/fuzzer-preauth_nomaths.c	Thu Oct 29 21:51:41 2020 +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/fuzz/fuzzer-pubkey.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,54 @@
+#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);
+
+	if (setjmp(fuzz.jmp) == 0) {
+		buffer *line = buf_getstringbuf(fuzz.input);
+		buffer *keyblob = buf_getstringbuf(fuzz.input);
+
+		unsigned int algolen;
+		char* algoname = buf_getstring(keyblob, &algolen);
+
+		if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
+			dropbear_exit("fuzzer imagined a bogus algorithm");
+		}
+
+		int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
+			algoname, algolen,
+			keyblob->data, keyblob->len);
+
+		if (ret == DROPBEAR_SUCCESS) {
+			/* fuzz_checkpubkey_line() should have cleaned up for failure */
+			svr_pubkey_options_cleanup();
+		}
+
+		buf_free(line);
+		buf_free(keyblob);
+		m_free(algoname);
+		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/fuzzer-verify.c	Thu Oct 29 21:51:41 2020 +0800
@@ -0,0 +1,79 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "dss.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 keytype = DROPBEAR_SIGNKEY_ANY;
+		if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
+			enum signature_type sigtype;
+			if (keytype == DROPBEAR_SIGNKEY_RSA) {
+				/* Flip a coin to decide rsa signature type */
+				int flag = buf_getbyte(fuzz.input);
+				if (flag & 0x01) {
+					sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
+				} else {
+					sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
+				}
+			} else {
+				sigtype = signature_type_from_signkey(keytype);
+			}
+			if (buf_verify(fuzz.input, key, sigtype, 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 (keytype == DROPBEAR_SIGNKEY_DSS) {
+					/* So far have seen dss keys with bad p/q/g domain parameters */
+					int pprime, qprime, trials;
+					trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
+					assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
+					trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
+					assert(mp_prime_is_prime(key->dsskey->q, trials, &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/fuzzer-client.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#include "fuzz.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	return fuzz_run_client(Data, Size, 0);
-}
-
--- a/fuzzer-client_nomaths.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#include "fuzz.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	return fuzz_run_client(Data, Size, 1);
-}
-
--- a/fuzzer-kexcurve25519.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-#include "fuzz.h"
-#include "session.h"
-#include "fuzz-wrapfd.h"
-#include "debug.h"
-#include "runopts.h"
-#include "algo.h"
-#include "bignum.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	static int once = 0;
-	static struct key_context* keep_newkeys = NULL;
-	/* number of generated parameters is limited by the timeout for the first run.
-	   TODO move this to the libfuzzer initialiser function instead if the timeout
-	   doesn't apply there */
-	#define NUM_PARAMS 20
-	static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
-
-	if (!once) {
-		fuzz_common_setup();
-		fuzz_svr_setup();
-
-		keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
-		keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
-		keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
-		ses.newkeys = keep_newkeys;
-
-		/* Pre-generate parameters */
-		int i;
-		for (i = 0; i < NUM_PARAMS; i++) {
-			curve25519_params[i] = gen_kexcurve25519_param();
-		}
-
-		once = 1;
-	}
-
-	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
-		return 0;
-	}
-
-	m_malloc_set_epoch(1);
-
-	if (setjmp(fuzz.jmp) == 0) {
-		/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() 
-		with DROPBEAR_KEX_CURVE25519 */
-		ses.newkeys = keep_newkeys;
-
-		/* Choose from the collection of curve25519 params */
-		unsigned int e = buf_getint(fuzz.input);
-		struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
-
-		buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
-
-		ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
-		kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
-
-		mp_clear(ses.dh_K);
-		m_free(ses.dh_K);
-		buf_free(ecdh_qs);
-
-		buf_free(ses.hash);
-		buf_free(ses.session_id);
-		/* kexhashbuf is freed in kexdh_comb_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/fuzzer-kexdh.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-#include "fuzz.h"
-#include "session.h"
-#include "fuzz-wrapfd.h"
-#include "debug.h"
-#include "runopts.h"
-#include "algo.h"
-#include "bignum.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	static int once = 0;
-	static struct key_context* keep_newkeys = NULL;
-	/* number of generated parameters is limited by the timeout for the first run.
-	   TODO move this to the libfuzzer initialiser function instead if the timeout
-	   doesn't apply there */
-	#define NUM_PARAMS 20
-	static struct kex_dh_param *dh_params[NUM_PARAMS];
-
-	if (!once) {
-		fuzz_common_setup();
-		fuzz_svr_setup();
-
-		keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
-		keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
-		keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
-		ses.newkeys = keep_newkeys;
-
-		/* Pre-generate parameters */
-		int i;
-		for (i = 0; i < NUM_PARAMS; i++) {
-			dh_params[i] = gen_kexdh_param();
-		}
-
-		once = 1;
-	}
-
-	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
-		return 0;
-	}
-
-	m_malloc_set_epoch(1);
-
-	if (setjmp(fuzz.jmp) == 0) {
-		/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() 
-		with DROPBEAR_KEX_NORMAL_DH */
-		ses.newkeys = keep_newkeys;
-
-		/* Choose from the collection of ecdh params */
-		unsigned int e = buf_getint(fuzz.input);
-		struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
-
-		DEF_MP_INT(dh_e);
-		m_mp_init(&dh_e);
-		if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
-			dropbear_exit("Bad kex value");
-		}
-
-		ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
-		kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
-
-		mp_clear(ses.dh_K);
-		m_free(ses.dh_K);
-		mp_clear(&dh_e);
-
-		buf_free(ses.hash);
-		buf_free(ses.session_id);
-		/* kexhashbuf is freed in kexdh_comb_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/fuzzer-kexecdh.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#include "fuzz.h"
-#include "session.h"
-#include "fuzz-wrapfd.h"
-#include "debug.h"
-#include "runopts.h"
-#include "algo.h"
-#include "bignum.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	static int once = 0;
-	static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
-	static struct key_context* keep_newkeys = NULL;
-	/* number of generated parameters is limited by the timeout for the first run */
-	#define NUM_PARAMS 80
-	static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
-
-	if (!once) {
-		fuzz_common_setup();
-		fuzz_svr_setup();
-
-		/* ses gets zeroed by fuzz_set_input */
-		keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
-		ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
-		ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
-		ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
-		assert(ecdh[0]);
-		assert(ecdh[1]);
-		assert(ecdh[2]);
-		keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
-		ses.newkeys = keep_newkeys;
-
-		/* Pre-generate parameters */
-		int i;
-		for (i = 0; i < NUM_PARAMS; i++) {
-			ses.newkeys->algo_kex = ecdh[i % 3];
-			ecdh_params[i] = gen_kexecdh_param();
-		}
-
-		once = 1;
-	}
-
-	if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
-		return 0;
-	}
-
-	m_malloc_set_epoch(1);
-
-	if (setjmp(fuzz.jmp) == 0) {
-		/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() 
-		with DROPBEAR_KEX_ECDH */
-		ses.newkeys = keep_newkeys;
-
-		/* random choice of ecdh 256, 384, 521 */
-		unsigned char b = buf_getbyte(fuzz.input);
-		ses.newkeys->algo_kex = ecdh[b % 3];
-
-		/* Choose from the collection of ecdh params */
-		unsigned int e = buf_getint(fuzz.input);
-		struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
-
-		buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
-
-		ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
-		kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
-
-		mp_clear(ses.dh_K);
-		m_free(ses.dh_K);
-		buf_free(ecdh_qs);
-
-		buf_free(ses.hash);
-		buf_free(ses.session_id);
-		/* kexhashbuf is freed in kexdh_comb_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/fuzzer-preauth.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#include "fuzz.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	return fuzz_run_preauth(Data, Size, 0);
-}
-
--- a/fuzzer-preauth_nomaths.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#include "fuzz.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-	return fuzz_run_preauth(Data, Size, 1);
-}
-
--- a/fuzzer-pubkey.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-#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);
-
-	if (setjmp(fuzz.jmp) == 0) {
-		buffer *line = buf_getstringbuf(fuzz.input);
-		buffer *keyblob = buf_getstringbuf(fuzz.input);
-
-		unsigned int algolen;
-		char* algoname = buf_getstring(keyblob, &algolen);
-
-		if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
-			dropbear_exit("fuzzer imagined a bogus algorithm");
-		}
-
-		int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
-			algoname, algolen,
-			keyblob->data, keyblob->len);
-
-		if (ret == DROPBEAR_SUCCESS) {
-			/* fuzz_checkpubkey_line() should have cleaned up for failure */
-			svr_pubkey_options_cleanup();
-		}
-
-		buf_free(line);
-		buf_free(keyblob);
-		m_free(algoname);
-		m_malloc_free_epoch(1, 0);
-	} else {
-		m_malloc_free_epoch(1, 1);
-		TRACE(("dropbear_exit longjmped"))
-		/* dropbear_exit jumped here */
-	}
-
-	return 0;
-}
--- a/fuzzer-verify.c	Thu Oct 29 21:40:34 2020 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-#include "fuzz.h"
-#include "session.h"
-#include "fuzz-wrapfd.h"
-#include "debug.h"
-#include "dss.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 keytype = DROPBEAR_SIGNKEY_ANY;
-		if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
-			enum signature_type sigtype;
-			if (keytype == DROPBEAR_SIGNKEY_RSA) {
-				/* Flip a coin to decide rsa signature type */
-				int flag = buf_getbyte(fuzz.input);
-				if (flag & 0x01) {
-					sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
-				} else {
-					sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
-				}
-			} else {
-				sigtype = signature_type_from_signkey(keytype);
-			}
-			if (buf_verify(fuzz.input, key, sigtype, 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 (keytype == DROPBEAR_SIGNKEY_DSS) {
-					/* So far have seen dss keys with bad p/q/g domain parameters */
-					int pprime, qprime, trials;
-					trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
-					assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
-					trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
-					assert(mp_prime_is_prime(key->dsskey->q, trials, &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;
-}