/src/uWebSockets/fuzzing/libEpollFuzzer/epoll_fuzzer.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* Welcome to libEpollFuzzer - a mock implementation of the epoll/socket syscalls */ |
2 | | |
3 | | /* Current implementation is extremely experimental and trashy, mind you */ |
4 | | |
5 | | #include <stdio.h> |
6 | | #include <stdlib.h> |
7 | | #include <stdint.h> |
8 | | #include <string.h> |
9 | | #include <stdarg.h> |
10 | | //#include <threads.h> |
11 | | |
12 | | #include <sys/timerfd.h> |
13 | | #include <sys/epoll.h> |
14 | | #include <sys/types.h> |
15 | | #include <sys/socket.h> |
16 | | #include <netdb.h> |
17 | | #include <errno.h> |
18 | | |
19 | | // todo: add connect, donät pass invalid-FD to real syscalls |
20 | | // getaddrinfo should return inet6 somtimes and sometimes wrong family (done) |
21 | | // accept4 should produce inet6 sometimes (done) |
22 | | // socket syscall should fail with given invalid family (done) |
23 | | // listen syscall should fail sometimes (done) |
24 | | |
25 | | /* Currently read, close, fcntl are wrapped to real syscalls */ |
26 | | |
27 | | /* TODO: Our FDs should start at 1024 while actual real FDs should be reserved from 0 to 1023 and passed to actual |
28 | | * real syscalls so that we can co-exist with overlapping syscalls like read, open, write, close */ |
29 | | |
30 | | //#define PRINTF_DEBUG |
31 | | |
32 | | /* The test case */ |
33 | | void test(); |
34 | | void teardown(); |
35 | | |
36 | | #ifdef __cplusplus |
37 | | extern "C" { |
38 | | #endif |
39 | | |
40 | | struct file { |
41 | | /* Every file has a type; socket, event, timer, epoll */ |
42 | | int type; |
43 | | |
44 | | /* We assume there can only be one event-loop at any given point in time, |
45 | | * so every file holds its own epoll_event */ |
46 | | struct epoll_event epev; |
47 | | |
48 | | /* A file may be added to an epfd by linking it in a list */ |
49 | | struct file *prev, *next; |
50 | | }; |
51 | | |
52 | | /* If FD is less than this, it should be passed to REAL syscall. |
53 | | * We never produce FDs lower than this (except for -1 on error) */ |
54 | | const int RESERVED_SYSTEM_FDS = 1024; |
55 | | |
56 | | /* Map from some collection of integers to a shared extensible struct of data */ |
57 | | const int MAX_FDS = 1000; |
58 | | struct file *fd_to_file[MAX_FDS]; |
59 | | |
60 | | const int FD_TYPE_EPOLL = 0; |
61 | | const int FD_TYPE_TIMER = 1; |
62 | | const int FD_TYPE_EVENT = 2; |
63 | | const int FD_TYPE_SOCKET = 3; |
64 | | |
65 | | int num_fds = 0; |
66 | | |
67 | | /* Keeping track of cunsumable data */ |
68 | | unsigned char *consumable_data; |
69 | | int consumable_data_length; |
70 | | |
71 | 7.19k | void set_consumable_data(const unsigned char *new_data, int new_length) { |
72 | 7.19k | consumable_data = (unsigned char *) new_data; |
73 | 7.19k | consumable_data_length = new_length; |
74 | 7.19k | } |
75 | | |
76 | | /* Returns non-null on error */ |
77 | 3.91M | int consume_byte(unsigned char *b) { |
78 | 3.91M | if (consumable_data_length) { |
79 | 3.90M | *b = consumable_data[0]; |
80 | 3.90M | consumable_data++; |
81 | 3.90M | consumable_data_length--; |
82 | 3.90M | return 0; |
83 | 3.90M | } |
84 | 5.05k | return -1; |
85 | 3.91M | } |
86 | | |
87 | | /* Keeping track of FDs */ |
88 | | |
89 | | /* Returns -1 on error, or RESERVED_SYSTEM_FDS and above */ |
90 | 1.48M | int allocate_fd() { |
91 | | // this can be massively optimized by having a list of free blocks or the like |
92 | 107M | for (int fd = 0; fd < MAX_FDS; fd++) { |
93 | 107M | if (!fd_to_file[fd]) { |
94 | 1.48M | num_fds++; |
95 | 1.48M | return fd + RESERVED_SYSTEM_FDS; |
96 | 1.48M | } |
97 | 107M | } |
98 | 198 | return -1; |
99 | 1.48M | } |
100 | | |
101 | | /* This one should set the actual file for this FD */ |
102 | 1.48M | void init_fd(int fd, int type, struct file *f) { |
103 | 1.48M | if (fd >= RESERVED_SYSTEM_FDS) { |
104 | 1.48M | fd_to_file[fd - RESERVED_SYSTEM_FDS] = f; |
105 | 1.48M | fd_to_file[fd - RESERVED_SYSTEM_FDS]->type = type; |
106 | 1.48M | fd_to_file[fd - RESERVED_SYSTEM_FDS]->next = NULL; |
107 | 1.48M | fd_to_file[fd - RESERVED_SYSTEM_FDS]->prev = NULL; |
108 | 1.48M | } |
109 | 1.48M | } |
110 | | |
111 | 20.3M | struct file *map_fd(int fd) { |
112 | 20.3M | if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) { |
113 | 20.3M | return fd_to_file[fd - RESERVED_SYSTEM_FDS]; |
114 | 20.3M | } |
115 | 0 | return NULL; |
116 | 20.3M | } |
117 | | |
118 | | /* This one should remove the FD from any pollset by calling epoll_ctl remove */ |
119 | 1.48M | int free_fd(int fd) { |
120 | 1.48M | if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) { |
121 | 1.48M | if (fd_to_file[fd - RESERVED_SYSTEM_FDS]) { |
122 | 1.48M | fd_to_file[fd - RESERVED_SYSTEM_FDS] = 0; |
123 | 1.48M | num_fds--; |
124 | 1.48M | return 0; |
125 | 1.48M | } |
126 | 1.48M | } |
127 | | |
128 | 0 | return -1; |
129 | 1.48M | } |
130 | | |
131 | | /* The epoll syscalls */ |
132 | | |
133 | | struct epoll_file { |
134 | | struct file base; |
135 | | |
136 | | /* A doubly linked list for polls awaiting events */ |
137 | | struct file *poll_set_head, *poll_set_tail; |
138 | | }; |
139 | | |
140 | | /* This function is O(n) and does not consume any fuzz data, but will fail if run out of FDs */ |
141 | 7.19k | int __wrap_epoll_create1(int flags) { |
142 | | |
143 | | /* Todo: check that we do not allocate more than one epoll FD */ |
144 | 7.19k | int fd = allocate_fd(); |
145 | | |
146 | 7.19k | if (fd != -1) { |
147 | 7.19k | struct epoll_file *ef = (struct epoll_file *)malloc(sizeof(struct epoll_file)); |
148 | | |
149 | | /* Init the epoll_file */ |
150 | 7.19k | ef->poll_set_head = NULL; |
151 | 7.19k | ef->poll_set_tail = NULL; |
152 | | |
153 | 7.19k | init_fd(fd, FD_TYPE_EPOLL, (struct file *)ef); |
154 | 7.19k | } |
155 | | |
156 | | #ifdef PRINTF_DEBUG |
157 | | printf("epoll_create1 returning epfd: %d\n", fd); |
158 | | #endif |
159 | | |
160 | 7.19k | return fd; |
161 | 7.19k | } |
162 | | |
163 | | // this function cannot be called inside an iteration! it changes the list |
164 | | /* This function is O(1) and does not consume any fuzz data */ |
165 | 3.54M | int __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) { |
166 | | |
167 | 3.54M | struct epoll_file *ef = (struct epoll_file *)map_fd(epfd); |
168 | 3.54M | if (!ef) { |
169 | 0 | return -1; |
170 | 0 | } |
171 | | |
172 | 3.54M | struct file *f = (struct file *)map_fd(fd); |
173 | 3.54M | if (!f) { |
174 | 0 | return -1; |
175 | 0 | } |
176 | | |
177 | | /* We add new polls in the head */ |
178 | 3.54M | if (op == EPOLL_CTL_ADD) { |
179 | | // if there is a head already |
180 | 1.47M | if (ef->poll_set_head) { |
181 | 1.47M | ef->poll_set_head->prev = f; |
182 | | |
183 | | // then it will be our next |
184 | 1.47M | f->next = ef->poll_set_head; |
185 | 1.47M | } else { |
186 | | // if there was no head then we became the tail also |
187 | 7.19k | ef->poll_set_tail = f; |
188 | 7.19k | } |
189 | | |
190 | | // we are now the head in any case |
191 | 1.47M | ef->poll_set_head = f; |
192 | | |
193 | 1.47M | f->epev = *event; |
194 | | |
195 | 2.07M | } else if (op == EPOLL_CTL_MOD) { |
196 | | /* Modifying is simply changing the file itself */ |
197 | 593k | f->epev = *event; |
198 | 1.47M | } else if (op == EPOLL_CTL_DEL) { |
199 | | |
200 | 1.47M | if (f->prev) { |
201 | 743k | f->prev->next = f->next; |
202 | 743k | } else { |
203 | 734k | ef->poll_set_head = f->next; |
204 | 734k | } |
205 | | |
206 | 1.47M | if (f->next) { |
207 | 1.47M | f->next->prev = f->prev; |
208 | 1.47M | } else { |
209 | | // tail ska vara vår.prev |
210 | 7.19k | ef->poll_set_tail = f->prev; |
211 | 7.19k | } |
212 | | |
213 | | // a file that is not in the list should be reset to NULL |
214 | 1.47M | f->prev = NULL; |
215 | 1.47M | f->next = NULL; |
216 | 1.47M | } |
217 | | |
218 | | /* You have to poll for errors and hangups */ |
219 | 3.54M | f->epev.events |= EPOLLERR | EPOLLHUP; |
220 | | |
221 | 3.54M | return 0; |
222 | 3.54M | } |
223 | | |
224 | | /* This function is O(n) and consumes fuzz data and might trigger teardown callback */ |
225 | | int __wrap_epoll_wait(int epfd, struct epoll_event *events, |
226 | 3.63M | int maxevents, int timeout) { |
227 | | //printf("epoll_wait: %d\n", 0); |
228 | | |
229 | | #ifdef PRINTF_DEBUG |
230 | | printf("Calling epoll_wait\n"); |
231 | | #endif |
232 | | |
233 | 3.63M | struct epoll_file *ef = (struct epoll_file *)map_fd(epfd); |
234 | 3.63M | if (!ef) { |
235 | 0 | return -1; |
236 | 0 | } |
237 | | |
238 | 3.63M | if (consumable_data_length) { |
239 | | |
240 | 3.62M | int ready_events = 0; |
241 | | |
242 | 22.3M | for (struct file *f = ef->poll_set_head; f; f = f->next) { |
243 | | |
244 | | |
245 | | /* Consume one fuzz byte, AND it with the event */ |
246 | 18.7M | if (!consumable_data_length) { |
247 | | // break if we have no data |
248 | 498 | break; |
249 | 498 | } |
250 | | |
251 | | // here we have the main condition that drives everything |
252 | 18.7M | int ready_event = consumable_data[0] & f->epev.events; |
253 | | |
254 | | // consume the byte |
255 | 18.7M | consumable_data_length--; |
256 | 18.7M | consumable_data++; |
257 | | |
258 | 18.7M | if (ready_event) { |
259 | 11.7M | if (ready_events < maxevents) { |
260 | 11.7M | events[ready_events] = f->epev; |
261 | | |
262 | | // todo: the event should be masked by the byte, not everything it wants shold be given all the time! |
263 | 11.7M | events[ready_events++].events = ready_event; |
264 | 11.7M | } else { |
265 | | // we are full, break |
266 | 0 | break; |
267 | 0 | } |
268 | 11.7M | } |
269 | | |
270 | 18.7M | } |
271 | | |
272 | 3.62M | return ready_events; |
273 | | |
274 | 3.62M | } else { |
275 | | |
276 | | #ifdef PRINTF_DEBUG |
277 | | printf("Calling teardown\n"); |
278 | | #endif |
279 | 7.17k | teardown(); |
280 | | |
281 | | // after shutting down the listen socket we clear the whole list (the bug in epoll_ctl remove) |
282 | | // so the below loop doesn't work - we never close anything more than the listen socket! |
283 | | |
284 | | /* You don't really need to emit teardown, you could simply emit error on every poll */ |
285 | | |
286 | 7.17k | int ready_events = 0; |
287 | | |
288 | | #ifdef PRINTF_DEBUG |
289 | | printf("Emitting error on every remaining FD\n"); |
290 | | #endif |
291 | 77.2k | for (struct file *f = ef->poll_set_head; f; f = f->next) { |
292 | | |
293 | 70.0k | if (f->type == FD_TYPE_SOCKET) { |
294 | | |
295 | 48.5k | if (ready_events < maxevents) { |
296 | 48.5k | events[ready_events] = f->epev; |
297 | | |
298 | | // todo: the event should be masked by the byte, not everything it wants shold be given all the time! |
299 | 48.5k | events[ready_events++].events = EPOLLERR | EPOLLHUP; |
300 | 48.5k | } else { |
301 | | // we are full, break |
302 | 0 | break; |
303 | 0 | } |
304 | | |
305 | 48.5k | } |
306 | 70.0k | } |
307 | | |
308 | | #ifdef PRINTF_DEBUG |
309 | | printf("Ready events: %d\n", ready_events); |
310 | | #endif |
311 | | |
312 | 7.17k | return ready_events; |
313 | 7.17k | } |
314 | 3.63M | } |
315 | | |
316 | | /* The socket syscalls */ |
317 | | |
318 | | struct socket_file { |
319 | | struct file base; |
320 | | |
321 | | /* We store socket addresses created in accept4 */ |
322 | | union { |
323 | | struct sockaddr_in6 in6; |
324 | | struct sockaddr_in in; |
325 | | } addr; |
326 | | |
327 | | /* The size of sockaddr_in6 or sockaddr_in as a whole */ |
328 | | socklen_t len; |
329 | | }; |
330 | | |
331 | | extern int __real_read(int fd, void *buf, size_t count); |
332 | 8.18M | int __wrap_read(int fd, void *buf, size_t count) { |
333 | | |
334 | 8.18M | if (fd < RESERVED_SYSTEM_FDS) { |
335 | 0 | return __real_read(fd, buf, count); |
336 | 0 | } |
337 | | |
338 | | #ifdef PRINTF_DEBUG |
339 | | printf("Wrapped read\n"); |
340 | | #endif |
341 | | |
342 | | /* Let's try and clear the buffer first */ |
343 | | //memset(buf, 0, count); |
344 | | |
345 | 8.18M | struct file *f = map_fd(fd); |
346 | 8.18M | if (!f) { |
347 | 0 | return -1; |
348 | 0 | } |
349 | | |
350 | 8.18M | errno = 0; |
351 | | |
352 | 8.18M | if (f->type == FD_TYPE_SOCKET) { |
353 | | |
354 | 597k | if (!consumable_data_length) { |
355 | 3.62k | errno = EWOULDBLOCK; |
356 | 3.62k | return -1; |
357 | 593k | } else { |
358 | 593k | int data_available = (unsigned char) consumable_data[0]; |
359 | 593k | consumable_data_length--; |
360 | 593k | consumable_data++; |
361 | | |
362 | 593k | if (consumable_data_length < data_available) { |
363 | 5.80k | data_available = consumable_data_length; |
364 | 5.80k | } |
365 | | |
366 | 593k | if (count < data_available) { |
367 | 0 | data_available = count; |
368 | 0 | } |
369 | | |
370 | 593k | memcpy(buf, consumable_data, data_available); |
371 | | |
372 | 593k | consumable_data_length -= data_available; |
373 | 593k | consumable_data += data_available; |
374 | | |
375 | 593k | return data_available; |
376 | 593k | } |
377 | 597k | } |
378 | | |
379 | 7.58M | if (f->type == FD_TYPE_EVENT) { |
380 | 2.44M | memset(buf, 1, 8); |
381 | 2.44M | return 8; |
382 | 2.44M | } |
383 | | |
384 | 5.13M | if (f->type == FD_TYPE_TIMER) { |
385 | 5.13M | memset(buf, 1, 8); |
386 | 5.13M | return 8; |
387 | 5.13M | } |
388 | | |
389 | 0 | return -1; |
390 | 5.13M | } |
391 | | |
392 | | /* We just ignore the extra flag here */ |
393 | 597k | int __wrap_recv(int sockfd, void *buf, size_t len, int flags) { |
394 | 597k | return __wrap_read(sockfd, buf, len); |
395 | 597k | } |
396 | | |
397 | 705k | int __wrap_send(int sockfd, const void *buf, size_t len, int flags) { |
398 | | |
399 | 705k | if (consumable_data_length) { |
400 | | /* We can send len scaled by the 1 byte */ |
401 | 688k | unsigned char scale = consumable_data[0]; |
402 | 688k | consumable_data++; |
403 | 688k | consumable_data_length--; |
404 | | |
405 | 688k | int written = float(scale) / 255.0f * len; |
406 | | |
407 | 688k | if (written == 0) { |
408 | 93.7k | errno = EWOULDBLOCK; |
409 | 594k | } else { |
410 | 594k | errno = 0; |
411 | 594k | } |
412 | | |
413 | 688k | return written; |
414 | 688k | } else { |
415 | 17.5k | return -1; |
416 | 17.5k | } |
417 | 705k | } |
418 | | |
419 | | int __wrap_sendto(int sockfd, const void *buf, size_t len, int flags, |
420 | 0 | const struct sockaddr *dest_addr, socklen_t addrlen) { |
421 | 0 | return __wrap_send(sockfd, buf, len, flags); |
422 | 0 | } |
423 | | |
424 | 7.18k | int __wrap_bind() { |
425 | 7.18k | return 0; |
426 | 7.18k | } |
427 | | |
428 | 1.47M | int __wrap_setsockopt() { |
429 | 1.47M | return 0; |
430 | 1.47M | } |
431 | | |
432 | | extern int __real_fcntl(int fd, int cmd, ... /* arg */ ); |
433 | 2.91M | int __wrap_fcntl(int fd, int cmd, ... /* arg */) { |
434 | 2.91M | if (fd < RESERVED_SYSTEM_FDS) { |
435 | 2 | va_list args; |
436 | 2 | va_start(args, cmd); |
437 | 2 | int ret = __real_fcntl(fd, cmd, args); |
438 | 2 | va_end(args); |
439 | 2 | return ret; |
440 | 2 | } |
441 | | |
442 | 2.91M | return 0; |
443 | 2.91M | } |
444 | | |
445 | | /* Addrinfo */ |
446 | | int __wrap_getaddrinfo(const char *node, const char *service, |
447 | | const struct addrinfo *hints, |
448 | 7.19k | struct addrinfo **res) { |
449 | | //printf("Wrapped getaddrinfo\n"); |
450 | | |
451 | 7.19k | struct addrinfo default_hints = {}; |
452 | | |
453 | 7.19k | if (!hints) { |
454 | 0 | hints = &default_hints; |
455 | 0 | } |
456 | | |
457 | 7.19k | unsigned char b; |
458 | 7.19k | if (consume_byte(&b)) { |
459 | 6 | return -1; |
460 | 6 | } |
461 | | |
462 | | /* This one should be thread_local */ |
463 | 7.19k | static /*thread_local*/ struct addrinfo ai; |
464 | 7.19k | ai.ai_flags = hints->ai_flags; |
465 | 7.19k | ai.ai_socktype = hints->ai_socktype; |
466 | 7.19k | ai.ai_protocol = hints->ai_protocol; |
467 | | |
468 | 7.19k | if (b > 127) { |
469 | 3.53k | ai.ai_family = AF_INET;//hints->ai_family; |
470 | 3.65k | } else { |
471 | 3.65k | ai.ai_family = AF_INET6;//hints->ai_family; |
472 | 3.65k | } |
473 | | |
474 | | /* This one is for generating the wrong family (maybe invalid?) */ |
475 | 7.19k | if (b == 0) { |
476 | 2 | ai.ai_family = hints->ai_family; |
477 | 2 | } |
478 | | |
479 | 7.19k | ai.ai_next = NULL; |
480 | 7.19k | ai.ai_canonname = NULL; // fel |
481 | | |
482 | | // these should depend on inet6 or inet */ |
483 | 7.19k | ai.ai_addrlen = 4; // fel |
484 | 7.19k | ai.ai_addr = NULL; // ska peka på en sockaddr! |
485 | | |
486 | | // we need to return an addrinfo with family AF_INET6 |
487 | | |
488 | 7.19k | *res = &ai; |
489 | 7.19k | return 0; |
490 | 7.19k | } |
491 | | |
492 | 7.19k | int __wrap_freeaddrinfo() { |
493 | 7.19k | return 0; |
494 | 7.19k | } |
495 | | |
496 | | /* This one should return the same address as accept4 did produce */ |
497 | 0 | int __wrap_getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { |
498 | |
|
499 | 0 | struct file *f = map_fd(sockfd); |
500 | 0 | if (!f) { |
501 | 0 | return -1; |
502 | 0 | } |
503 | | |
504 | | // todo: this could fail with -1 also (consume a byte)? |
505 | | |
506 | 0 | if (f->type == FD_TYPE_SOCKET) { |
507 | |
|
508 | 0 | struct socket_file *sf = (struct socket_file *) f; |
509 | |
|
510 | 0 | if (addr) { |
511 | 0 | memcpy(addr, &sf->addr, sf->len); |
512 | 0 | *addrlen = sf->len; |
513 | 0 | } |
514 | |
|
515 | 0 | return 0; |
516 | 0 | } |
517 | | |
518 | 0 | return -1; |
519 | 0 | } |
520 | | |
521 | 3.89M | int __wrap_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { |
522 | | /* We must end with -1 since we are called in a loop */ |
523 | | |
524 | 3.89M | unsigned char b; |
525 | 3.89M | if (consume_byte(&b)) { |
526 | 5.03k | return -1; |
527 | 5.03k | } |
528 | | |
529 | | /* This rule might change, anything below 10 is accepted */ |
530 | 3.88M | if (b < 10) { |
531 | | |
532 | 1.44M | int fd = allocate_fd(); |
533 | 1.44M | if (fd != -1) { |
534 | | |
535 | | /* Allocate the file */ |
536 | 1.44M | struct socket_file *sf = (struct socket_file *) malloc(sizeof(struct socket_file)); |
537 | | |
538 | | /* Init the file */ |
539 | | |
540 | | /* Here we need to create a socket FD and return */ |
541 | 1.44M | init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf); |
542 | | |
543 | | /* We need to provide an addr */ |
544 | | |
545 | | /* Begin by setting it to an empty in6 address */ |
546 | 1.44M | memset(&sf->addr, 0, sizeof(struct sockaddr_in6)); |
547 | 1.44M | sf->len = sizeof(struct sockaddr_in6); |
548 | 1.44M | sf->addr.in6.sin6_family = AF_INET6; |
549 | | |
550 | | /* Opt-in to ipv4 */ |
551 | 1.44M | if (b < 5) { |
552 | 1.29M | memset(&sf->addr, 0, sizeof(struct sockaddr_in6)); |
553 | 1.29M | sf->len = sizeof(struct sockaddr_in); |
554 | 1.29M | sf->addr.in.sin_family = AF_INET; |
555 | 1.29M | } |
556 | | |
557 | 1.44M | if (addr) { |
558 | | /* Copy from socket to addr */ |
559 | 1.44M | memcpy(addr, &sf->addr, sf->len); |
560 | 1.44M | } |
561 | 1.44M | } |
562 | | |
563 | 1.44M | return fd; |
564 | 1.44M | } |
565 | | |
566 | 2.43M | return -1; |
567 | 3.88M | } |
568 | | |
569 | 7.18k | int __wrap_listen() { |
570 | | /* Listen consumes one byte and fails on -1 */ |
571 | 7.18k | unsigned char b; |
572 | 7.18k | if (consume_byte(&b)) { |
573 | 9 | return -1; |
574 | 9 | } |
575 | | |
576 | 7.18k | if (b) { |
577 | 7.17k | return 0; |
578 | 7.17k | } |
579 | | |
580 | 1 | return -1; |
581 | 7.18k | } |
582 | | |
583 | | /* This one is similar to accept4 and has to return a valid FD of type socket */ |
584 | 7.18k | int __wrap_socket(int domain, int type, int protocol) { |
585 | | |
586 | | /* Only accept valid families */ |
587 | 7.18k | if (domain != AF_INET && domain != AF_INET6) { |
588 | 0 | return -1; |
589 | 0 | } |
590 | | |
591 | 7.18k | int fd = allocate_fd(); |
592 | | |
593 | 7.18k | if (fd != -1) { |
594 | 7.18k | struct socket_file *sf = (struct socket_file *)malloc(sizeof(struct socket_file)); |
595 | | |
596 | | /* Init the file */ |
597 | | |
598 | 7.18k | init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf); |
599 | 7.18k | } |
600 | | |
601 | | #ifdef PRINTF_DEBUG |
602 | | printf("socket returning fd: %d\n", fd); |
603 | | #endif |
604 | | |
605 | 7.18k | return fd; |
606 | 7.18k | } |
607 | | |
608 | 175k | int __wrap_shutdown() { |
609 | | //printf("Wrapped shutdown\n"); |
610 | 175k | return 0; |
611 | 175k | } |
612 | | |
613 | | /* The timerfd syscalls */ |
614 | | |
615 | | struct timer_file { |
616 | | struct file base; |
617 | | }; |
618 | | |
619 | 14.3k | int __wrap_timerfd_create(int clockid, int flags) { |
620 | | |
621 | 14.3k | int fd = allocate_fd(); |
622 | | |
623 | 14.3k | if (fd != -1) { |
624 | 14.3k | struct timer_file *tf = (struct timer_file *)malloc(sizeof(struct timer_file)); |
625 | | |
626 | | /* Init the file */ |
627 | | |
628 | | |
629 | 14.3k | init_fd(fd, FD_TYPE_TIMER, (struct file *)tf); |
630 | | |
631 | 14.3k | } |
632 | | |
633 | | #ifdef PRINTF_DEBUG |
634 | | printf("timerfd_create returning fd: %d\n", fd); |
635 | | #endif |
636 | | |
637 | 14.3k | return fd; |
638 | 14.3k | } |
639 | | |
640 | | int __wrap_timerfd_settime(int fd, int flags, |
641 | | const struct itimerspec *new_value, |
642 | 14.3k | struct itimerspec *old_value) { |
643 | | //printf("timerfd_settime: %d\n", fd); |
644 | 14.3k | return 0; |
645 | 14.3k | } |
646 | | |
647 | | /* The eventfd syscalls */ |
648 | | |
649 | | struct event_file { |
650 | | struct file base; |
651 | | }; |
652 | | |
653 | 7.19k | int __wrap_eventfd() { |
654 | | |
655 | 7.19k | int fd = allocate_fd(); |
656 | | |
657 | 7.19k | if (fd != -1) { |
658 | 7.19k | struct event_file *ef = (struct event_file *)malloc(sizeof(struct event_file)); |
659 | | |
660 | | /* Init the file */ |
661 | | |
662 | 7.19k | init_fd(fd, FD_TYPE_EVENT, (struct file *)ef); |
663 | | |
664 | | //printf("eventfd: %d\n", fd); |
665 | 7.19k | } |
666 | | |
667 | | #ifdef PRINTF_DEBUG |
668 | | printf("eventfd returning fd: %d\n", fd); |
669 | | #endif |
670 | | |
671 | 7.19k | return fd; |
672 | 7.19k | } |
673 | | |
674 | | // timerfd_settime |
675 | | |
676 | | /* File descriptors exist in a shared dimension, and has to know its type */ |
677 | | extern int __real_close(int fd); |
678 | 1.48M | int __wrap_close(int fd) { |
679 | | |
680 | 1.48M | if (fd < RESERVED_SYSTEM_FDS) { |
681 | 0 | return __real_close(fd); |
682 | 0 | } |
683 | | |
684 | 1.48M | struct file *f = map_fd(fd); |
685 | | |
686 | 1.48M | if (!f) { |
687 | 0 | return -1; |
688 | 0 | } |
689 | | |
690 | 1.48M | if (f->type == FD_TYPE_EPOLL) { |
691 | | #ifdef PRINTF_DEBUG |
692 | | printf("Closing epoll FD: %d\n", fd); |
693 | | #endif |
694 | | |
695 | 7.19k | free(f); |
696 | | |
697 | 7.19k | return free_fd(fd); |
698 | | |
699 | 1.47M | } else if (f->type == FD_TYPE_TIMER) { |
700 | | #ifdef PRINTF_DEBUG |
701 | | printf("Closing timer fd: %d\n", fd); |
702 | | #endif |
703 | | |
704 | 14.3k | free(f); |
705 | | |
706 | 14.3k | return free_fd(fd); |
707 | 1.46M | } else if (f->type == FD_TYPE_EVENT) { |
708 | | #ifdef PRINTF_DEBUG |
709 | | printf("Closing event fd: %d\n", fd); |
710 | | #endif |
711 | | |
712 | 7.19k | free(f); |
713 | | |
714 | 7.19k | return free_fd(fd); |
715 | 1.45M | } else if (f->type == FD_TYPE_SOCKET) { |
716 | | #ifdef PRINTF_DEBUG |
717 | | printf("Closing socket fd: %d\n", fd); |
718 | | #endif |
719 | | |
720 | | // we should call epoll_ctl remove here |
721 | | |
722 | 1.45M | free(f); |
723 | | |
724 | 1.45M | int ret = free_fd(fd); |
725 | | |
726 | | #ifdef PRINTF_DEBUG |
727 | | printf("Ret: %d\n", ret); |
728 | | #endif |
729 | | |
730 | | //free(-1); |
731 | 1.45M | return ret; |
732 | 1.45M | } |
733 | | |
734 | 0 | return -1; |
735 | 1.48M | } |
736 | | |
737 | 7.19k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
738 | 7.19k | set_consumable_data(data, size); |
739 | | |
740 | 7.19k | test(); |
741 | | |
742 | 7.19k | if (num_fds) { |
743 | 0 | printf("ERROR! Cannot leave open FDs after test!\n"); |
744 | 0 | } |
745 | | |
746 | 7.19k | return 0; |
747 | 7.19k | } |
748 | | |
749 | | #ifdef __cplusplus |
750 | | } |
751 | | #endif |