summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2020-10-18 22:53:44 +0800
committerMatt Johnston <matt@ucc.asn.au>2020-10-18 22:53:44 +0800
commit6ca24af24afe3a3572e9d043df3f8342d38c84b1 (patch)
treeb06b58a6f94bd2827d023f0de10e7f3843a6e28c
parent17873e8c922eded2cec86184673a6d110df6403f (diff)
parent400c7c161f8fd4859f557339f77025044ec950e0 (diff)
Merge fuzz branch
-rw-r--r--Makefile.in28
-rw-r--r--cli-kex.c13
-rw-r--r--cli-main.c57
-rw-r--r--cli-session.c65
-rw-r--r--common-kex.c6
-rw-r--r--dbutil.c7
-rw-r--r--fuzz-common.c89
-rw-r--r--fuzz-harness.c2
-rw-r--r--fuzz-wrapfd.c72
-rw-r--r--fuzz-wrapfd.h10
-rw-r--r--fuzz.h11
-rw-r--r--fuzzer-client.c6
-rw-r--r--fuzzer-client_nomaths.c6
-rw-r--r--session.h2
14 files changed, 244 insertions, 130 deletions
diff --git a/Makefile.in b/Makefile.in
index 145617b..fae4cf3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -268,7 +268,8 @@ lint:
## Fuzzing targets
# list of fuzz targets
-FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
+FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths \
+ fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 fuzzer-client fuzzer-client_nomaths
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
@@ -279,10 +280,7 @@ list-fuzz-targets:
fuzzstandalone: FUZZLIB=fuzz-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets
-# exclude svr-main.o to avoid duplicate main
-svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
-
-fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
+fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(allobjs) fuzz-common.o
# build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a
@@ -290,25 +288,31 @@ fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
- $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+
+fuzzer-client: fuzzer-client.o fuzz-harness.o
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
+
+fuzzer-client_nomaths: fuzzer-client_nomaths.o fuzz-harness.o
+ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-%.options: Makefile
echo "[libfuzzer]" > $@
diff --git a/cli-kex.c b/cli-kex.c
index af1cfcf..4f2a884 100644
--- a/cli-kex.c
+++ b/cli-kex.c
@@ -46,6 +46,13 @@ void send_msg_kexdh_init() {
TRACE(("send_msg_kexdh_init()"))
CHECKCLEARTOWRITE();
+
+#if DROPBEAR_FUZZ
+ if (fuzz.fuzzing && fuzz.skip_kexmaths) {
+ return;
+ }
+#endif
+
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
switch (ses.newkeys->algo_kex->mode) {
#if DROPBEAR_NORMAL_DH
@@ -98,6 +105,12 @@ void recv_msg_kexdh_reply() {
unsigned char* keyblob = NULL;
TRACE(("enter recv_msg_kexdh_reply"))
+
+#if DROPBEAR_FUZZ
+ if (fuzz.fuzzing && fuzz.skip_kexmaths) {
+ return;
+ }
+#endif
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
dropbear_exit("Received out-of-order kexdhreply");
diff --git a/cli-main.c b/cli-main.c
index aabbbcd..7f455d1 100644
--- a/cli-main.c
+++ b/cli-main.c
@@ -31,9 +31,7 @@
#include "dbrandom.h"
#include "crypto_desc.h"
#include "netio.h"
-
-static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
-static void cli_dropbear_log(int priority, const char* format, va_list param);
+#include "fuzz.h"
#if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
@@ -98,58 +96,6 @@ int main(int argc, char ** argv) {
}
#endif /* DBMULTI stuff */
-static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
- char exitmsg[150];
- char fullmsg[300];
-
- /* Note that exit message must be rendered before session cleanup */
-
- /* Render the formatted exit message */
- vsnprintf(exitmsg, sizeof(exitmsg), format, param);
- TRACE(("Exited, cleaning up: %s", exitmsg))
-
- /* Add the prefix depending on session/auth state */
- if (!ses.init_done) {
- snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
- } else {
- snprintf(fullmsg, sizeof(fullmsg),
- "Connection to %s@%s:%s exited: %s",
- cli_opts.username, cli_opts.remotehost,
- cli_opts.remoteport, exitmsg);
- }
-
- /* Do the cleanup first, since then the terminal will be reset */
- session_cleanup();
- /* Avoid printing onwards from terminal cruft */
- fprintf(stderr, "\n");
-
- dropbear_log(LOG_INFO, "%s", fullmsg);
- exit(exitcode);
-}
-
-static void cli_dropbear_log(int priority,
- const char* format, va_list param) {
-
- char printbuf[1024];
- const char *name;
-
- name = cli_opts.progname;
- if (!name) {
- name = "dbclient";
- }
-
- vsnprintf(printbuf, sizeof(printbuf), format, param);
-
-#ifndef DISABLE_SYSLOG
- if (opts.usingsyslog) {
- syslog(priority, "%s", printbuf);
- }
-#endif
-
- fprintf(stderr, "%s: %s\n", name, printbuf);
- fflush(stderr);
-}
-
static void exec_proxy_cmd(const void *user_data_cmd) {
const char *cmd = user_data_cmd;
char *usershell;
@@ -199,4 +145,5 @@ static void kill_proxy_sighandler(int UNUSED(signo)) {
kill_proxy_command();
_exit(1);
}
+
#endif /* DROPBEAR_CLI_PROXYCMD */
diff --git a/cli-session.c b/cli-session.c
index f42ea90..5e5af22 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -352,6 +352,11 @@ static void cli_session_cleanup(void) {
(void)fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
+ /* Don't leak */
+ m_close(cli_ses.stdincopy);
+ m_close(cli_ses.stdoutcopy);
+ m_close(cli_ses.stderrcopy);
+
cli_tty_cleanup();
if (cli_ses.server_sig_algs) {
buf_free(cli_ses.server_sig_algs);
@@ -407,3 +412,63 @@ static void recv_msg_global_request_cli(void) {
/* Send a proper rejection */
send_msg_request_failure();
}
+
+void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
+ char exitmsg[150];
+ char fullmsg[300];
+
+ /* Note that exit message must be rendered before session cleanup */
+
+ /* Render the formatted exit message */
+ vsnprintf(exitmsg, sizeof(exitmsg), format, param);
+ TRACE(("Exited, cleaning up: %s", exitmsg))
+
+ /* Add the prefix depending on session/auth state */
+ if (!ses.init_done) {
+ snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
+ } else {
+ snprintf(fullmsg, sizeof(fullmsg),
+ "Connection to %s@%s:%s exited: %s",
+ cli_opts.username, cli_opts.remotehost,
+ cli_opts.remoteport, exitmsg);
+ }
+
+ /* Do the cleanup first, since then the terminal will be reset */
+ session_cleanup();
+
+#if DROPBEAR_FUZZ
+ if (fuzz.do_jmp) {
+ longjmp(fuzz.jmp, 1);
+ }
+#endif
+
+ /* Avoid printing onwards from terminal cruft */
+ fprintf(stderr, "\n");
+
+ dropbear_log(LOG_INFO, "%s", fullmsg);
+
+ exit(exitcode);
+}
+
+void cli_dropbear_log(int priority, const char* format, va_list param) {
+
+ char printbuf[1024];
+ const char *name;
+
+ name = cli_opts.progname;
+ if (!name) {
+ name = "dbclient";
+ }
+
+ vsnprintf(printbuf, sizeof(printbuf), format, param);
+
+#ifndef DISABLE_SYSLOG
+ if (opts.usingsyslog) {
+ syslog(priority, "%s", printbuf);
+ }
+#endif
+
+ fprintf(stderr, "%s: %s\n", name, printbuf);
+ fflush(stderr);
+}
+
diff --git a/common-kex.c b/common-kex.c
index 4caa06e..39d916b 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -487,6 +487,12 @@ void recv_msg_kexinit() {
TRACE(("continue recv_msg_kexinit: sent kexinit"))
}
+ /* "Once a party has sent a SSH_MSG_KEXINIT message ...
+ further SSH_MSG_KEXINIT messages MUST NOT be sent" */
+ if (ses.kexstate.recvkexinit) {
+ dropbear_exit("Unexpected KEXINIT");
+ }
+
/* start the kex hash */
local_ident_len = strlen(LOCAL_IDENT);
remote_ident_len = strlen(ses.remoteident);
diff --git a/dbutil.c b/dbutil.c
index 32920f7..5af6330 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -121,7 +121,6 @@ static void generic_dropbear_exit(int exitcode, const char* format,
_dropbear_log(LOG_INFO, fmtbuf, param);
#if DROPBEAR_FUZZ
- /* longjmp before cleaning up svr_opts */
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
@@ -258,6 +257,12 @@ int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
const int FDIN = 0;
const int FDOUT = 1;
+#if DROPBEAR_FUZZ
+ if (fuzz.fuzzing) {
+ return fuzz_spawn_command(ret_writefd, ret_readfd, ret_errfd, ret_pid);
+ }
+#endif
+
/* redirect stdin/stdout/stderr */
if (pipe(infds) != 0) {
return DROPBEAR_FAILURE;
diff --git a/fuzz-common.c b/fuzz-common.c
index c14fa66..95b3937 100644
--- a/fuzz-common.c
+++ b/fuzz-common.c
@@ -16,6 +16,7 @@ static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list
static void load_fixed_hostkeys(void);
void fuzz_common_setup(void) {
+ disallow_core();
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
@@ -36,7 +37,8 @@ int fuzz_set_input(const uint8_t *Data, size_t Size) {
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
- wrapfd_setup();
+ memset(&cli_ses, 0x0, sizeof(cli_ses));
+ wrapfd_setup(fuzz.input);
fuzz_seed();
@@ -63,21 +65,32 @@ void fuzz_svr_setup(void) {
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
+ "dropbear",
"-E",
};
int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, argv);
- /* user lookups might be slow, cache it */
- fuzz.pw_name = m_strdup("person");
- fuzz.pw_dir = m_strdup("/tmp");
- fuzz.pw_shell = m_strdup("/bin/zsh");
- fuzz.pw_passwd = m_strdup("!!zzznope");
-
load_fixed_hostkeys();
}
+void fuzz_cli_setup(void) {
+ fuzz_common_setup();
+
+ _dropbear_exit = cli_dropbear_exit;
+ _dropbear_log = cli_dropbear_log;
+
+ char *argv[] = {
+ "dbclient",
+ "-y",
+ "localhost",
+ };
+
+ int argc = sizeof(argv) / sizeof(*argv);
+ cli_getopts(argc, argv);
+}
+
static void load_fixed_hostkeys(void) {
#include "fuzz-hostkeys.c"
@@ -151,6 +164,17 @@ void fuzz_fake_send_kexdh_reply(void) {
finish_kexhashbuf();
}
+/* fake version of spawn_command() */
+int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
+ *ret_writefd = wrapfd_new();
+ *ret_readfd = wrapfd_new();
+ if (ret_errfd) {
+ *ret_errfd = wrapfd_new();
+ }
+ *ret_pid = 999;
+ return DROPBEAR_SUCCESS;
+}
+
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
@@ -164,7 +188,7 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
}
/*
- get prefix. input format is
+ get prefix, allowing for future extensibility. input format is
string prefix
uint32 wrapfd seed
... to be extended later
@@ -182,8 +206,7 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
uint32_t wrapseed = buf_getint(fuzz.input);
wrapfd_setseed(wrapseed);
- int fakesock = 20;
- wrapfd_add(fakesock, fuzz.input, PLAIN);
+ int fakesock = wrapfd_new();
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
@@ -198,6 +221,52 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
return 0;
}
+int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) {
+ static int once = 0;
+ if (!once) {
+ fuzz_cli_setup();
+ fuzz.skip_kexmaths = skip_kexmaths;
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ /*
+ get prefix, allowing for future extensibility. input format is
+ string prefix
+ uint32 wrapfd seed
+ ... to be extended later
+ [bytes] ssh input stream
+ */
+
+ /* be careful to avoid triggering buffer.c assertions */
+ if (fuzz.input->len < 8) {
+ return 0;
+ }
+ size_t prefix_size = buf_getint(fuzz.input);
+ if (prefix_size != 4) {
+ return 0;
+ }
+ uint32_t wrapseed = buf_getint(fuzz.input);
+ wrapfd_setseed(wrapseed);
+
+ int fakesock = wrapfd_new();
+
+ m_malloc_set_epoch(1);
+ if (setjmp(fuzz.jmp) == 0) {
+ cli_session(fakesock, fakesock, NULL, 0);
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
+
const void* fuzz_get_algo(const algo_type *algos, const char* name) {
const algo_type *t;
for (t = algos; t->name; t++) {
diff --git a/fuzz-harness.c b/fuzz-harness.c
index be23d4e..ced707c 100644
--- a/fuzz-harness.c
+++ b/fuzz-harness.c
@@ -9,7 +9,6 @@ int main(int argc, char ** argv) {
buffer *input = buf_new(100000);
for (i = 1; i < argc; i++) {
- printf("arg %s\n", argv[i]);
#if DEBUG_TRACE
if (strcmp(argv[i], "-v") == 0) {
debug_trace = 1;
@@ -30,6 +29,7 @@ int main(int argc, char ** argv) {
buf_readfile(input, fn);
buf_setpos(input, 0);
+ /* Run twice to catch problems with statefulness */
fuzz.wrapfds = old_fuzz_wrapfds;
printf("Running %s once \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
diff --git a/fuzz-wrapfd.c b/fuzz-wrapfd.c
index ed8968a..dfae3c1 100644
--- a/fuzz-wrapfd.c
+++ b/fuzz-wrapfd.c
@@ -17,25 +17,33 @@ static const double CHANCE_WRITE2 = 0.5;
struct fdwrap {
enum wrapfd_mode mode;
- buffer *buf;
int closein;
int closeout;
};
-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 struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {0};
+static int wrapfd_maxfd = -1;
static unsigned short rand_state[3];
+static buffer *input_buf;
+static int devnull_fd = -1;
+
+static void wrapfd_remove(int fd);
-void wrapfd_setup(void) {
+void wrapfd_setup(buffer *buf) {
TRACE(("wrapfd_setup"))
- nused = 0;
- memset(wrap_fds, 0x0, sizeof(wrap_fds));
- memset(wrap_used, 0x0, sizeof(wrap_used));
+
+ // clean old ones
+ int i;
+ for (i = 0; i <= wrapfd_maxfd; i++) {
+ if (wrap_fds[i].mode == COMMONBUF) {
+ wrapfd_remove(i);
+ }
+ }
+ wrapfd_maxfd = -1;
memset(rand_state, 0x0, sizeof(rand_state));
wrapfd_setseed(50);
+ input_buf = buf;
}
void wrapfd_setseed(uint32_t seed) {
@@ -43,39 +51,30 @@ void wrapfd_setseed(uint32_t seed) {
nrand48(rand_state);
}
-void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
- TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
- assert(fd >= 0);
- assert(fd <= IOWRAP_MAXFD);
- assert(wrap_fds[fd].mode == UNUSED);
- assert(buf || mode == RANDOMIN);
+int wrapfd_new() {
+ if (devnull_fd == -1) {
+ devnull_fd = open("/dev/null", O_RDONLY);
+ assert(devnull_fd != -1);
+ }
- wrap_fds[fd].mode = mode;
- wrap_fds[fd].buf = buf;
+ int fd = dup(devnull_fd);
+ assert(fd != -1);
+ assert(wrap_fds[fd].mode == UNUSED);
+ wrap_fds[fd].mode = COMMONBUF;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
- wrap_used[nused] = fd;
+ wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
- nused++;
+ return fd;
}
-void wrapfd_remove(int fd) {
- unsigned int i, j;
+static void wrapfd_remove(int fd) {
TRACE(("wrapfd_remove %d", fd))
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--;
+ m_close(fd);
}
int wrapfd_close(int fd) {
@@ -115,15 +114,14 @@ int wrapfd_read(int fd, void *out, size_t count) {
return -1;
}
- buf = wrap_fds[fd].buf;
- if (buf) {
- maxread = MIN(buf->len - buf->pos, count);
+ if (input_buf) {
+ maxread = MIN(input_buf->len - input_buf->pos, count);
/* returns 0 if buf is EOF, as intended */
if (maxread > 0) {
maxread = nrand48(rand_state) % maxread + 1;
}
- memcpy(out, buf_getptr(buf, maxread), maxread);
- buf_incrpos(buf, maxread);
+ memcpy(out, buf_getptr(input_buf, maxread), maxread);
+ buf_incrpos(input_buf, maxread);
return maxread;
}
@@ -175,8 +173,6 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
int ret = 0;
int fdlist[IOWRAP_MAXFD+1];
- memset(fdlist, 0x0, sizeof(fdlist));
-
if (!fuzz.wrapfds) {
return select(nfds, readfds, writefds, exceptfds, timeout);
}
diff --git a/fuzz-wrapfd.h b/fuzz-wrapfd.h
index 7aed43a..60c66a7 100644
--- a/fuzz-wrapfd.h
+++ b/fuzz-wrapfd.h
@@ -5,15 +5,13 @@
enum wrapfd_mode {
UNUSED = 0,
- PLAIN,
- INPROGRESS,
- RANDOMIN
+ COMMONBUF, // using the common buffer
};
-void wrapfd_setup(void);
+// buf is a common buffer read by all wrapped FDs. doesn't take ownership of buf
+void wrapfd_setup(buffer *buf);
void wrapfd_setseed(uint32_t seed);
-// doesn't take ownership of buf. buf is optional.
-void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
+int wrapfd_new();
// called via #defines for read/write/select
int wrapfd_read(int fd, void *out, size_t count);
diff --git a/fuzz.h b/fuzz.h
index dab6c37..c43f9b1 100644
--- a/fuzz.h
+++ b/fuzz.h
@@ -13,6 +13,7 @@
// once per process
void fuzz_common_setup(void);
void fuzz_svr_setup(void);
+void fuzz_cli_setup(void);
// must be called once per fuzz iteration.
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
@@ -28,9 +29,12 @@ int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const unsigned char* keyblob, unsigned int keybloblen);
extern const char * const * fuzz_signkey_names;
void fuzz_seed(void);
+
+// helpers
void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void fuzz_fake_send_kexdh_reply(void);
+int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid);
// fake IO wrappers
#ifndef FUZZ_SKIP_WRAP
@@ -56,13 +60,6 @@ struct dropbear_fuzz_options {
// dropbear_exit() jumps back
int do_jmp;
sigjmp_buf jmp;
-
- uid_t pw_uid;
- gid_t pw_gid;
- char* pw_name;
- char* pw_dir;
- char* pw_shell;
- char* pw_passwd;
};
extern struct dropbear_fuzz_options fuzz;
diff --git a/fuzzer-client.c b/fuzzer-client.c
new file mode 100644
index 0000000..eb59f46
--- /dev/null
+++ b/fuzzer-client.c
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return fuzz_run_client(Data, Size, 0);
+}
+
diff --git a/fuzzer-client_nomaths.c b/fuzzer-client_nomaths.c
new file mode 100644
index 0000000..e0910a7
--- /dev/null
+++ b/fuzzer-client_nomaths.c
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return fuzz_run_client(Data, Size, 1);
+}
+
diff --git a/session.h b/session.h
index 9b8edda..fb5b8cb 100644
--- a/session.h
+++ b/session.h
@@ -64,6 +64,8 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress, pid_t proxy_cmd_pid) ATTRIB_NORETURN;
void cli_connected(int result, int sock, void* userdata, const char *errstring);
+void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
+void cli_dropbear_log(int priority, const char* format, va_list param);
void cleantext(char* dirtytext);
void kill_proxy_command(void);