Coverage Report

Created: 2024-09-08 06:28

/src/dropbear/fuzz/fuzz-wrapfd.c
Line
Count
Source (jump to first uncovered line)
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
4.04M
#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
32
22.1k
void wrapfd_setup(buffer *buf) {
33
22.1k
  TRACE(("wrapfd_setup"))
34
35
  // clean old ones
36
22.1k
  int i;
37
137k
  for (i = 0; i <= wrapfd_maxfd; i++) {
38
115k
    if (wrap_fds[i].mode != UNUSED) {
39
7.96k
      wrapfd_remove(i);
40
7.96k
    }
41
115k
  }
42
22.1k
  wrapfd_maxfd = -1;
43
44
22.1k
  memset(rand_state, 0x0, sizeof(rand_state));
45
22.1k
  wrapfd_setseed(50);
46
22.1k
  input_buf = buf;
47
22.1k
}
48
49
37.1k
void wrapfd_setseed(uint32_t seed) {
50
37.1k
  memcpy(rand_state, &seed, sizeof(seed));
51
37.1k
  nrand48(rand_state);
52
37.1k
}
53
54
15.0k
int wrapfd_new_fuzzinput() {
55
15.0k
  if (devnull_fd == -1) {
56
5
    devnull_fd = open("/dev/null", O_RDONLY);
57
5
    assert(devnull_fd != -1);
58
5
  }
59
60
15.0k
  int fd = dup(devnull_fd);
61
15.0k
  assert(fd != -1);
62
15.0k
  assert(wrap_fds[fd].mode == UNUSED);
63
15.0k
  wrap_fds[fd].mode = COMMONBUF;
64
15.0k
  wrap_fds[fd].closein = 0;
65
15.0k
  wrap_fds[fd].closeout = 0;
66
15.0k
  wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
67
68
15.0k
  return fd;
69
15.0k
}
70
71
10.5k
int wrapfd_new_dummy() {
72
10.5k
  if (devnull_fd == -1) {
73
0
    devnull_fd = open("/dev/null", O_RDONLY);
74
0
    assert(devnull_fd != -1);
75
0
  }
76
77
10.5k
  int fd = dup(devnull_fd);
78
10.5k
  if (fd == -1) {
79
0
    return -1;
80
0
  }
81
10.5k
  if (fd > IOWRAP_MAXFD) {
82
0
    close(fd);
83
0
    errno = EMFILE;
84
0
    return -1;
85
0
  }
86
10.5k
  assert(wrap_fds[fd].mode == UNUSED);
87
10.5k
  wrap_fds[fd].mode = DUMMY;
88
10.5k
  wrap_fds[fd].closein = 0;
89
10.5k
  wrap_fds[fd].closeout = 0;
90
10.5k
  wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
91
92
10.5k
  return fd;
93
10.5k
}
94
95
96
25.5k
static void wrapfd_remove(int fd) {
97
25.5k
  TRACE(("wrapfd_remove %d", fd))
98
25.5k
  assert(fd >= 0);
99
25.5k
  assert(fd <= IOWRAP_MAXFD);
100
25.5k
  assert(wrap_fds[fd].mode != UNUSED);
101
25.5k
  wrap_fds[fd].mode = UNUSED;
102
25.5k
  close(fd);
103
25.5k
}
104
105
39.2k
int wrapfd_close(int fd) {
106
39.2k
  if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
107
17.6k
    wrapfd_remove(fd);
108
17.6k
    return 0;
109
21.5k
  } else {
110
21.5k
    return close(fd);
111
21.5k
  }
112
39.2k
}
113
114
1.98M
int wrapfd_read(int fd, void *out, size_t count) {
115
1.98M
  size_t maxread;
116
117
1.98M
  if (!fuzz.wrapfds) {
118
0
    return read(fd, out, count);
119
0
  }
120
121
1.98M
  if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
122
    /* XXX - assertion failure? */
123
623
    TRACE(("Bad read descriptor %d\n", fd))
124
623
    errno = EBADF;
125
623
    return -1;
126
623
  }
127
128
1.97M
  assert(count != 0);
129
130
1.97M
  if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
131
323
    wrap_fds[fd].closein = 1;
132
323
    errno = ECONNRESET;
133
323
    return -1;
134
323
  }
135
136
1.97M
  if (erand48(rand_state) < CHANCE_INTR) {
137
2.58k
    errno = EINTR;
138
2.58k
    return -1;
139
2.58k
  }
140
141
1.97M
  if (input_buf && wrap_fds[fd].mode == COMMONBUF) {
142
1.77M
    maxread = MIN(input_buf->len - input_buf->pos, count);
143
    /* returns 0 if buf is EOF, as intended */
144
1.77M
    if (maxread > 0) {
145
1.76M
      maxread = nrand48(rand_state) % maxread + 1;
146
1.76M
    }
147
1.77M
    memcpy(out, buf_getptr(input_buf, maxread), maxread);
148
1.77M
    buf_incrpos(input_buf, maxread);
149
1.77M
    return maxread;
150
1.77M
  }
