mirror of
https://github.com/clearml/dropbear
synced 2025-04-10 15:35:41 +00:00
fuzz harness
--HG-- branch : fuzz
This commit is contained in:
parent
9f24cdf74c
commit
fb719e3d0b
25
Makefile.in
25
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
78
fuzz-common.c
Normal file
78
fuzz-common.c
Normal file
@ -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 */
|
8
fuzz-harness.c
Normal file
8
fuzz-harness.c
Normal file
@ -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;
|
||||
}
|
35
fuzz.h
Normal file
35
fuzz.h
Normal file
@ -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 */
|
31
fuzzer-preauth.c
Normal file
31
fuzzer-preauth.c
Normal file
@ -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;
|
||||
}
|
3
packet.c
3
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;
|
||||
|
23
runopts.h
23
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;
|
||||
|
@ -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
|
||||
|
@ -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++) {
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user