diff options
-rw-r--r-- | Makefile.in | 58 | ||||
-rw-r--r-- | buffer.c | 1 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | dbrandom.c | 3 | ||||
-rw-r--r-- | dbutil.c | 35 | ||||
-rw-r--r-- | fuzz.h | 23 | ||||
-rw-r--r-- | fuzz/fuzz-common.c (renamed from fuzz-common.c) | 40 | ||||
-rw-r--r-- | fuzz/fuzz-harness.c (renamed from fuzz-harness.c) | 6 | ||||
-rw-r--r-- | fuzz/fuzz-hostkeys.c (renamed from fuzz-hostkeys.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzz-sshpacketmutator.c | 240 | ||||
-rw-r--r-- | fuzz/fuzz-wrapfd.c (renamed from fuzz-wrapfd.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-client.c (renamed from fuzzer-client.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-client_mutator.c | 6 | ||||
-rw-r--r-- | fuzz/fuzzer-client_mutator_nomaths.c | 6 | ||||
-rw-r--r-- | fuzz/fuzzer-client_nomaths.c (renamed from fuzzer-client_nomaths.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-kexcurve25519.c (renamed from fuzzer-kexcurve25519.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-kexdh.c (renamed from fuzzer-kexdh.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-kexecdh.c (renamed from fuzzer-kexecdh.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-preauth.c (renamed from fuzzer-preauth.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-preauth_nomaths.c (renamed from fuzzer-preauth_nomaths.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-pubkey.c (renamed from fuzzer-pubkey.c) | 0 | ||||
-rw-r--r-- | fuzz/fuzzer-verify.c (renamed from fuzzer-verify.c) | 0 |
22 files changed, 369 insertions, 50 deletions
diff --git a/Makefile.in b/Makefile.in index 182cb42..682419a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -62,7 +62,7 @@ CONVERTOBJS=dropbearconvert.o keyimport.o SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o ifeq (@DROPBEAR_FUZZ@, 1) - allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@ + allobjs = $(COMMONOBJS) fuzz/fuzz-common.o fuzz/fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@ allobjs:=$(subst svr-main.o, ,$(allobjs)) allobjs:=$(subst cli-main.o, ,$(allobjs)) @@ -72,6 +72,7 @@ ifeq (@DROPBEAR_FUZZ@, 1) dropbearconvertobjs=$(allobjs) $(CONVERTOBJS) # CXX only set when fuzzing CXX=@CXX@ + FUZZ_CLEAN=fuzz-clean else dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) @@ -246,7 +247,7 @@ ltm-clean: 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 @@ lint: # 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 - -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(). +fuzzstandalone: FUZZLIB=fuzz/fuzz-harness.o +fuzzstandalone: fuzz/fuzz-harness.o fuzz-targets + +# 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) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-verify: fuzzer-verify.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ +$(FUZZ_TARGETS): $(FUZZ_OBJS) $(allobjs) $(LIBTOM_DEPS) + $(CXX) $(CXXFLAGS) fuzz/$@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) -lcrypt -fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-client: fuzzer-client.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ - -fuzzer-client_nomaths: fuzzer-client_nomaths.o fuzz-harness.o - $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ +# fuzzers that use the custom mutator +fuzzer-client_mutator fuzzer-client_mutator_nomaths: allobjs += fuzz/fuzz-sshpacketmutator.o fuzzer-%.options: Makefile echo "[libfuzzer]" > $@ @@ -329,3 +312,6 @@ fuzz-hostkeys: /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) @@ -188,6 +188,7 @@ unsigned char* buf_getptr(const buffer* buf, unsigned int len) { 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]; diff --git a/configure.ac b/configure.ac index 473cea5..8f552a8 100644 --- a/configure.ac +++ b/configure.ac @@ -347,6 +347,7 @@ AC_ARG_ENABLE(fuzz, 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) @@ -150,10 +150,11 @@ static void write_urandom() } #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; @@ -385,20 +385,37 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) { #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) { @@ -15,6 +15,10 @@ void fuzz_common_setup(void); 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 @@ 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_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 @@ struct dropbear_fuzz_options { 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 */ diff --git a/fuzz-common.c b/fuzz/fuzz-common.c index 60dab21..a147710 100644 --- a/fuzz-common.c +++ b/fuzz/fuzz-common.c @@ -1,7 +1,6 @@ #include "includes.h" #include "includes.h" -#include "fuzz.h" #include "dbutil.h" #include "runopts.h" #include "crypto_desc.h" @@ -11,12 +10,27 @@ #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; @@ -25,9 +39,25 @@ void fuzz_common_setup(void) { fuzz.input = m_malloc(sizeof(buffer)); _dropbear_log = fuzz_dropbear_log; crypto_init(); - fuzz_seed(); + 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) { @@ -42,7 +72,7 @@ int fuzz_set_input(const uint8_t *Data, size_t Size) { memset(&cli_ses, 0x0, sizeof(cli_ses)); wrapfd_setup(fuzz.input); - fuzz_seed(); + fuzz_seed(fuzz.input->data, MIN(fuzz.input->len, 16)); return DROPBEAR_SUCCESS; } @@ -235,10 +265,12 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) { 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 */ @@ -281,10 +313,12 @@ int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) { 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 */ diff --git a/fuzz-harness.c b/fuzz/fuzz-harness.c index ced707c..36905d6 100644 --- a/fuzz-harness.c +++ b/fuzz/fuzz-harness.c @@ -46,3 +46,9 @@ int main(int argc, char ** argv) { 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; +} diff --git a/fuzz-hostkeys.c b/fuzz/fuzz-hostkeys.c index 128c8d1..128c8d1 100644 --- a/fuzz-hostkeys.c +++ b/fuzz/fuzz-hostkeys.c diff --git a/fuzz/fuzz-sshpacketmutator.c b/fuzz/fuzz-sshpacketmutator.c new file mode 100644 index 0000000..d26089d --- /dev/null +++ b/fuzz/fuzz-sshpacketmutator.c @@ -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; +} + diff --git a/fuzz-wrapfd.c b/fuzz/fuzz-wrapfd.c index c6d59fc..c6d59fc 100644 --- a/fuzz-wrapfd.c +++ b/fuzz/fuzz-wrapfd.c diff --git a/fuzzer-client.c b/fuzz/fuzzer-client.c index eb59f46..eb59f46 100644 --- a/fuzzer-client.c +++ b/fuzz/fuzzer-client.c diff --git a/fuzz/fuzzer-client_mutator.c b/fuzz/fuzzer-client_mutator.c new file mode 100644 index 0000000..eb59f46 --- /dev/null +++ b/fuzz/fuzzer-client_mutator.c @@ -0,0 +1,6 @@ +#include "fuzz.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return fuzz_run_client(Data, Size, 0); +} + diff --git a/fuzz/fuzzer-client_mutator_nomaths.c b/fuzz/fuzzer-client_mutator_nomaths.c new file mode 100644 index 0000000..eb59f46 --- /dev/null +++ b/fuzz/fuzzer-client_mutator_nomaths.c @@ -0,0 +1,6 @@ +#include "fuzz.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return fuzz_run_client(Data, Size, 0); +} + diff --git a/fuzzer-client_nomaths.c b/fuzz/fuzzer-client_nomaths.c index e0910a7..e0910a7 100644 --- a/fuzzer-client_nomaths.c +++ b/fuzz/fuzzer-client_nomaths.c diff --git a/fuzzer-kexcurve25519.c b/fuzz/fuzzer-kexcurve25519.c index f2eab14..f2eab14 100644 --- a/fuzzer-kexcurve25519.c +++ b/fuzz/fuzzer-kexcurve25519.c diff --git a/fuzzer-kexdh.c b/fuzz/fuzzer-kexdh.c index 224ff58..224ff58 100644 --- a/fuzzer-kexdh.c +++ b/fuzz/fuzzer-kexdh.c diff --git a/fuzzer-kexecdh.c b/fuzz/fuzzer-kexecdh.c index c3a450a..c3a450a 100644 --- a/fuzzer-kexecdh.c +++ b/fuzz/fuzzer-kexecdh.c diff --git a/fuzzer-preauth.c b/fuzz/fuzzer-preauth.c index 3ac49f4..3ac49f4 100644 --- a/fuzzer-preauth.c +++ b/fuzz/fuzzer-preauth.c diff --git a/fuzzer-preauth_nomaths.c b/fuzz/fuzzer-preauth_nomaths.c index efdc2c3..efdc2c3 100644 --- a/fuzzer-preauth_nomaths.c +++ b/fuzz/fuzzer-preauth_nomaths.c diff --git a/fuzzer-pubkey.c b/fuzz/fuzzer-pubkey.c index 7c12cdc..7c12cdc 100644 --- a/fuzzer-pubkey.c +++ b/fuzz/fuzzer-pubkey.c diff --git a/fuzzer-verify.c b/fuzz/fuzzer-verify.c index a0ad086..a0ad086 100644 --- a/fuzzer-verify.c +++ b/fuzz/fuzzer-verify.c |