mirror of
https://github.com/clearml/dropbear
synced 2025-04-09 07:06:39 +00:00
add wrapfd. improve fuzzer in makefile
--HG-- branch : fuzz
This commit is contained in:
parent
4dae8edb76
commit
e7cdb2ebe5
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
193
fuzz-wrapfd.c
Normal file
193
fuzz-wrapfd.c
Normal file
@ -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
fuzz-wrapfd.h
Normal file
17
fuzz-wrapfd.h
Normal file
@ -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
fuzz.h
6
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;
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user