Mercurial > dropbear
view fuzz/fuzz-common.c @ 1857:6022df862942
Use DSCP for IP QoS traffic classes
The previous TOS values are deprecated and not used by modern traffic
classifiers. This sets AF21 for "interactive" traffic (with a tty).
Non-tty traffic sets AF11 - that indicates high throughput but is not
lowest priority (which would be CS1 or LE).
This differs from the CS1 used by OpenSSH, it lets interactive git over SSH
have higher priority than background least effort traffic. Dropbear's settings
here should be suitable with the diffservs used by CAKE qdisc.
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 25 Jan 2022 17:32:20 +0800 |
parents | 19b28d2fbe30 |
children |
line wrap: on
line source
#define FUZZ_NO_REPLACE_STDERR #define FUZZ_NO_REPLACE_GETPW #include "includes.h" #include "includes.h" #include "dbutil.h" #include "runopts.h" #include "crypto_desc.h" #include "session.h" #include "dbrandom.h" #include "bignum.h" #include "atomicio.h" #include "fuzz-wrapfd.h" #include "fuzz.h" struct dropbear_fuzz_options fuzz; static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param); static void load_fixed_hostkeys(void); static void load_fixed_client_key(void); // This runs automatically before main, due to contructor attribute in fuzz.h void fuzz_early_setup(void) { /* Set stderr to point to normal stderr by default */ fuzz.fake_stderr = stderr; } void fuzz_common_setup(void) { disallow_core(); fuzz.fuzzing = 1; fuzz.wrapfds = 1; fuzz.do_jmp = 1; fuzz.input = m_malloc(sizeof(buffer)); _dropbear_log = fuzz_dropbear_log; crypto_init(); fuzz_seed("start", 5); /* let any messages get flushed */ setlinebuf(stdout); #if DEBUG_TRACE if (debug_trace) { fprintf(stderr, "Dropbear fuzzer: -v specified, not disabling stderr output\n"); } else #endif if (getenv("DROPBEAR_KEEP_STDERR")) { fprintf(stderr, "Dropbear fuzzer: DROPBEAR_KEEP_STDERR, not disabling stderr output\n"); } else { fprintf(stderr, "Dropbear fuzzer: Disabling stderr output\n"); fuzz.fake_stderr = fopen("/dev/null", "w"); assert(fuzz.fake_stderr); } } int fuzz_set_input(const uint8_t *Data, size_t Size) { fuzz.input->data = (unsigned char*)Data; fuzz.input->size = Size; fuzz.input->len = Size; fuzz.input->pos = 0; memset(&ses, 0x0, sizeof(ses)); memset(&svr_ses, 0x0, sizeof(svr_ses)); memset(&cli_ses, 0x0, sizeof(cli_ses)); wrapfd_setup(fuzz.input); // printhex("input", fuzz.input->data, fuzz.input->len); fuzz_seed(fuzz.input->data, MIN(fuzz.input->len, 16)); return DROPBEAR_SUCCESS; } #if DEBUG_TRACE static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) { if (debug_trace) { char printbuf[1024]; vsnprintf(printbuf, sizeof(printbuf), format, param); fprintf(stderr, "%s\n", printbuf); } } #else static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) { /* No print */ } #endif /* DEBUG_TRACE */ void fuzz_svr_setup(void) { fuzz_common_setup(); _dropbear_exit = svr_dropbear_exit; char *argv[] = { "dropbear", "-E", }; int argc = sizeof(argv) / sizeof(*argv); svr_getopts(argc, argv); load_fixed_hostkeys(); } void fuzz_svr_hook_preloop() { if (fuzz.svr_postauth) { ses.authstate.authdone = 1; fill_passwd("root"); } } void fuzz_cli_setup(void) { fuzz_common_setup(); _dropbear_exit = cli_dropbear_exit; _dropbear_log = cli_dropbear_log; char *argv[] = { "dbclient", "-y", "localhost", "uptime" }; int argc = sizeof(argv) / sizeof(*argv); cli_getopts(argc, argv); load_fixed_client_key(); /* Avoid password prompt */ setenv(DROPBEAR_PASSWORD_ENV, "password", 1); } #include "fuzz-hostkeys.c" static void load_fixed_client_key(void) { buffer *b = buf_new(3000); sign_key *key; enum signkey_type keytype; key = new_sign_key(); keytype = DROPBEAR_SIGNKEY_ANY; buf_putbytes(b, keyed25519, keyed25519_len); buf_setpos(b, 0); if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed ed25519 hostkey"); } list_append(cli_opts.privkeys, key); buf_free(b); } static void load_fixed_hostkeys(void) { 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_setlen(b, 0); buf_putbytes(b, keyed25519, keyed25519_len); buf_setpos(b, 0); type = DROPBEAR_SIGNKEY_ED25519; if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { dropbear_exit("failed fixed ed25519 hostkey"); } buf_free(b); } void fuzz_kex_fakealgos(void) { ses.newkeys->recv.crypt_mode = &dropbear_mode_none; ses.newkeys->recv.algo_mac = &dropbear_nohash; } void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port, char **remote_host, char **remote_port, int UNUSED(host_lookup)) { if (local_host) { *local_host = m_strdup("fuzzlocalhost"); } if (local_port) { *local_port = m_strdup("1234"); } if (remote_host) { *remote_host = m_strdup("fuzzremotehost"); } if (remote_port) { *remote_port = m_strdup("9876"); } } /* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */ void fuzz_fake_send_kexdh_reply(void) { assert(!ses.dh_K); m_mp_alloc_init_multi(&ses.dh_K, NULL); mp_set_ul(ses.dh_K, 12345678uL); 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_dummy(); *ret_readfd = wrapfd_new_dummy(); if (ret_errfd) { *ret_errfd = wrapfd_new_dummy(); } if (*ret_writefd == -1 || *ret_readfd == -1 || (ret_errfd && *ret_errfd == -1)) { m_close(*ret_writefd); m_close(*ret_readfd); if (ret_errfd) { m_close(*ret_errfd); } return DROPBEAR_FAILURE; } else { *ret_pid = 999; return DROPBEAR_SUCCESS; } } /* Fake dropbear_listen, always returns failure for now. TODO make it sometimes return success with wrapfd_new_dummy() sockets. Making the listeners fake a new incoming connection will be harder. */ /* Listen on address:port. * Special cases are address of "" listening on everything, * and address of NULL listening on localhost only. * Returns the number of sockets bound on success, or -1 on failure. On * failure, if errstring wasn't NULL, it'll be a newly malloced error * string.*/ int fuzz_dropbear_listen(const char* UNUSED(address), const char* UNUSED(port), int *UNUSED(socks), unsigned int UNUSED(sockcount), char **errstring, int *UNUSED(maxfd)) { if (errstring) { *errstring = m_strdup("fuzzing can't listen (yet)"); } return -1; } int fuzz_run_server(const uint8_t *Data, size_t Size, int skip_kexmaths, int postauth) { static int once = 0; if (!once) { fuzz_svr_setup(); fuzz.skip_kexmaths = skip_kexmaths; once = 1; } fuzz.svr_postauth = postauth; if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) { return 0; } uint32_t wrapseed; genrandom((void*)&wrapseed, sizeof(wrapseed)); wrapfd_setseed(wrapseed); int fakesock = wrapfd_new_fuzzinput(); m_malloc_set_epoch(1); fuzz.do_jmp = 1; if (setjmp(fuzz.jmp) == 0) { svr_session(fakesock, fakesock); m_malloc_free_epoch(1, 0); } else { fuzz.do_jmp = 0; m_malloc_free_epoch(1, 1); TRACE(("dropbear_exit longjmped")) /* dropbear_exit jumped here */ } 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; } // Allow to proceed sooner ses.kexstate.donefirstkex = 1; uint32_t wrapseed; genrandom((void*)&wrapseed, sizeof(wrapseed)); wrapfd_setseed(wrapseed); int fakesock = wrapfd_new_fuzzinput(); m_malloc_set_epoch(1); fuzz.do_jmp = 1; if (setjmp(fuzz.jmp) == 0) { cli_session(fakesock, fakesock, NULL, 0); m_malloc_free_epoch(1, 0); } else { fuzz.do_jmp = 0; 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++) { if (strcmp(t->name, name) == 0) { return t->data; } } assert(0); } void fuzz_dump(const unsigned char* data, size_t len) { if (fuzz.dumping) { TRACE(("dump %zu", len)) assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len); } } static struct passwd pwd_root = { .pw_name = "root", .pw_passwd = "!", .pw_uid = 0, .pw_gid = 0, .pw_dir = "/root", .pw_shell = "/bin/sh", }; static struct passwd pwd_other = { .pw_name = "other", .pw_passwd = "!", .pw_uid = 100, .pw_gid = 100, .pw_dir = "/home/other", .pw_shell = "/bin/sh", }; /* oss-fuzz runs fuzzers under minijail, without /etc/passwd. We provide sufficient values for the fuzzers to run */ struct passwd* fuzz_getpwnam(const char *login) { if (!fuzz.fuzzing) { return getpwnam(login); } if (strcmp(login, pwd_other.pw_name) == 0) { return &pwd_other; } if (strcmp(login, pwd_root.pw_name) == 0) { return &pwd_root; } return NULL; } struct passwd* fuzz_getpwuid(uid_t uid) { if (!fuzz.fuzzing) { return getpwuid(uid); } if (uid == pwd_other.pw_uid) { return &pwd_other; } if (uid == pwd_root.pw_uid) { return &pwd_root; } return NULL; }