summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2017-05-19 00:48:46 +0800
committerMatt Johnston <matt@ucc.asn.au>2017-05-19 00:48:46 +0800
commite7cdb2ebe5982e4fd881d9ee1e472ad922237b07 (patch)
treea452e928f0798553aa4f27bda068f101c978f897
parent4dae8edb76c3c252b681669c16f978477c633c16 (diff)
add wrapfd. improve fuzzer in makefile
--HG-- branch : fuzz
-rw-r--r--Makefile.in7
-rw-r--r--configure.ac8
-rw-r--r--fuzz-common.c33
-rw-r--r--fuzz-wrapfd.c193
-rw-r--r--fuzz-wrapfd.h17
-rw-r--r--fuzz.h6
-rw-r--r--fuzzer-preauth.c16
7 files changed, 268 insertions, 12 deletions
diff --git a/Makefile.in b/Makefile.in
index 192d8f9..19c747f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,7 +34,7 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
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 @@ CONVERTOBJS=dropbearconvert.o keyimport.o
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 @@ fuzz-hostkeys:
/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 --git a/configure.ac b/configure.ac
index 03a1e4f..9a7fbc9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -223,10 +223,14 @@ AC_ARG_ENABLE(fuzz,
[
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 --git a/fuzz-common.c b/fuzz-common.c
index d9587c9..bfd2634 100644
--- a/fuzz-common.c
+++ b/fuzz-common.c
@@ -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 load_fixed_hostkeys(void);
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 --git a/fuzz-wrapfd.c b/fuzz-wrapfd.c
new file mode 100644
index 0000000..7509afe
--- /dev/null
+++ b/fuzz-wrapfd.c
@@ -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 --git a/fuzz-wrapfd.h b/fuzz-wrapfd.h
new file mode 100644
index 0000000..d4578b7
--- /dev/null
+++ b/fuzz-wrapfd.h
@@ -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 --git a/fuzz.h b/fuzz.h
index e7360e3..c46ded9 100644
--- a/fuzz.h
+++ b/fuzz.h
@@ -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 @@ struct dropbear_fuzz_options {
FILE* recordf;
// fuzzing input
- buffer input;
+ buffer *input;
// dropbear_exit() jumps back
sigjmp_buf jmp;
diff --git a/fuzzer-preauth.c b/fuzzer-preauth.c
index 6a40108..7564973 100644
--- a/fuzzer-preauth.c
+++ b/fuzzer-preauth.c
@@ -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 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
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
}