# HG changeset patch # User Matt Johnston # Date 1495257796 -28800 # Node ID 08f4fa4dc6a0267f3d23254b54a3798d894abae3 # Parent 3677a510f545f2e17f43045dc809c6e5254f0abe closer to working diff -r 3677a510f545 -r 08f4fa4dc6a0 common-kex.c --- a/common-kex.c Fri May 19 00:48:46 2017 +0800 +++ b/common-kex.c Sat May 20 13:23:16 2017 +0800 @@ -944,14 +944,9 @@ } #ifdef DROPBEAR_FUZZ - ses.newkeys->recv.algo_crypt = &dropbear_nocipher; - ses.newkeys->trans.algo_crypt = &dropbear_nocipher; - ses.newkeys->recv.crypt_mode = &dropbear_mode_none; - ses.newkeys->trans.crypt_mode = &dropbear_mode_none; - ses.newkeys->recv.algo_mac = &dropbear_nohash; - ses.newkeys->trans.algo_mac = &dropbear_nohash; - ses.newkeys->recv.algo_comp = DROPBEAR_COMP_NONE; - ses.newkeys->trans.algo_comp = DROPBEAR_COMP_NONE; + if (fuzz.fuzzing) { + fuzz_kex_fakealgos(); + } #endif /* reserved for future extensions */ diff -r 3677a510f545 -r 08f4fa4dc6a0 common-session.c --- a/common-session.c Fri May 19 00:48:46 2017 +0800 +++ b/common-session.c Sat May 20 13:23:16 2017 +0800 @@ -161,7 +161,12 @@ /* We get woken up when signal handlers write to this pipe. SIGCHLD in svr-chansession is the only one currently. */ - FD_SET(ses.signal_pipe[0], &readfd); +#ifdef DROPBEAR_FUZZ + if (!fuzz.fuzzing) +#endif + { + FD_SET(ses.signal_pipe[0], &readfd); + } ses.channel_signal_pending = 0; /* set up for channels which can be read/written */ diff -r 3677a510f545 -r 08f4fa4dc6a0 dbrandom.c --- a/dbrandom.c Fri May 19 00:48:46 2017 +0800 +++ b/dbrandom.c Sat May 20 13:23:16 2017 +0800 @@ -28,8 +28,6 @@ #include "bignum.h" #include "dbrandom.h" #include "runopts.h" -#include "fuzz.h" - /* this is used to generate unique output from the same hashpool */ static uint32_t counter = 0; diff -r 3677a510f545 -r 08f4fa4dc6a0 fuzz-common.c --- a/fuzz-common.c Fri May 19 00:48:46 2017 +0800 +++ b/fuzz-common.c Sat May 20 13:23:16 2017 +0800 @@ -1,7 +1,5 @@ #include "includes.h" -#ifdef DROPBEAR_FUZZ - #include "includes.h" #include "fuzz.h" #include "dbutil.h" @@ -17,6 +15,7 @@ static void common_setup_fuzzer(void) { fuzz.fuzzing = 1; + fuzz.wrapfds = 1; fuzz.input = m_malloc(sizeof(buffer)); crypto_init(); } @@ -30,7 +29,7 @@ // get prefix. input format is // string prefix - // uint32_t seed + // uint32 wrapfd seed // ... to be extended later // [bytes] ssh input stream @@ -114,4 +113,6 @@ buf_free(b); } -#endif /* DROPBEAR_FUZZ */ +void fuzz_kex_fakealgos(void) { + ses.newkeys->recv.crypt_mode = &dropbear_mode_none; +} diff -r 3677a510f545 -r 08f4fa4dc6a0 fuzz-harness.c --- a/fuzz-harness.c Fri May 19 00:48:46 2017 +0800 +++ b/fuzz-harness.c Sat May 20 13:23:16 2017 +0800 @@ -8,6 +8,10 @@ int i; buffer *input = buf_new(100000); +#if DROPBEAR_TRACE + debug_trace = 1; +#endif + for (i = 1; i < argc; i++) { char* fn = argv[i]; buf_setlen(input, 0); diff -r 3677a510f545 -r 08f4fa4dc6a0 fuzz-wrapfd.c --- a/fuzz-wrapfd.c Fri May 19 00:48:46 2017 +0800 +++ b/fuzz-wrapfd.c Sat May 20 13:23:16 2017 +0800 @@ -1,6 +1,9 @@ +#define FUZZ_SKIP_WRAP 1 #include "includes.h" #include "fuzz-wrapfd.h" +#include "fuzz.h" + static const int IOWRAP_MAXFD = FD_SETSIZE-1; static const int MAX_RANDOM_IN = 50000; static const double CHANCE_CLOSE = 1.0 / 300; @@ -22,6 +25,7 @@ static unsigned short rand_state[3]; void wrapfd_setup(uint32_t seed) { + TRACE(("wrapfd_setup %x", seed)) nused = 0; memset(wrap_fds, 0x0, sizeof(wrap_fds)); @@ -35,6 +39,8 @@ assert(wrap_fds[fd].mode == UNUSED); assert(buf || mode == RANDOMIN); + TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode)) + wrap_fds[fd].mode = mode; wrap_fds[fd].buf = buf; wrap_used[nused] = fd; @@ -49,6 +55,8 @@ assert(wrap_fds[fd].mode != UNUSED); wrap_fds[fd].mode = UNUSED; + TRACE(("wrapfd_remove %d", fd)) + // remove from used list for (i = 0, j = 0; i < nused; i++) { if (wrap_used[i] != fd) { @@ -64,7 +72,12 @@ size_t maxread; buffer *buf; - if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode != UNUSED) { + 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; @@ -86,7 +99,9 @@ if (buf) { maxread = MIN(buf->len - buf->pos, count); // returns 0 if buf is EOF, as intended - maxread = nrand48(rand_state) % maxread + 1; + if (maxread > 0) { + maxread = nrand48(rand_state) % maxread + 1; + } memcpy(out, buf_getptr(buf, maxread), maxread); buf_incrpos(buf, maxread); return maxread; @@ -101,7 +116,13 @@ 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) { + + 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; @@ -128,11 +149,15 @@ } int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, - fd_set *UNUSED(exceptfds), struct timeval *UNUSED(timeout)) { - int i, nset; + fd_set *exceptfds, struct timeval *timeout) { + int i, nset, sel; int ret = 0; int fdlist[IOWRAP_MAXFD+1] = {0}; + if (!fuzz.wrapfds) { + return select(nfds, readfds, writefds, exceptfds, timeout); + } + assert(nfds <= IOWRAP_MAXFD+1); if (erand48(rand_state) < CHANCE_INTR) { @@ -141,24 +166,26 @@ } // read - if (erand48(rand_state) < CHANCE_READ1) { + if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) { for (i = 0, nset = 0; i < nfds; i++) { if (FD_ISSET(i, readfds)) { assert(wrap_fds[i].mode != UNUSED); fdlist[nset] = i; + nset++; } } FD_ZERO(readfds); if (nset > 0) { // set one - FD_SET(fdlist[random() % nset], readfds); + sel = fdlist[nrand48(rand_state) % nset]; + FD_SET(sel, readfds); ret++; if (erand48(rand_state) < CHANCE_READ2) { - i = fdlist[random() % nset]; - if (!FD_ISSET(i, readfds)) { - FD_SET(i, readfds); + sel = fdlist[nrand48(rand_state) % nset]; + if (!FD_ISSET(sel, readfds)) { + FD_SET(sel, readfds); ret++; } } @@ -166,24 +193,26 @@ } // write - if (erand48(rand_state) < CHANCE_WRITE1) { + if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) { for (i = 0, nset = 0; i < nfds; i++) { if (FD_ISSET(i, writefds)) { assert(wrap_fds[i].mode != UNUSED); fdlist[nset] = i; + nset++; } } FD_ZERO(writefds); // set one if (nset > 0) { - FD_SET(fdlist[nrand48(rand_state) % nset], writefds); + sel = fdlist[nrand48(rand_state) % nset]; + FD_SET(sel, writefds); ret++; if (erand48(rand_state) < CHANCE_WRITE2) { - i = fdlist[nrand48(rand_state) % nset]; - if (!FD_ISSET(i, writefds)) { - FD_SET(i, writefds); + sel = fdlist[nrand48(rand_state) % nset]; + if (!FD_ISSET(sel, writefds)) { + FD_SET(sel, writefds); ret++; } } @@ -191,3 +220,4 @@ } return ret; } + diff -r 3677a510f545 -r 08f4fa4dc6a0 fuzz-wrapfd.h --- a/fuzz-wrapfd.h Fri May 19 00:48:46 2017 +0800 +++ b/fuzz-wrapfd.h Sat May 20 13:23:16 2017 +0800 @@ -14,4 +14,10 @@ // doesn't take ownership of buf. buf is optional. void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode); +// called via #defines for read/write/select +int wrapfd_read(int fd, void *out, size_t count); +int wrapfd_write(int fd, const void* in, size_t count); +int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); + #endif // FUZZ_WRAPFD_H diff -r 3677a510f545 -r 08f4fa4dc6a0 fuzz.h --- a/fuzz.h Fri May 19 00:48:46 2017 +0800 +++ b/fuzz.h Sat May 20 13:23:16 2017 +0800 @@ -1,10 +1,13 @@ #ifndef DROPBEAR_FUZZ_H #define DROPBEAR_FUZZ_H +#include "config.h" +#ifdef DROPBEAR_FUZZ + #include "includes.h" #include "buffer.h" - -#ifdef DROPBEAR_FUZZ +#include "algo.h" +#include "fuzz-wrapfd.h" // once per process void svr_setup_fuzzer(void); @@ -12,6 +15,16 @@ // once per input. returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE int fuzzer_set_input(const uint8_t *Data, size_t Size); +void fuzz_kex_fakealgos(void); + +// fake IO wrappers +#ifndef FUZZ_SKIP_WRAP +#define select(nfds, readfds, writefds, exceptfds, timeout) \ + wrapfd_select(nfds, readfds, writefds, exceptfds, timeout) +#define write(fd, buf, count) wrapfd_write(fd, buf, count) +#define read(fd, buf, count) wrapfd_read(fd, buf, count) +#endif // FUZZ_SKIP_WRAP + struct dropbear_fuzz_options { int fuzzing; @@ -20,6 +33,9 @@ // fuzzing input buffer *input; + struct dropbear_cipher recv_cipher; + struct dropbear_hash recv_mac; + int wrapfds; // dropbear_exit() jumps back sigjmp_buf jmp; @@ -34,6 +50,6 @@ extern struct dropbear_fuzz_options fuzz; -#endif +#endif // DROPBEAR_FUZZ #endif /* DROPBEAR_FUZZ_H */ diff -r 3677a510f545 -r 08f4fa4dc6a0 fuzzer-preauth.c --- a/fuzzer-preauth.c Fri May 19 00:48:46 2017 +0800 +++ b/fuzzer-preauth.c Sat May 20 13:23:16 2017 +0800 @@ -24,6 +24,7 @@ if (setjmp(fuzz.jmp) == 0) { svr_session(fakesock, fakesock); } else { + TRACE(("dropbear_exit longjmped")) // dropbear_exit jumped here } diff -r 3677a510f545 -r 08f4fa4dc6a0 includes.h --- a/includes.h Fri May 19 00:48:46 2017 +0800 +++ b/includes.h Sat May 20 13:23:16 2017 +0800 @@ -133,7 +133,6 @@ #include #endif - #include "compat.h" #ifndef HAVE_U_INT8_T @@ -164,6 +163,8 @@ #include "fake-rfc2553.h" +#include "fuzz.h" + #ifndef LOG_AUTHPRIV #define LOG_AUTHPRIV LOG_AUTH #endif diff -r 3677a510f545 -r 08f4fa4dc6a0 netio.c --- a/netio.c Fri May 19 00:48:46 2017 +0800 +++ b/netio.c Sat May 20 13:23:16 2017 +0800 @@ -195,6 +195,7 @@ } iter = next_iter; } + TRACE(("leave set_connect_fds")) } void handle_connect_fds(fd_set *writefd) { diff -r 3677a510f545 -r 08f4fa4dc6a0 packet.c --- a/packet.c Fri May 19 00:48:46 2017 +0800 +++ b/packet.c Sat May 20 13:23:16 2017 +0800 @@ -36,7 +36,6 @@ #include "channel.h" #include "netio.h" #include "runopts.h" -#include "fuzz.h" static int read_packet_init(void); static void make_mac(unsigned int seqno, const struct key_context_directional * key_state, @@ -371,6 +370,17 @@ buf_setpos(ses.readbuf, 0); make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes); +#ifdef DROPBEAR_FUZZ + if (fuzz.fuzzing) { + // fail 1 in 1000 times to test error path + unsigned int value = *((unsigned int*)&mac_bytes); + if (value % 1000 == 0) { + return DROPBEAR_FAILURE; + } + return DROPBEAR_SUCCESS; + } +#endif + /* compare the hash */ buf_setpos(ses.readbuf, contents_len); if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {