# HG changeset patch # User Matt Johnston # Date 1495126126 -28800 # Node ID 3677a510f545f2e17f43045dc809c6e5254f0abe # Parent 3fdd8c5a019597f0cee2755d66e2474210100773 add wrapfd. improve fuzzer in makefile diff -r 3fdd8c5a0195 -r 3677a510f545 Makefile.in --- a/Makefile.in Thu May 18 23:45:10 2017 +0800 +++ b/Makefile.in Fri May 19 00:48:46 2017 +0800 @@ -34,7 +34,7 @@ queue.o \ atomicio.o compat.o fake-rfc2553.o \ ltc_prng.o ecc.o ecdsa.o crypto_desc.o \ - gensignkey.o gendss.o genrsa.o fuzz-common.o + gensignkey.o gendss.o genrsa.o SVROBJS=svr-kex.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \ @@ -57,6 +57,10 @@ SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o +ifeq (@DROPBEAR_FUZZ@, 1) + COMMONOBJS += fuzz-common.o fuzz-wrapfd.o +endif + HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \ debug.h channel.h chansession.h config.h queue.h sshpty.h \ @@ -270,3 +274,4 @@ /usr/bin/xxd -i -a keyr >> hostkeys.c /usr/bin/xxd -i -a keye >> hostkeys.c /usr/bin/xxd -i -a keyd >> hostkeys.c + diff -r 3fdd8c5a0195 -r 3677a510f545 configure.ac --- a/configure.ac Thu May 18 23:45:10 2017 +0800 +++ b/configure.ac Fri May 19 00:48:46 2017 +0800 @@ -223,10 +223,14 @@ [ AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing) AC_MSG_NOTICE(Enabling fuzzing) + DROPBEAR_FUZZ=1 + ], + [ + DROPBEAR_FUZZ=0 ] + ) - - +AC_SUBST(DROPBEAR_FUZZ) # Checks for header files. AC_HEADER_STDC diff -r 3fdd8c5a0195 -r 3677a510f545 fuzz-common.c --- a/fuzz-common.c Thu May 18 23:45:10 2017 +0800 +++ b/fuzz-common.c Fri May 19 00:48:46 2017 +0800 @@ -8,6 +8,8 @@ #include "runopts.h" #include "crypto_desc.h" #include "session.h" +#include "dbrandom.h" +#include "fuzz-wrapfd.h" struct dropbear_fuzz_options fuzz; @@ -15,9 +17,40 @@ static void common_setup_fuzzer(void) { fuzz.fuzzing = 1; + fuzz.input = m_malloc(sizeof(buffer)); crypto_init(); } +int fuzzer_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; + + // get prefix. input format is + // string prefix + // uint32_t seed + // ... to be extended later + // [bytes] ssh input stream + + // be careful to avoid triggering buffer.c assertions + if (fuzz.input->len < 8) { + return DROPBEAR_FAILURE; + } + size_t prefix_size = buf_getint(fuzz.input); + if (prefix_size != 4) { + return DROPBEAR_FAILURE; + } + uint32_t wrapseed = buf_getint(fuzz.input); + wrapfd_setup(wrapseed); + + seedrandom(); + + return DROPBEAR_SUCCESS; +} + + void svr_setup_fuzzer(void) { struct passwd *pw; diff -r 3fdd8c5a0195 -r 3677a510f545 fuzz-wrapfd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fuzz-wrapfd.c Fri May 19 00:48:46 2017 +0800 @@ -0,0 +1,193 @@ +#include "includes.h" +#include "fuzz-wrapfd.h" + +static const int IOWRAP_MAXFD = FD_SETSIZE-1; +static const int MAX_RANDOM_IN = 50000; +static const double CHANCE_CLOSE = 1.0 / 300; +static const double CHANCE_INTR = 1.0 / 200; +static const double CHANCE_READ1 = 0.6; +static const double CHANCE_READ2 = 0.3; +static const double CHANCE_WRITE1 = 0.8; +static const double CHANCE_WRITE2 = 0.3; + +struct fdwrap { + enum wrapfd_mode mode; + buffer *buf; +}; + +static struct fdwrap wrap_fds[IOWRAP_MAXFD+1]; +// for quick selection of in-use descriptors +static int wrap_used[IOWRAP_MAXFD+1]; +static unsigned int nused; +static unsigned short rand_state[3]; + +void wrapfd_setup(uint32_t seed) { + nused = 0; + memset(wrap_fds, 0x0, sizeof(wrap_fds)); + + *((uint32_t*)rand_state) = seed; + nrand48(rand_state); +} + +void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) { + assert(fd >= 0); + assert(fd <= IOWRAP_MAXFD); + assert(wrap_fds[fd].mode == UNUSED); + assert(buf || mode == RANDOMIN); + + wrap_fds[fd].mode = mode; + wrap_fds[fd].buf = buf; + wrap_used[nused] = fd; + + nused++; +} + +void wrapfd_remove(int fd) { + unsigned int i, j; + assert(fd >= 0); + assert(fd <= IOWRAP_MAXFD); + assert(wrap_fds[fd].mode != UNUSED); + wrap_fds[fd].mode = UNUSED; + + // remove from used list + for (i = 0, j = 0; i < nused; i++) { + if (wrap_used[i] != fd) { + wrap_used[j] = wrap_used[i]; + j++; + } + } + nused--; +} + + +int wrapfd_read(int fd, void *out, size_t count) { + size_t maxread; + buffer *buf; + + if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode != UNUSED) { + TRACE(("Bad read descriptor %d\n", fd)) + errno = EBADF; + return -1; + } + + assert(count != 0); + + if (erand48(rand_state) < CHANCE_CLOSE) { + wrapfd_remove(fd); + return 0; + } + + if (erand48(rand_state) < CHANCE_INTR) { + errno = EINTR; + return -1; + } + + buf = wrap_fds[fd].buf; + if (buf) { + maxread = MIN(buf->len - buf->pos, count); + // returns 0 if buf is EOF, as intended + maxread = nrand48(rand_state) % maxread + 1; + memcpy(out, buf_getptr(buf, maxread), maxread); + buf_incrpos(buf, maxread); + return maxread; + } + + maxread = MIN(MAX_RANDOM_IN, count); + maxread = nrand48(rand_state) % maxread + 1; + memset(out, 0xef, maxread); + return maxread; +} + +int wrapfd_write(int fd, const void* in, size_t count) { + unsigned const volatile char* volin = in; + unsigned int i; + if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode != UNUSED) { + 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 (erand48(rand_state) < CHANCE_CLOSE) { + wrapfd_remove(fd); + return 0; + } + + 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 *UNUSED(exceptfds), struct timeval *UNUSED(timeout)) { + int i, nset; + int ret = 0; + int fdlist[IOWRAP_MAXFD+1] = {0}; + + assert(nfds <= IOWRAP_MAXFD+1); + + if (erand48(rand_state) < CHANCE_INTR) { + errno = EINTR; + return -1; + } + + // read + if (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; + } + } + FD_ZERO(readfds); + + if (nset > 0) { + // set one + FD_SET(fdlist[random() % nset], readfds); + ret++; + + if (erand48(rand_state) < CHANCE_READ2) { + i = fdlist[random() % nset]; + if (!FD_ISSET(i, readfds)) { + FD_SET(i, readfds); + ret++; + } + } + } + } + + // write + if (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; + } + } + FD_ZERO(writefds); + + // set one + if (nset > 0) { + FD_SET(fdlist[nrand48(rand_state) % nset], writefds); + ret++; + + if (erand48(rand_state) < CHANCE_WRITE2) { + i = fdlist[nrand48(rand_state) % nset]; + if (!FD_ISSET(i, writefds)) { + FD_SET(i, writefds); + ret++; + } + } + } + } + return ret; +} diff -r 3fdd8c5a0195 -r 3677a510f545 fuzz-wrapfd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fuzz-wrapfd.h Fri May 19 00:48:46 2017 +0800 @@ -0,0 +1,17 @@ +#ifndef FUZZ_WRAPFD_H +#define FUZZ_WRAPFD_H + +#include "buffer.h" + +enum wrapfd_mode { + UNUSED = 0, + PLAIN, + INPROGRESS, + RANDOMIN, +}; + +void wrapfd_setup(uint32_t wrapseed); +// doesn't take ownership of buf. buf is optional. +void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode); + +#endif // FUZZ_WRAPFD_H diff -r 3fdd8c5a0195 -r 3677a510f545 fuzz.h --- a/fuzz.h Thu May 18 23:45:10 2017 +0800 +++ b/fuzz.h Fri May 19 00:48:46 2017 +0800 @@ -6,8 +6,12 @@ #ifdef DROPBEAR_FUZZ +// once per process void svr_setup_fuzzer(void); +// once per input. returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE +int fuzzer_set_input(const uint8_t *Data, size_t Size); + struct dropbear_fuzz_options { int fuzzing; @@ -15,7 +19,7 @@ FILE* recordf; // fuzzing input - buffer input; + buffer *input; // dropbear_exit() jumps back sigjmp_buf jmp; diff -r 3fdd8c5a0195 -r 3677a510f545 fuzzer-preauth.c --- a/fuzzer-preauth.c Thu May 18 23:45:10 2017 +0800 +++ b/fuzzer-preauth.c Fri May 19 00:48:46 2017 +0800 @@ -1,10 +1,10 @@ #include "fuzz.h" #include "dbrandom.h" #include "session.h" +#include "fuzz-wrapfd.h" -static int setup_fuzzer(void) { +static void setup_fuzzer(void) { svr_setup_fuzzer(); - return 0; } int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { @@ -14,15 +14,15 @@ once = 1; } - fuzz.input.data = (unsigned char*)Data; - fuzz.input.size = Size; - fuzz.input.len = Size; - fuzz.input.pos = 0; + if (fuzzer_set_input(Data, Size) == DROPBEAR_FAILURE) { + return 0; + } - seedrandom(); + int fakesock = 1; + wrapfd_add(fakesock, fuzz.input, PLAIN); if (setjmp(fuzz.jmp) == 0) { - svr_session(-1, -1); + svr_session(fakesock, fakesock); } else { // dropbear_exit jumped here }