Get client fuzzer building and starting (fails straight away)

--HG--
branch : fuzz
This commit is contained in:
Matt Johnston 2020-10-18 12:17:39 +08:00
parent cc1b07dcf1
commit 282fc81981
8 changed files with 138 additions and 93 deletions

View File

@ -268,7 +268,8 @@ lint:
## Fuzzing targets ## Fuzzing targets
# list of fuzz 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_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS)) FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
@ -279,10 +280,7 @@ list-fuzz-targets:
fuzzstandalone: FUZZLIB=fuzz-harness.o fuzzstandalone: FUZZLIB=fuzz-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets fuzzstandalone: fuzz-harness.o fuzz-targets
# exclude svr-main.o to avoid duplicate main fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(allobjs) fuzz-common.o
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
# build all the fuzzers. This will require fail to link unless built with # build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a # make fuzz-targets FUZZLIB=-lFuzzer.a
@ -290,25 +288,28 @@ fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS) fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o 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 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 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 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 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 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 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-%.options: Makefile fuzzer-%.options: Makefile
echo "[libfuzzer]" > $@ echo "[libfuzzer]" > $@

View File

@ -31,9 +31,7 @@
#include "dbrandom.h" #include "dbrandom.h"
#include "crypto_desc.h" #include "crypto_desc.h"
#include "netio.h" #include "netio.h"
#include "fuzz.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);
#if DROPBEAR_CLI_PROXYCMD #if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out); 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 */ #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) { static void exec_proxy_cmd(const void *user_data_cmd) {
const char *cmd = user_data_cmd; const char *cmd = user_data_cmd;
char *usershell; char *usershell;
@ -199,4 +145,5 @@ static void kill_proxy_sighandler(int UNUSED(signo)) {
kill_proxy_command(); kill_proxy_command();
_exit(1); _exit(1);
} }
#endif /* DROPBEAR_CLI_PROXYCMD */ #endif /* DROPBEAR_CLI_PROXYCMD */

View File

@ -407,3 +407,62 @@ static void recv_msg_global_request_cli(void) {
/* Send a proper rejection */ /* Send a proper rejection */
send_msg_request_failure(); 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();
/* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n");
dropbear_log(LOG_INFO, "%s", fullmsg);
#if DROPBEAR_FUZZ
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
#endif
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);
}

View File

@ -16,6 +16,7 @@ static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list
static void load_fixed_hostkeys(void); static void load_fixed_hostkeys(void);
void fuzz_common_setup(void) { void fuzz_common_setup(void) {
disallow_core();
fuzz.fuzzing = 1; fuzz.fuzzing = 1;
fuzz.wrapfds = 1; fuzz.wrapfds = 1;
fuzz.do_jmp = 1; fuzz.do_jmp = 1;
@ -69,37 +70,23 @@ void fuzz_svr_setup(void) {
int argc = sizeof(argv) / sizeof(*argv); int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, 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(); load_fixed_hostkeys();
} }
#if 0
void fuzz_cli_setup(void) { void fuzz_cli_setup(void) {
fuzz_common_setup(); fuzz_common_setup();
_dropbear_exit = cli_dropbear_exit; _dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
char *argv[] = { char *argv[] = {
"-E", "-y",
"localhost",
}; };
int argc = sizeof(argv) / sizeof(*argv); int argc = sizeof(argv) / sizeof(*argv);
cli_getopts(argc, argv); cli_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();
} }
#endif
static void load_fixed_hostkeys(void) { static void load_fixed_hostkeys(void) {
#include "fuzz-hostkeys.c" #include "fuzz-hostkeys.c"
@ -198,7 +185,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 string prefix
uint32 wrapfd seed uint32 wrapfd seed
... to be extended later ... to be extended later
@ -231,6 +218,52 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
return 0; 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 void* fuzz_get_algo(const algo_type *algos, const char* name) {
const algo_type *t; const algo_type *t;
for (t = algos; t->name; t++) { for (t = algos; t->name; t++) {

View File

@ -29,6 +29,7 @@ int main(int argc, char ** argv) {
buf_readfile(input, fn); buf_readfile(input, fn);
buf_setpos(input, 0); buf_setpos(input, 0);
/* Run twice to catch problems with statefulness */
fuzz.wrapfds = old_fuzz_wrapfds; fuzz.wrapfds = old_fuzz_wrapfds;
printf("Running %s once \n", fn); printf("Running %s once \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len); LLVMFuzzerTestOneInput(input->data, input->len);

10
fuzz.h
View File

@ -13,6 +13,7 @@
// once per process // once per process
void fuzz_common_setup(void); void fuzz_common_setup(void);
void fuzz_svr_setup(void); void fuzz_svr_setup(void);
void fuzz_cli_setup(void);
// must be called once per fuzz iteration. // must be called once per fuzz iteration.
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE // returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
@ -28,6 +29,8 @@ int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const unsigned char* keyblob, unsigned int keybloblen); const unsigned char* keyblob, unsigned int keybloblen);
extern const char * const * fuzz_signkey_names; extern const char * const * fuzz_signkey_names;
void fuzz_seed(void); void fuzz_seed(void);
// helpers
void fuzz_get_socket_address(int fd, char **local_host, char **local_port, void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup); char **remote_host, char **remote_port, int host_lookup);
void fuzz_fake_send_kexdh_reply(void); void fuzz_fake_send_kexdh_reply(void);
@ -57,13 +60,6 @@ struct dropbear_fuzz_options {
// dropbear_exit() jumps back // dropbear_exit() jumps back
int do_jmp; int do_jmp;
sigjmp_buf 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; extern struct dropbear_fuzz_options fuzz;

6
fuzzer-client.c Normal file
View File

@ -0,0 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_client(Data, Size, 0);
}

View File

@ -64,6 +64,8 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */ /* Client */
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress, pid_t proxy_cmd_pid) ATTRIB_NORETURN; 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_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 cleantext(char* dirtytext);
void kill_proxy_command(void); void kill_proxy_command(void);