151
152
  // return fixed output, of random length
153
203k
  maxread = MIN(MAX_RANDOM_IN, count);
154
203k
  maxread = nrand48(rand_state) % maxread + 1;
155
203k
  memset(out, 0xef, maxread);
156
203k
  return maxread;
157
1.97M
}
158
159
0
int wrapfd_write(int fd, const void* in, size_t count) {
160
0
  unsigned const volatile char* volin = in;
161
0
  unsigned int i;
162
163
0
  if (!fuzz.wrapfds) {
164
0
    return write(fd, in, count);
165
0
  }
166
167
0
  if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
168
    /* XXX - assertion failure? */
169
0
    TRACE(("Bad read descriptor %d\n", fd))
170
0
    errno = EBADF;
171
0
    return -1;
172
0
  }
173
174
0
  assert(count != 0);
175
176
  /* force read to exercise sanitisers */
177
0
  for (i = 0; i < count; i++) {
178
0
    (void)volin[i];
179
0
  }
180
181
0
  if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
182
0
    wrap_fds[fd].closeout = 1;
183
0
    errno = ECONNRESET;
184
0
    return -1;
185
0
  }
186
187
0
  if (erand48(rand_state) < CHANCE_INTR) {
188
0
    errno = EINTR;
189
0
    return -1;
190
0
  }
191
192
0
  return nrand48(rand_state) % (count+1);
193
0
}
194
195
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, 
196
1.89M
  fd_set *exceptfds, struct timeval *timeout) {
197
1.89M
  int i, nset, sel;
198
1.89M
  int ret = 0;
199
1.89M
  int fdlist[IOWRAP_MAXFD+1];
200
201
1.89M
  if (!fuzz.wrapfds) {
202
0
    return select(nfds, readfds, writefds, exceptfds, timeout);
203
0
  }
204
205
1.89M
  assert(nfds <= IOWRAP_MAXFD+1);
206
207
1.89M
  if (erand48(rand_state) < CHANCE_INTR) {
208
2.39k
    errno = EINTR;
209
2.39k
    return -1;
210
2.39k
  }
211
212
  /* read */
213
1.89M
  if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
214
21.4M
    for (i = 0, nset = 0; i < nfds; i++) {
215
19.6M
      if (FD_ISSET(i, readfds)) {
216
2.75M
        assert(wrap_fds[i].mode != UNUSED);
217
2.75M
        fdlist[nset] = i;
218
2.75M
        nset++;
219
2.75M
      }
220
19.6M
    }
221
1.79M
    DROPBEAR_FD_ZERO(readfds);
222
223
1.79M
    if (nset > 0) {
224
      /* set one */
225
1.70M
      sel = fdlist[nrand48(rand_state) % nset];
226
1.70M
      FD_SET(sel, readfds);
227
1.70M
      ret++;
228
229
1.70M
      if (erand48(rand_state) < CHANCE_READ2) {
230
841k
        sel = fdlist[nrand48(rand_state) % nset];
231
841k
        if (!FD_ISSET(sel, readfds)) {
232
58.4k
          FD_SET(sel, readfds);
233
58.4k
          ret++;
234
58.4k
        }
235
841k
      }
236
1.70M
    }
237
1.79M
  }
238
239
  /* write */
240
1.89M
  if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
241
18.7M
    for (i = 0, nset = 0; i < nfds; i++) {
242
17.2M
      if (FD_ISSET(i, writefds)) {
243
232k
        assert(wrap_fds[i].mode != UNUSED);
244
232k
        fdlist[nset] = i;
245
232k
        nset++;
246
232k
      }
247
17.2M
    }
248
1.45M
    DROPBEAR_FD_ZERO(writefds);
249
250
    /* set one */
251
1.45M
    if (nset > 0) {
252
232k
      sel = fdlist[nrand48(rand_state) % nset];
253
232k
      FD_SET(sel, writefds);
254
232k
      ret++;
255
256
232k
      if (erand48(rand_state) < CHANCE_WRITE2) {
257
110k
        sel = fdlist[nrand48(rand_state) % nset];
258
110k
        if (!FD_ISSET(sel, writefds)) {
259
0
          FD_SET(sel, writefds);
260
0
          ret++;
261
0
        }
262
110k
      }
263
232k
    }
264
1.45M
  }
265
1.89M
  return ret;
266
1.89M
}
267
268
1.02k
int fuzz_kill(pid_t pid, int sig) {
269
1.02k
  if (fuzz.fuzzing) {
270
1.02k
    TRACE(("fuzz_kill ignoring pid %d signal %d", (pid), sig))
271
1.02k
    if (sig >= 0) {
272
1.02k
      return 0;
273
1.02k
    } else {
274
0
      errno = EINVAL;
275
0
      return -1;
276
0
    }
277
1.02k
  }
278
0
  return kill(pid, sig);
279
1.02k
}