Skip to content

Commit

Permalink
add wrapfd. improve fuzzer in makefile
Browse files Browse the repository at this point in the history
--HG--
branch : fuzz
  • Loading branch information
mkj committed May 18, 2017
1 parent 4dae8ed commit e7cdb2e
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 12 deletions.
7 changes: 6 additions & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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 \
Expand Down Expand Up @@ -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

8 changes: 6 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions fuzz-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,49 @@
#include "runopts.h"
#include "crypto_desc.h"
#include "session.h"
#include "dbrandom.h"
#include "fuzz-wrapfd.h"

struct dropbear_fuzz_options fuzz;

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;

Expand Down
193 changes: 193 additions & 0 deletions fuzz-wrapfd.c
Original file line number Diff line number Diff line change
@@ -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;
}
17 changes: 17 additions & 0 deletions fuzz-wrapfd.h
Original file line number Diff line number Diff line change
@@ -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
6 changes: 5 additions & 1 deletion fuzz.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@

#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;

// to record an unencrypted stream
FILE* recordf;

// fuzzing input
buffer input;
buffer *input;

// dropbear_exit() jumps back
sigjmp_buf jmp;
Expand Down
16 changes: 8 additions & 8 deletions fuzzer-preauth.c
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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
}
Expand Down

0 comments on commit e7cdb2e

Please sign in to comment.