1 #define FUZZ_SKIP_WRAP 1
2 #include "includes.h"
3 #include "fuzz-wrapfd.h"
4 
5 #include "dbutil.h"
6 
7 #include "fuzz.h"
8 
9 #define IOWRAP_MAXFD (FD_SETSIZE-1)
10 static const int MAX_RANDOM_IN = 50000;
11 static const double CHANCE_CLOSE = 1.0 / 600;
12 static const double CHANCE_INTR = 1.0 / 900;
13 static const double CHANCE_READ1 = 0.96;
14 static const double CHANCE_READ2 = 0.5;
15 static const double CHANCE_WRITE1 = 0.96;
16 static const double CHANCE_WRITE2 = 0.5;
17 
18 struct fdwrap {
19 	enum wrapfd_mode mode;
20 	int closein;
21 	int closeout;
22 };
23 
24 static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
25 static int wrapfd_maxfd = -1;
26 static unsigned short rand_state[3];
27 static buffer *input_buf;
28 static int devnull_fd = -1;
29 
30 static void wrapfd_remove(int fd);
31 
wrapfd_setup(buffer * buf)32 void wrapfd_setup(buffer *buf) {
33 	TRACE(("wrapfd_setup"))
34 
35 	// clean old ones
36 	int i;
37 	for (i = 0; i <= wrapfd_maxfd; i++) {
38 		if (wrap_fds[i].mode == COMMONBUF) {
39 			wrapfd_remove(i);
40 		}
41 	}
42 	wrapfd_maxfd = -1;
43 
44 	memset(rand_state, 0x0, sizeof(rand_state));
45 	wrapfd_setseed(50);
46 	input_buf = buf;
47 }
48 
wrapfd_setseed(uint32_t seed)49 void wrapfd_setseed(uint32_t seed) {
50 	memcpy(rand_state, &seed, sizeof(seed));
51 	nrand48(rand_state);
52 }
53 
wrapfd_new()54 int wrapfd_new() {
55 	if (devnull_fd == -1) {
56 		devnull_fd = open("/dev/null", O_RDONLY);
57 		assert(devnull_fd != -1);
58 	}
59 
60 	int fd = dup(devnull_fd);
61 	assert(fd != -1);
62 	assert(wrap_fds[fd].mode == UNUSED);
63 	wrap_fds[fd].mode = COMMONBUF;
64 	wrap_fds[fd].closein = 0;
65 	wrap_fds[fd].closeout = 0;
66 	wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
67 
68 	return fd;
69 }
70 
wrapfd_remove(int fd)71 static void wrapfd_remove(int fd) {
72 	TRACE(("wrapfd_remove %d", fd))
73 	assert(fd >= 0);
74 	assert(fd <= IOWRAP_MAXFD);
75 	assert(wrap_fds[fd].mode != UNUSED);
76 	wrap_fds[fd].mode = UNUSED;
77 	m_close(fd);
78 }
79 
wrapfd_close(int fd)80 int wrapfd_close(int fd) {
81 	if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
82 		wrapfd_remove(fd);
83 		return 0;
84 	} else {
85 		return close(fd);
86 	}
87 }
88 
wrapfd_read(int fd,void * out,size_t count)89 int wrapfd_read(int fd, void *out, size_t count) {
90 	size_t maxread;
91 
92 	if (!fuzz.wrapfds) {
93 		return read(fd, out, count);
94 	}
95 
96 	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
97 		/* XXX - assertion failure? */
98 		TRACE(("Bad read descriptor %d\n", fd))
99 		errno = EBADF;
100 		return -1;
101 	}
102 
103 	assert(count != 0);
104 
105 	if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
106 		wrap_fds[fd].closein = 1;
107 		errno = ECONNRESET;
108 		return -1;
109 	}
110 
111 	if (erand48(rand_state) < CHANCE_INTR) {
112 		errno = EINTR;
113 		return -1;
114 	}
115 
116 	if (input_buf) {
117 		maxread = MIN(input_buf->len - input_buf->pos, count);
118 		/* returns 0 if buf is EOF, as intended */
119 		if (maxread > 0) {
120 			maxread = nrand48(rand_state) % maxread + 1;
121 		}
122 		memcpy(out, buf_getptr(input_buf, maxread), maxread);
123 		buf_incrpos(input_buf, maxread);
124 		return maxread;
125 	}
126 
127 	maxread = MIN(MAX_RANDOM_IN, count);
128 	maxread = nrand48(rand_state) % maxread + 1;
129 	memset(out, 0xef, maxread);
130 	return maxread;
131 }
132 
wrapfd_write(int fd,const void * in,size_t count)133 int wrapfd_write(int fd, const void* in, size_t count) {
134 	unsigned const volatile char* volin = in;
135 	unsigned int i;
136 
137 	if (!fuzz.wrapfds) {
138 		return write(fd, in, count);
139 	}
140 
141 	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
142 		/* XXX - assertion failure? */
143 		TRACE(("Bad read descriptor %d\n", fd))
144 		errno = EBADF;
145 		return -1;
146 	}
147 
148 	assert(count != 0);
149 
150 	/* force read to exercise sanitisers */
151 	for (i = 0; i < count; i++) {
152 		(void)volin[i];
153 	}
154 
155 	if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
156 		wrap_fds[fd].closeout = 1;
157 		errno = ECONNRESET;
158 		return -1;
159 	}
160 
161 	if (erand48(rand_state) < CHANCE_INTR) {
162 		errno = EINTR;
163 		return -1;
164 	}
165 
166 	return nrand48(rand_state) % (count+1);
167 }
168 
wrapfd_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)169 int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
170 	fd_set *exceptfds, struct timeval *timeout) {
171 	int i, nset, sel;
172 	int ret = 0;
173 	int fdlist[IOWRAP_MAXFD+1];
174 
175 	if (!fuzz.wrapfds) {
176 		return select(nfds, readfds, writefds, exceptfds, timeout);
177 	}
178 
179 	assert(nfds <= IOWRAP_MAXFD+1);
180 
181 	if (erand48(rand_state) < CHANCE_INTR) {
182 		errno = EINTR;
183 		return -1;
184 	}
185 
186 	/* read */
187 	if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
188 		for (i = 0, nset = 0; i < nfds; i++) {
189 			if (FD_ISSET(i, readfds)) {
190 				assert(wrap_fds[i].mode != UNUSED);
191 				fdlist[nset] = i;
192 				nset++;
193 			}
194 		}
195 		DROPBEAR_FD_ZERO(readfds);
196 
197 		if (nset > 0) {
198 			/* set one */
199 			sel = fdlist[nrand48(rand_state) % nset];
200 			FD_SET(sel, readfds);
201 			ret++;
202 
203 			if (erand48(rand_state) < CHANCE_READ2) {
204 				sel = fdlist[nrand48(rand_state) % nset];
205 				if (!FD_ISSET(sel, readfds)) {
206 					FD_SET(sel, readfds);
207 					ret++;
208 				}
209 			}
210 		}
211 	}
212 
213 	/* write */
214 	if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
215 		for (i = 0, nset = 0; i < nfds; i++) {
216 			if (FD_ISSET(i, writefds)) {
217 				assert(wrap_fds[i].mode != UNUSED);
218 				fdlist[nset] = i;
219 				nset++;
220 			}
221 		}
222 		DROPBEAR_FD_ZERO(writefds);
223 
224 		/* set one */
225 		if (nset > 0) {
226 			sel = fdlist[nrand48(rand_state) % nset];
227 			FD_SET(sel, writefds);
228 			ret++;
229 
230 			if (erand48(rand_state) < CHANCE_WRITE2) {
231 				sel = fdlist[nrand48(rand_state) % nset];
232 				if (!FD_ISSET(sel, writefds)) {
233 					FD_SET(sel, writefds);
234 					ret++;
235 				}
236 			}
237 		}
238 	}
239 	return ret;
240 }
241 
242