diff --git a/common-channel.c b/common-channel.c index 7383f47a2666bb7f79f39b4514631a56e773d99f..14985a97f200c549050155985c3b034ff5c8ddd0 100644 --- a/common-channel.c +++ b/common-channel.c @@ -88,6 +88,10 @@ void chancleanup() { unsigned int i; + if (!ses.channels) { + return; + } + TRACE(("enter chancleanup")) for (i = 0; i < ses.chansize; i++) { if (ses.channels[i] != NULL) { diff --git a/common-kex.c b/common-kex.c index 5259fceaa238c1f0ea75437dc89ee7a1aeab62ea..a95182c957a184724b84433de5e2f052c4271882 100644 --- a/common-kex.c +++ b/common-kex.c @@ -403,6 +403,7 @@ static void gen_new_zstream_recv() { ses.newkeys->recv.zstream->zfree = Z_NULL; if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) { + m_free(ses.newkeys->recv.zstream); dropbear_exit("zlib error"); } } else { diff --git a/common-session.c b/common-session.c index aa97b6516579c49e78192ca36fb4b3459ef6bb6b..aa0dddb82fd7a0020fd6c171d0ed7dc75d1d35ac 100644 --- a/common-session.c +++ b/common-session.c @@ -82,14 +82,18 @@ void common_session_init(int sock_in, int sock_out) { ses.last_packet_time_any_sent = 0; ses.last_packet_time_keepalive_sent = 0; - if (pipe(ses.signal_pipe) < 0) { - dropbear_exit("Signal pipe failed"); +#ifdef DROPBEAR_FUZZ + if (!fuzz.fuzzing) +#endif + { + if (pipe(ses.signal_pipe) < 0) { + dropbear_exit("Signal pipe failed"); + } + setnonblocking(ses.signal_pipe[0]); + setnonblocking(ses.signal_pipe[1]); + ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]); + ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]); } - setnonblocking(ses.signal_pipe[0]); - setnonblocking(ses.signal_pipe[1]); - - ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]); - ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]); ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN); ses.transseq = 0; @@ -311,6 +315,16 @@ void session_cleanup() { buf_free(dequeue(&ses.writequeue)); } + m_free(ses.newkeys); +#ifndef DISABLE_ZLIB + if (ses.keys->recv.zstream != NULL) { + if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) { + dropbear_exit("Crypto error"); + } + m_free(ses.keys->recv.zstream); + } +#endif + m_free(ses.remoteident); m_free(ses.authstate.pw_dir); m_free(ses.authstate.pw_name); diff --git a/dbrandom.c b/dbrandom.c index b4b63ccaa6f1bb7f943ac15205290fada19181f0..bb9c4c8e960319c6a1b833aef7da4bf62c884aca 100644 --- a/dbrandom.c +++ b/dbrandom.c @@ -181,7 +181,8 @@ static void write_urandom() #endif } -static void seedfuzz(void) { +#ifdef DROPBEAR_FUZZ +void seedfuzz(void) { hash_state hs; sha1_init(&hs); sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz")); @@ -190,6 +191,7 @@ static void seedfuzz(void) { counter = 0; donerandinit = 1; } +#endif /* Initialise the prng from /dev/urandom or prngd. This function can * be called multiple times */ @@ -203,7 +205,6 @@ void seedrandom() { #ifdef DROPBEAR_FUZZ if (fuzz.fuzzing || fuzz.recordf) { - seedfuzz(); return; } #endif diff --git a/dbutil.c b/dbutil.c index 830e8d278e16a36bbbdbaa95b259c8ae97cb4c96..4c835a49f932e42cf09ef092e395d743ce5a9c55 100644 --- a/dbutil.c +++ b/dbutil.c @@ -569,7 +569,16 @@ void setnonblocking(int fd) { * can't be set to non-blocking */ TRACE(("ignoring ENODEV for setnonblocking")) } else { - dropbear_exit("Couldn't set nonblocking"); +#ifdef DROPBEAR_FUZZ + if (fuzz.fuzzing) + { + TRACE(("fuzzing ignore setnonblocking failure for %d", fd)) + } + else +#endif + { + dropbear_exit("Couldn't set nonblocking"); + } } } TRACE(("leave setnonblocking")) diff --git a/debug.h b/debug.h index 93fbc1f3d9027613c9936b45f095c8f3e7ceef6b..0cd611dae46e3f3c88f4f1195bfb542783e69ca0 100644 --- a/debug.h +++ b/debug.h @@ -64,6 +64,7 @@ /* you don't need to touch this block */ #if DEBUG_TRACE +extern int debug_trace; #define TRACE(X) dropbear_trace X; #define TRACE2(X) dropbear_trace2 X; #else /*DEBUG_TRACE*/ diff --git a/fuzz-common.c b/fuzz-common.c index cc3d4d64b13b0629f8faae4fc6ffa814f2107a2d..144bf145ac95515bb8ad9711624fc407d2ad02d0 100644 --- a/fuzz-common.c +++ b/fuzz-common.c @@ -27,6 +27,9 @@ int fuzzer_set_input(const uint8_t *Data, size_t Size) { fuzz.input->len = Size; fuzz.input->pos = 0; + memset(&ses, 0x0, sizeof(ses)); + memset(&svr_ses, 0x0, sizeof(svr_ses)); + // get prefix. input format is // string prefix // uint32 wrapfd seed @@ -44,7 +47,7 @@ int fuzzer_set_input(const uint8_t *Data, size_t Size) { uint32_t wrapseed = buf_getint(fuzz.input); wrapfd_setup(wrapseed); - seedrandom(); + seedfuzz(); return DROPBEAR_SUCCESS; } diff --git a/fuzz-harness.c b/fuzz-harness.c index e3f661794b0df9a5eb4a70b5b0eaacb1fde7785d..c31d2b77b1b92fcdc19c3877b9bcab82a083ed21 100644 --- a/fuzz-harness.c +++ b/fuzz-harness.c @@ -18,7 +18,9 @@ int main(int argc, char ** argv) { buf_readfile(input, fn); buf_setpos(input, 0); - printf("Running %s\n", fn); + printf("Running %s once \n", fn); + LLVMFuzzerTestOneInput(input->data, input->len); + printf("Running %s twice \n", fn); LLVMFuzzerTestOneInput(input->data, input->len); printf("Done %s\n", fn); } diff --git a/fuzz-wrapfd.c b/fuzz-wrapfd.c index 62f1c914edccba26809a6ec631545ba59a5a5388..215eb166ddd22392f307dc32f25ca6afa909148b 100644 --- a/fuzz-wrapfd.c +++ b/fuzz-wrapfd.c @@ -16,6 +16,8 @@ static const double CHANCE_WRITE2 = 0.3; struct fdwrap { enum wrapfd_mode mode; buffer *buf; + int closein; + int closeout; }; static struct fdwrap wrap_fds[IOWRAP_MAXFD+1]; @@ -28,21 +30,25 @@ void wrapfd_setup(uint32_t seed) { TRACE(("wrapfd_setup %x", seed)) nused = 0; memset(wrap_fds, 0x0, sizeof(wrap_fds)); + memset(wrap_used, 0x0, sizeof(wrap_used)); + memset(rand_state, 0x0, sizeof(rand_state)); *((uint32_t*)rand_state) = 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); - TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode)) wrap_fds[fd].mode = mode; wrap_fds[fd].buf = buf; + wrap_fds[fd].closein = 0; + wrap_fds[fd].closeout = 0; wrap_used[nused] = fd; nused++; @@ -50,12 +56,12 @@ void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) { void wrapfd_remove(int fd) { unsigned int i, j; + TRACE(("wrapfd_remove %d", fd)) assert(fd >= 0); assert(fd <= IOWRAP_MAXFD); 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++) { @@ -67,6 +73,9 @@ void wrapfd_remove(int fd) { nused--; } +void wrapfd_close(int fd) { + wrapfd_remove(fd); +} int wrapfd_read(int fd, void *out, size_t count) { size_t maxread; @@ -85,9 +94,10 @@ int wrapfd_read(int fd, void *out, size_t count) { assert(count != 0); - if (erand48(rand_state) < CHANCE_CLOSE) { - wrapfd_remove(fd); - return 0; + if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) { + wrap_fds[fd].closein = 1; + errno = ECONNRESET; + return -1; } if (erand48(rand_state) < CHANCE_INTR) { @@ -135,9 +145,10 @@ int wrapfd_write(int fd, const void* in, size_t count) { (void)volin[i]; } - if (erand48(rand_state) < CHANCE_CLOSE) { - wrapfd_remove(fd); - return 0; + if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) { + wrap_fds[fd].closeout = 1; + errno = ECONNRESET; + return -1; } if (erand48(rand_state) < CHANCE_INTR) { diff --git a/fuzz.h b/fuzz.h index 5a1ab3e7bd8a5a25eb24c4316efa98366cca9678..d0e13b3de341d3d028b90fe4a18fd10db18a8df9 100644 --- a/fuzz.h +++ b/fuzz.h @@ -23,6 +23,7 @@ void fuzz_kex_fakealgos(void); 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) +#define close(fd) wrapfd_close(fd) #endif // FUZZ_SKIP_WRAP struct dropbear_fuzz_options { diff --git a/fuzzer-preauth.c b/fuzzer-preauth.c index 7a56e6a85e5fe82e37c2b1e246efa64676e578fe..9ca7b842d998495aed17c85b50ee63f450336af1 100644 --- a/fuzzer-preauth.c +++ b/fuzzer-preauth.c @@ -2,9 +2,11 @@ #include "dbrandom.h" #include "session.h" #include "fuzz-wrapfd.h" +#include "debug.h" static void setup_fuzzer(void) { svr_setup_fuzzer(); + //debug_trace = 1; } int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { diff --git a/svr-session.c b/svr-session.c index 8cb0ea9b7ab7188620fd325351ca6df097a2edbf..a1466fe0186f849952f9aa6d0bf0c7c88fd49340 100644 --- a/svr-session.c +++ b/svr-session.c @@ -245,7 +245,9 @@ void svr_dropbear_log(int priority, const char* format, va_list param) { static void svr_remoteclosed() { m_close(ses.sock_in); - m_close(ses.sock_out); + if (ses.sock_in != ses.sock_out) { + m_close(ses.sock_out); + } ses.sock_in = -1; ses.sock_out = -1; dropbear_close("Exited normally");