summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.hgignore2
-rw-r--r--Makefile.in25
-rw-r--r--dbrandom.c7
-rw-r--r--fuzz-common.c78
-rw-r--r--fuzz-harness.c8
-rw-r--r--fuzz-hostkeys.c (renamed from hostkeys.c)0
-rw-r--r--fuzz.h35
-rw-r--r--fuzzer-preauth.c31
-rw-r--r--packet.c3
-rw-r--r--runopts.h23
-rw-r--r--svr-auth.c2
-rw-r--r--svr-runopts.c58
-rw-r--r--svr-session.c13
13 files changed, 191 insertions, 94 deletions
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..3938238
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,2 @@
+.*\.o
+.*~
diff --git a/Makefile.in b/Makefile.in
index 286e25a..d94f87b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -30,7 +30,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
+ gensignkey.o gendss.o genrsa.o fuzz-common.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 \
@@ -224,8 +224,27 @@ distclean: clean tidy
tidy:
-rm -f *~ *.gcov */*~
-# run this manually for fuzzing. hostkeys.c is checked in.
-hostkeys:
+## Fuzzing targets
+
+# exclude svr-main.o to avoid duplicate main
+svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
+CLANG=clang
+
+# fuzzers that don't use libfuzzer, just a standalone harness that feeds inputs
+fuzzstandalone: LIBS+=fuzz-harness.o
+fuzzstandalone: fuzz-harness.o fuzzers
+
+# build all the fuzzers. This will require fail to link unless built with
+# make fuzzers LIBS=-lFuzzer.a
+# or similar - the library provides main().
+fuzzers: fuzzer-preauth
+
+fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+ $(CC) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
+
+# run this to update hardcoded hostkeys for for fuzzing.
+# hostkeys.c is checked in to hg.
+fuzz-hostkeys:
dropbearkey -t rsa -f keyr
dropbearkey -t dss -f keyd
dropbearkey -t ecdsa -size 256 -f keye
diff --git a/dbrandom.c b/dbrandom.c
index f4fc94d..0197411 100644
--- a/dbrandom.c
+++ b/dbrandom.c
@@ -28,6 +28,7 @@
#include "bignum.h"
#include "dbrandom.h"
#include "runopts.h"
+#include "fuzz.h"
/* this is used to generate unique output from the same hashpool */
@@ -147,7 +148,7 @@ void addrandom(unsigned char * buf, unsigned int len)
hash_state hs;
#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing || opts.fuzz.recordf) {
+ if (fuzz.fuzzing || fuzz.recordf) {
return;
}
#endif
@@ -165,7 +166,7 @@ void addrandom(unsigned char * buf, unsigned int len)
static void write_urandom()
{
#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing || opts.fuzz.recordf) {
+ if (fuzz.fuzzing || fuzz.recordf) {
return;
}
#endif
@@ -203,7 +204,7 @@ void seedrandom() {
clock_t clockval;
#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing || opts.fuzz.recordf) {
+ if (fuzz.fuzzing || fuzz.recordf) {
seedfuzz();
return;
}
diff --git a/fuzz-common.c b/fuzz-common.c
new file mode 100644
index 0000000..cc6c125
--- /dev/null
+++ b/fuzz-common.c
@@ -0,0 +1,78 @@
+#include "includes.h"
+
+#ifdef DROPBEAR_FUZZ
+
+#include "includes.h"
+#include "fuzz.h"
+#include "dbutil.h"
+#include "runopts.h"
+
+struct dropbear_fuzz_options fuzz;
+
+static void load_fixed_hostkeys(void);
+
+static void common_setup_fuzzer(void) {
+ fuzz.fuzzing = 1;
+}
+
+void svr_setup_fuzzer(void) {
+ struct passwd *pw;
+
+ common_setup_fuzzer();
+
+ char *argv[] = {
+ "-E",
+ };
+
+ int argc = sizeof(argv) / sizeof(*argv);
+ svr_getopts(argc, argv);
+
+ /* user lookups might be slow, cache it */
+ pw = getpwuid(getuid());
+ dropbear_assert(pw);
+ fuzz.pw_name = m_strdup(pw->pw_name);
+ fuzz.pw_dir = m_strdup(pw->pw_dir);
+ fuzz.pw_shell = m_strdup(pw->pw_shell);
+ fuzz.pw_passwd = m_strdup("!!zzznope");
+
+ load_fixed_hostkeys();
+}
+
+static void load_fixed_hostkeys(void) {
+#include "fuzz-hostkeys.c"
+
+ buffer *b = buf_new(3000);
+ enum signkey_type type;
+
+ TRACE(("load fixed hostkeys"))
+
+ svr_opts.hostkey = new_sign_key();
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keyr, keyr_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_RSA;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed rsa hostkey");
+ }
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keyd, keyd_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_DSS;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed dss hostkey");
+ }
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keye, keye_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed ecdsa hostkey");
+ }
+
+ buf_free(b);
+}
+
+#endif /* DROPBEAR_FUZZ */
diff --git a/fuzz-harness.c b/fuzz-harness.c
new file mode 100644
index 0000000..19b01e3
--- /dev/null
+++ b/fuzz-harness.c
@@ -0,0 +1,8 @@
+#include "includes.h"
+
+extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
+
+int main(int argc, char ** argv) {
+ LLVMFuzzerTestOneInput("hello", 5);
+ return 0;
+}
diff --git a/hostkeys.c b/fuzz-hostkeys.c
index dc1615d..dc1615d 100644
--- a/hostkeys.c
+++ b/fuzz-hostkeys.c
diff --git a/fuzz.h b/fuzz.h
new file mode 100644
index 0000000..e7360e3
--- /dev/null
+++ b/fuzz.h
@@ -0,0 +1,35 @@
+#ifndef DROPBEAR_FUZZ_H
+#define DROPBEAR_FUZZ_H
+
+#include "includes.h"
+#include "buffer.h"
+
+#ifdef DROPBEAR_FUZZ
+
+void svr_setup_fuzzer(void);
+
+struct dropbear_fuzz_options {
+ int fuzzing;
+
+ // to record an unencrypted stream
+ FILE* recordf;
+
+ // fuzzing input
+ buffer input;
+
+ // dropbear_exit() jumps back
+ 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;
+
+#endif
+
+#endif /* DROPBEAR_FUZZ_H */
diff --git a/fuzzer-preauth.c b/fuzzer-preauth.c
new file mode 100644
index 0000000..6a40108
--- /dev/null
+++ b/fuzzer-preauth.c
@@ -0,0 +1,31 @@
+#include "fuzz.h"
+#include "dbrandom.h"
+#include "session.h"
+
+static int setup_fuzzer(void) {
+ svr_setup_fuzzer();
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static int once = 0;
+ if (!once) {
+ setup_fuzzer();
+ once = 1;
+ }
+
+ fuzz.input.data = (unsigned char*)Data;
+ fuzz.input.size = Size;
+ fuzz.input.len = Size;
+ fuzz.input.pos = 0;
+
+ seedrandom();
+
+ if (setjmp(fuzz.jmp) == 0) {
+ svr_session(-1, -1);
+ } else {
+ // dropbear_exit jumped here
+ }
+
+ return 0;
+}
diff --git a/packet.c b/packet.c
index f10e639..235069b 100644
--- a/packet.c
+++ b/packet.c
@@ -36,6 +36,7 @@
#include "channel.h"
#include "netio.h"
#include "runopts.h"
+#include "fuzz.h"
static int read_packet_init(void);
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
@@ -78,7 +79,7 @@ void write_packet() {
calls write_packet() without bothering to test with select() since
it's likely to be necessary */
#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing) {
+ if (fuzz.fuzzing) {
// pretend to write one packet at a time
// TODO(fuzz): randomise amount written based on the fuzz input
written = iov[0].iov_len;
diff --git a/runopts.h b/runopts.h
index 1f51b16..f7c869d 100644
--- a/runopts.h
+++ b/runopts.h
@@ -58,29 +58,6 @@ typedef struct runopts {
char *mac_list;
#endif
-#ifdef DROPBEAR_FUZZ
- struct {
- int fuzzing;
-
- // to record an unencrypted stream
- FILE* recordf;
-
- // fuzzing input
- buffer *input;
-
- // dropbear_exit() jumps back
- sigjmp_buf jmp;
-
- uid_t pw_uid;
- gid_t pw_gid;
- char* pw_name;
- char* pw_dir;
- char* pw_shell;
- char* pw_passwd;
-
- } fuzz;
-#endif
-
} runopts;
extern runopts opts;
diff --git a/svr-auth.c b/svr-auth.c
index d00fa7a..9156d77 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -359,7 +359,7 @@ void send_msg_userauth_failure(int partial, int incrfail) {
/* We delay for 300ms +- 50ms */
delay = 250000 + (delay % 100000);
#ifndef DROPBEAR_FUZZ
- if (!opts.fuzz.fuzzing) {
+ if (!fuzz.fuzzing) {
usleep(delay);
}
#endif
diff --git a/svr-runopts.c b/svr-runopts.c
index c0b7bf2..295b653 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -346,19 +346,6 @@ void svr_getopts(int argc, char ** argv) {
}
opts.idle_timeout_secs = val;
}
-
-#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing) {
- struct passwd *pw;
- /* user lookups might be slow, cache it */
- pw = getpwuid(getuid());
- dropbear_assert(pw);
- opts.fuzz.pw_name = m_strdup(pw->pw_name);
- opts.fuzz.pw_dir = m_strdup(pw->pw_dir);
- opts.fuzz.pw_shell = m_strdup(pw->pw_shell);
- opts.fuzz.pw_passwd = m_strdup("!!zzznope");
- }
-#endif
}
static void addportandaddress(const char* spec) {
@@ -488,57 +475,12 @@ static void addhostkey(const char *keyfile) {
svr_opts.num_hostkey_files++;
}
-#ifdef DROPBEAR_FUZZ
-static void load_fixed_hostkeys() {
-#include "hostkeys.c"
-
- buffer *b = buf_new(3000);
- enum signkey_type type;
-
- TRACE(("load fixed hostkeys"))
-
- svr_opts.hostkey = new_sign_key();
-
- buf_setlen(b, 0);
- buf_putbytes(b, keyr, keyr_len);
- buf_setpos(b, 0);
- type = DROPBEAR_SIGNKEY_RSA;
- if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
- dropbear_exit("failed fixed rsa hostkey");
- }
-
- buf_setlen(b, 0);
- buf_putbytes(b, keyd, keyd_len);
- buf_setpos(b, 0);
- type = DROPBEAR_SIGNKEY_DSS;
- if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
- dropbear_exit("failed fixed dss hostkey");
- }
-
- buf_setlen(b, 0);
- buf_putbytes(b, keye, keye_len);
- buf_setpos(b, 0);
- type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
- if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
- dropbear_exit("failed fixed ecdsa hostkey");
- }
-
- buf_free(b);
-}
-#endif // DROPBEAR_FUZZ
void load_all_hostkeys() {
int i;
int disable_unset_keys = 1;
int any_keys = 0;
-#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing) {
- load_fixed_hostkeys();
- return;
- }
-#endif
-
svr_opts.hostkey = new_sign_key();
for (i = 0; i < svr_opts.num_hostkey_files; i++) {
diff --git a/svr-session.c b/svr-session.c
index 0e6a9e8..41571bb 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -40,6 +40,7 @@
#include "auth.h"
#include "runopts.h"
#include "crypto_desc.h"
+#include "fuzz.h"
static void svr_remoteclosed(void);
@@ -182,6 +183,13 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
session_cleanup();
}
+#ifdef DROPBEAR_FUZZ
+ // longjmp before cleaning up svr_opts
+ if (fuzz.fuzzing) {
+ longjmp(fuzz.jmp, 1);
+ }
+#endif
+
if (svr_opts.hostkey) {
sign_key_free(svr_opts.hostkey);
svr_opts.hostkey = NULL;
@@ -191,11 +199,6 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
m_free(svr_opts.ports[i]);
}
-#ifdef DROPBEAR_FUZZ
- if (opts.fuzz.fuzzing) {
- longjmp(opts.fuzz.jmp, 1);
- }
-#endif
exit(exitcode);