summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2017-05-20 13:23:16 +0800
committerMatt Johnston <matt@ucc.asn.au>2017-05-20 13:23:16 +0800
commit5fef5159de5ffa389b5535bd1e59eb3d03ca6c4a (patch)
treefc26adab7954a7b3fc7cff1551a0b02a5c9f822b
parent8bb133a13195c94855b457e30add3755533bc836 (diff)
downloaddropbear-5fef5159de5ffa389b5535bd1e59eb3d03ca6c4a.tar.gz
closer to working
-rw-r--r--common-kex.c11
-rw-r--r--common-session.c7
-rw-r--r--dbrandom.c2
-rw-r--r--fuzz-common.c9
-rw-r--r--fuzz-harness.c4
-rw-r--r--fuzz-wrapfd.c60
-rw-r--r--fuzz-wrapfd.h6
-rw-r--r--fuzz.h22
-rw-r--r--fuzzer-preauth.c1
-rw-r--r--includes.h3
-rw-r--r--netio.c1
-rw-r--r--packet.c12
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 */
diff --git a/dbrandom.c b/dbrandom.c
index f9da8bb..b4b63cc 100644
--- a/dbrandom.c
+++ b/dbrandom.c
@@ -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
diff --git a/fuzz.h b/fuzz.h
index c46ded9..5a1ab3e 100644
--- a/fuzz.h
+++ b/fuzz.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
}
diff --git a/includes.h b/includes.h
index e9fe1fd..b3e1357 100644
--- a/includes.h
+++ b/includes.h
@@ -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
diff --git a/netio.c b/netio.c
index 17693ec..b482431 100644
--- a/netio.c
+++ b/netio.c
@@ -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) {
diff --git a/packet.c b/packet.c
index 235069b..a02cb1b 100644
--- a/packet.c
+++ b/packet.c
@@ -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) {