summaryrefslogtreecommitdiffhomepage
path: root/fuzz-wrapfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz-wrapfd.c')
-rw-r--r--fuzz-wrapfd.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/fuzz-wrapfd.c b/fuzz-wrapfd.c
new file mode 100644
index 0000000..ed8968a
--- /dev/null
+++ b/fuzz-wrapfd.c
@@ -0,0 +1,246 @@
+#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;
+ 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];
+
+void wrapfd_setup(void) {
+ 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);
+}
+
+void wrapfd_setseed(uint32_t seed) {
+ memcpy(rand_state, &seed, sizeof(seed));
+ 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++;
+}
+
+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) {
+ 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;
+ buffer *buf;
+
+ 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;
+ }
+
+ buf = wrap_fds[fd].buf;
+ if (buf) {
+ maxread = MIN(buf->len - 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);
+ 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];
+
+ memset(fdlist, 0x0, sizeof(fdlist));
+
+ 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;
+}
+