diff options
-rw-r--r-- | common-kex.c | 11 | ||||
-rw-r--r-- | common-session.c | 7 | ||||
-rw-r--r-- | dbrandom.c | 2 | ||||
-rw-r--r-- | fuzz-common.c | 9 | ||||
-rw-r--r-- | fuzz-harness.c | 4 | ||||
-rw-r--r-- | fuzz-wrapfd.c | 60 | ||||
-rw-r--r-- | fuzz-wrapfd.h | 6 | ||||
-rw-r--r-- | fuzz.h | 22 | ||||
-rw-r--r-- | fuzzer-preauth.c | 1 | ||||
-rw-r--r-- | includes.h | 3 | ||||
-rw-r--r-- | netio.c | 1 | ||||
-rw-r--r-- | packet.c | 12 |
12 files changed, 103 insertions, 35 deletions
diff --git a/common-kex.c b/common-kex.c index ac28fa3..5259fce 100644 --- a/common-kex.c +++ b/common-kex.c @@ -944,14 +944,9 @@ static void read_kex_algos() { } #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 --git a/common-session.c b/common-session.c index 99a5470..aa97b65 100644 --- a/common-session.c +++ b/common-session.c @@ -161,7 +161,12 @@ void session_loop(void(*loophandler)()) { /* 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 */ @@ -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 --git a/fuzz-common.c b/fuzz-common.c index bfd2634..cc3d4d6 100644 --- a/fuzz-common.c +++ b/fuzz-common.c @@ -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 load_fixed_hostkeys(void); static void common_setup_fuzzer(void) { fuzz.fuzzing = 1; + fuzz.wrapfds = 1; fuzz.input = m_malloc(sizeof(buffer)); crypto_init(); } @@ -30,7 +29,7 @@ int fuzzer_set_input(const uint8_t *Data, size_t Size) { // 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 @@ static void load_fixed_hostkeys(void) { buf_free(b); } -#endif /* DROPBEAR_FUZZ */ +void fuzz_kex_fakealgos(void) { + ses.newkeys->recv.crypt_mode = &dropbear_mode_none; +} diff --git a/fuzz-harness.c b/fuzz-harness.c index 822d4ac..e3f6617 100644 --- a/fuzz-harness.c +++ b/fuzz-harness.c @@ -8,6 +8,10 @@ int main(int argc, char ** argv) { 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 --git a/fuzz-wrapfd.c b/fuzz-wrapfd.c index 7509afe..62f1c91 100644 --- a/fuzz-wrapfd.c +++ b/fuzz-wrapfd.c @@ -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 int nused; 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 @@ void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) { 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 @@ void wrapfd_remove(int fd) { 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 @@ 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) { + 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 @@ int wrapfd_read(int fd, void *out, size_t count) { 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_read(int fd, void *out, size_t count) { 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_write(int fd, const void* in, size_t count) { } 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 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, } // 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 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, } // 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 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, } return ret; } + diff --git a/fuzz-wrapfd.h b/fuzz-wrapfd.h index d4578b7..a73a7fe 100644 --- a/fuzz-wrapfd.h +++ b/fuzz-wrapfd.h @@ -14,4 +14,10 @@ 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); +// 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 @@ -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 @@ 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); +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 @@ struct dropbear_fuzz_options { // 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 @@ struct dropbear_fuzz_options { extern struct dropbear_fuzz_options fuzz; -#endif +#endif // DROPBEAR_FUZZ #endif /* DROPBEAR_FUZZ_H */ diff --git a/fuzzer-preauth.c b/fuzzer-preauth.c index 7564973..7a56e6a 100644 --- a/fuzzer-preauth.c +++ b/fuzzer-preauth.c @@ -24,6 +24,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (setjmp(fuzz.jmp) == 0) { svr_session(fakesock, fakesock); } else { + TRACE(("dropbear_exit longjmped")) // dropbear_exit jumped here } @@ -133,7 +133,6 @@ #include <tommath.h> #endif - #include "compat.h" #ifndef HAVE_U_INT8_T @@ -164,6 +163,8 @@ typedef u_int32_t uint32_t; #include "fake-rfc2553.h" +#include "fuzz.h" + #ifndef LOG_AUTHPRIV #define LOG_AUTHPRIV LOG_AUTH #endif @@ -195,6 +195,7 @@ void set_connect_fds(fd_set *writefd) { } iter = next_iter; } + TRACE(("leave set_connect_fds")) } void handle_connect_fds(fd_set *writefd) { @@ -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 @@ static int checkmac() { 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) { |