diff fuzz/fuzz-wrapfd.c @ 1756:d5680e12ac33

Move fuzzing code to fuzz/ subdirectory, improve Makefile.in
author Matt Johnston <matt@ucc.asn.au>
date Fri, 23 Oct 2020 23:10:20 +0800
parents fuzz-wrapfd.c@28ab2cdb84bf
children 97ad26e397a5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzz/fuzz-wrapfd.c	Fri Oct 23 23:10:20 2020 +0800
@@ -0,0 +1,241 @@
+#define FUZZ_SKIP_WRAP 1
+#include "includes.h"
+#include "fuzz-wrapfd.h"
+
+#include "dbutil.h"
+
+#include "fuzz.h"
+
+#define IOWRAP_MAXFD (FD_SETSIZE-1)
+static const int MAX_RANDOM_IN = 50000;
+static const double CHANCE_CLOSE = 1.0 / 600;
+static const double CHANCE_INTR = 1.0 / 900;
+static const double CHANCE_READ1 = 0.96;
+static const double CHANCE_READ2 = 0.5;
+static const double CHANCE_WRITE1 = 0.96;
+static const double CHANCE_WRITE2 = 0.5;
+
+struct fdwrap {
+	enum wrapfd_mode mode;
+	int closein;
+	int closeout;
+};
+
+static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
+static int wrapfd_maxfd = -1;
+static unsigned short rand_state[3];
+static buffer *input_buf;
+static int devnull_fd = -1;
+
+static void wrapfd_remove(int fd);
+
+void wrapfd_setup(buffer *buf) {
+	TRACE(("wrapfd_setup"))
+
+	// clean old ones
+	int i;
+	for (i = 0; i <= wrapfd_maxfd; i++) {
+		if (wrap_fds[i].mode == COMMONBUF) {
+			wrapfd_remove(i);
+		}
+	}
+	wrapfd_maxfd = -1;
+
+	memset(rand_state, 0x0, sizeof(rand_state));
+	wrapfd_setseed(50);
+	input_buf = buf;
+}
+
+void wrapfd_setseed(uint32_t seed) {
+	memcpy(rand_state, &seed, sizeof(seed));
+	nrand48(rand_state);
+}
+
+int wrapfd_new() {
+	if (devnull_fd == -1) {
+		devnull_fd = open("/dev/null", O_RDONLY);
+		assert(devnull_fd != -1);
+	}
+
+	int fd = dup(devnull_fd);
+	assert(fd != -1);
+	assert(wrap_fds[fd].mode == UNUSED);
+	wrap_fds[fd].mode = COMMONBUF;
+	wrap_fds[fd].closein = 0;
+	wrap_fds[fd].closeout = 0;
+	wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
+
+	return fd;
+}
+
+static void wrapfd_remove(int fd) {
+	TRACE(("wrapfd_remove %d", fd))
+	assert(fd >= 0);
+	assert(fd <= IOWRAP_MAXFD);
+	assert(wrap_fds[fd].mode != UNUSED);
+	wrap_fds[fd].mode = UNUSED;
+	m_close(fd);
+}
+
+int wrapfd_close(int fd) {
+	if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
+		wrapfd_remove(fd);
+		return 0;
+	} else {
+		return close(fd);
+	}
+}
+
+int wrapfd_read(int fd, void *out, size_t count) {
+	size_t maxread;
+
+	if (!fuzz.wrapfds) {
+		return read(fd, out, count);
+	}
+
+	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
+		/* XXX - assertion failure? */
+		TRACE(("Bad read descriptor %d\n", fd))
+		errno = EBADF;
+		return -1;
+	}
+
+	assert(count != 0);
+
+	if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
+		wrap_fds[fd].closein = 1;
+		errno = ECONNRESET;
+		return -1;
+	}
+
+	if (erand48(rand_state) < CHANCE_INTR) {
+		errno = EINTR;
+		return -1;
+	}
+
+	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(input_buf, maxread), maxread);
+		buf_incrpos(input_buf, maxread);
+		return maxread;
+	}
+
+	maxread = MIN(MAX_RANDOM_IN, count);
+	maxread = nrand48(rand_state) % maxread + 1;
+	memset(out, 0xef, maxread);
+	return maxread;
+}
+
+int wrapfd_write(int fd, const void* in, size_t count) {
+	unsigned const volatile char* volin = in;
+	unsigned int i;
+
+	if (!fuzz.wrapfds) {
+		return write(fd, in, count);
+	}
+
+	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
+		/* XXX - assertion failure? */
+		TRACE(("Bad read descriptor %d\n", fd))
+		errno = EBADF;
+		return -1;
+	}
+
+	assert(count != 0);
+
+	/* force read to exercise sanitisers */
+	for (i = 0; i < count; i++) {
+		(void)volin[i];
+	}
+
+	if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
+		wrap_fds[fd].closeout = 1;
+		errno = ECONNRESET;
+		return -1;
+	}
+
+	if (erand48(rand_state) < CHANCE_INTR) {
+		errno = EINTR;
+		return -1;
+	}
+
+	return nrand48(rand_state) % (count+1);
+}
+
+int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, 
+	fd_set *exceptfds, struct timeval *timeout) {
+	int i, nset, sel;
+	int ret = 0;
+	int fdlist[IOWRAP_MAXFD+1];
+
+	if (!fuzz.wrapfds) {
+		return select(nfds, readfds, writefds, exceptfds, timeout);
+	}
+
+	assert(nfds <= IOWRAP_MAXFD+1);
+
+	if (erand48(rand_state) < CHANCE_INTR) {
+		errno = EINTR;
+		return -1;
+	}
+
+	/* read */
+	if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
+		for (i = 0, nset = 0; i < nfds; i++) {
+			if (FD_ISSET(i, readfds)) {
+				assert(wrap_fds[i].mode != UNUSED);
+				fdlist[nset] = i;
+				nset++;
+			}
+		}
+		DROPBEAR_FD_ZERO(readfds);
+
+		if (nset > 0) {
+			/* set one */
+			sel = fdlist[nrand48(rand_state) % nset];
+			FD_SET(sel, readfds);
+			ret++;
+
+			if (erand48(rand_state) < CHANCE_READ2) {
+				sel = fdlist[nrand48(rand_state) % nset];
+				if (!FD_ISSET(sel, readfds)) {
+					FD_SET(sel, readfds);
+					ret++;
+				}
+			}
+		}
+	}
+
+	/* write */
+	if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
+		for (i = 0, nset = 0; i < nfds; i++) {
+			if (FD_ISSET(i, writefds)) {
+				assert(wrap_fds[i].mode != UNUSED);
+				fdlist[nset] = i;
+				nset++;
+			}
+		}
+		DROPBEAR_FD_ZERO(writefds);
+
+		/* set one */
+		if (nset > 0) {
+			sel = fdlist[nrand48(rand_state) % nset];
+			FD_SET(sel, writefds);
+			ret++;
+
+			if (erand48(rand_state) < CHANCE_WRITE2) {
+				sel = fdlist[nrand48(rand_state) % nset];
+				if (!FD_ISSET(sel, writefds)) {
+					FD_SET(sel, writefds);
+					ret++;
+				}
+			}
+		}
+	}
+	return ret;
+}
+