changeset 1740:dfbe947bdf0d fuzz

Make wrapfd share a common buffer for all FDs
author Matt Johnston <matt@ucc.asn.au>
date Thu, 15 Oct 2020 22:46:24 +0800
parents 13d834efc376
children d1b279aa5ed1
files dbutil.c fuzz-common.c fuzz-harness.c fuzz-wrapfd.c fuzz-wrapfd.h fuzz.h
diffstat 6 files changed, 71 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/dbutil.c	Thu Oct 15 19:55:15 2020 +0800
+++ b/dbutil.c	Thu Oct 15 22:46:24 2020 +0800
@@ -121,7 +121,6 @@
 	_dropbear_log(LOG_INFO, fmtbuf, param);
 
 #if DROPBEAR_FUZZ
-	/* longjmp before cleaning up svr_opts */
     if (fuzz.do_jmp) {
         longjmp(fuzz.jmp, 1);
     }
@@ -258,6 +257,12 @@
 	const int FDIN = 0;
 	const int FDOUT = 1;
 
+#if DROPBEAR_FUZZ
+	if (fuzz.fuzzing) {
+		return fuzz_spawn_command(ret_writefd, ret_readfd, ret_errfd, ret_pid);
+	}
+#endif
+
 	/* redirect stdin/stdout/stderr */
 	if (pipe(infds) != 0) {
 		return DROPBEAR_FAILURE;
--- a/fuzz-common.c	Thu Oct 15 19:55:15 2020 +0800
+++ b/fuzz-common.c	Thu Oct 15 22:46:24 2020 +0800
@@ -36,7 +36,7 @@
 
     memset(&ses, 0x0, sizeof(ses));
     memset(&svr_ses, 0x0, sizeof(svr_ses));
-    wrapfd_setup();
+    wrapfd_setup(fuzz.input);
 
     fuzz_seed();
 
@@ -78,6 +78,29 @@
     load_fixed_hostkeys();
 }
 
+#if 0
+void fuzz_cli_setup(void) {
+    fuzz_common_setup();
+    
+    _dropbear_exit = cli_dropbear_exit;
+
+    char *argv[] = { 
+        "-E", 
+    };
+
+    int argc = sizeof(argv) / sizeof(*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) {
 #include "fuzz-hostkeys.c"   
 
@@ -151,6 +174,17 @@
     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();
+    *ret_readfd = wrapfd_new();
+    if (ret_errfd) {
+        *ret_errfd = wrapfd_new();
+    }
+    ret_pid = 999;
+    return DROPBEAR_SUCCESS;
+}
+
 int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
     static int once = 0;
     if (!once) {
@@ -182,8 +216,7 @@
     uint32_t wrapseed = buf_getint(fuzz.input);
     wrapfd_setseed(wrapseed);
 
-    int fakesock = 20;
-    wrapfd_add(fakesock, fuzz.input, PLAIN);
+    int fakesock = wrapfd_new();
 
     m_malloc_set_epoch(1);
     if (setjmp(fuzz.jmp) == 0) {
--- a/fuzz-harness.c	Thu Oct 15 19:55:15 2020 +0800
+++ b/fuzz-harness.c	Thu Oct 15 22:46:24 2020 +0800
@@ -9,7 +9,6 @@
     buffer *input = buf_new(100000);
 
     for (i = 1; i < argc; i++) {
-        printf("arg %s\n", argv[i]);
 #if DEBUG_TRACE
         if (strcmp(argv[i], "-v") == 0) {
             debug_trace = 1;
--- a/fuzz-wrapfd.c	Thu Oct 15 19:55:15 2020 +0800
+++ b/fuzz-wrapfd.c	Thu Oct 15 22:46:24 2020 +0800
@@ -7,6 +7,8 @@
 #include "fuzz.h"
 
 #define IOWRAP_MAXFD (FD_SETSIZE-1)
+// hopefully above any real fd...
+static const int WRAPFD_STARTFD = 400;
 static const int MAX_RANDOM_IN = 50000;
 static const double CHANCE_CLOSE = 1.0 / 600;
 static const double CHANCE_INTR = 1.0 / 900;
@@ -17,25 +19,21 @@
 
 struct fdwrap {
 	enum wrapfd_mode mode;
-	buffer *buf;
 	int closein;
 	int closeout;
 };
 
 static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
-/* for quick selection of in-use descriptors */
-static int wrap_used[IOWRAP_MAXFD+1];
-static unsigned int nused;
 static unsigned short rand_state[3];
+static buffer *input_buf;
 
-void wrapfd_setup(void) {
+void wrapfd_setup(buffer *buf) {
 	TRACE(("wrapfd_setup"))
-	nused = 0;
 	memset(wrap_fds, 0x0, sizeof(wrap_fds));
-	memset(wrap_used, 0x0, sizeof(wrap_used));
 
 	memset(rand_state, 0x0, sizeof(rand_state));
 	wrapfd_setseed(50);
+	input_buf = buf;
 }
 
 void wrapfd_setseed(uint32_t seed) {
@@ -43,39 +41,29 @@
 	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);
-
-	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++;
+int wrapfd_new() {
+	int fd;
+	// Find a spare file descriptor to use
+	for (fd = WRAPFD_STARTFD; fd < IOWRAP_MAXFD; fd++) {
+		if (wrap_fds[fd].mode == UNUSED) {
+			// check real file descriptors haven't got as far as WRAPFD_STARTFD
+			assert(close(fd) == -1 && errno == EBADF);
+			wrap_fds[fd].mode = COMMONBUF;
+			wrap_fds[fd].closein = 0;
+			wrap_fds[fd].closeout = 0;
+			return fd;
+		}
+	}
+	errno = EMFILE;
+	return -1;
 }
 
 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;
-
-
-	/* remove from used list */
-	for (i = 0, j = 0; i < nused; i++) {
-		if (wrap_used[i] != fd) {
-			wrap_used[j] = wrap_used[i];
-			j++;
-		}
-	}
-	nused--;
 }
 
 int wrapfd_close(int fd) {
@@ -115,15 +103,14 @@
 		return -1;
 	}
 
-	buf = wrap_fds[fd].buf;
-	if (buf) {
-		maxread = MIN(buf->len - buf->pos, count);
+	if (input_buf) {
+		maxread = MIN(input_buf->len - input_buf->pos, count);
 		/* returns 0 if buf is EOF, as intended */
 		if (maxread > 0) {
 			maxread = nrand48(rand_state) % maxread + 1;
 		}
-		memcpy(out, buf_getptr(buf, maxread), maxread);
-		buf_incrpos(buf, maxread);
+		memcpy(out, buf_getptr(input_buf, maxread), maxread);
+		buf_incrpos(input_buf, maxread);
 		return maxread;
 	}
 
--- a/fuzz-wrapfd.h	Thu Oct 15 19:55:15 2020 +0800
+++ b/fuzz-wrapfd.h	Thu Oct 15 22:46:24 2020 +0800
@@ -5,15 +5,13 @@
 
 enum wrapfd_mode {
     UNUSED = 0,
-    PLAIN,
-    INPROGRESS,
-    RANDOMIN
+    COMMONBUF, // using the common buffer
 };
 
-void wrapfd_setup(void);
+// buf is a common buffer read by all wrapped FDs. doesn't take ownership of buf
+void wrapfd_setup(buffer *buf);
 void wrapfd_setseed(uint32_t seed);
-// doesn't take ownership of buf. buf is optional.
-void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
+int wrapfd_new();
 
 // called via #defines for read/write/select
 int wrapfd_read(int fd, void *out, size_t count);
--- a/fuzz.h	Thu Oct 15 19:55:15 2020 +0800
+++ b/fuzz.h	Thu Oct 15 22:46:24 2020 +0800
@@ -31,6 +31,7 @@
 void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
                         char **remote_host, char **remote_port, int host_lookup);
 void fuzz_fake_send_kexdh_reply(void);
+int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid);
 
 // fake IO wrappers
 #ifndef FUZZ_SKIP_WRAP