1 /*
2 american fuzzy lop++ - afl-untracer skeleton example
3 ---------------------------------------------------
4
5 Written by Marc Heuse <mh@mh-sec.de>
6
7 Copyright 2019-2022 AFLplusplus Project. All rights reserved.
8
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at:
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15
16 HOW-TO
17 ======
18
19 You only need to change the following:
20
21 1. decide if you want to receive data from stdin [DEFAULT] or file(name)
22 -> use_stdin = 0 if via file, and what the maximum input size is
23 2. dl load the library you want to fuzz, lookup the functions you need
24 and setup the calls to these
25 3. in the while loop you call the functions in the necessary order -
26 incl the cleanup. the cleanup is important!
27
28 Just look these steps up in the code, look for "// STEP x:"
29
30
31 */
32
33 #define __USE_GNU
34 #define _GNU_SOURCE
35
36 #ifdef __ANDROID__
37 #include "android-ashmem.h"
38 #endif
39 #include "config.h"
40 #include "types.h"
41 #include "debug.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <signal.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <assert.h>
49 #include <stdint.h>
50 #include <errno.h>
51 #include <dlfcn.h>
52 #include <fcntl.h>
53 #include <pthread.h>
54
55 #include <sys/mman.h>
56 #include <sys/shm.h>
57 #include <sys/wait.h>
58 #include <sys/types.h>
59
60 #if defined(__linux__)
61 #include <sys/personality.h>
62 #include <sys/ucontext.h>
63 #elif defined(__APPLE__) && defined(__LP64__)
64 #include <mach-o/dyld_images.h>
65 #elif defined(__FreeBSD__)
66 #include <sys/sysctl.h>
67 #include <sys/user.h>
68 #include <sys/procctl.h>
69 #else
70 #error "Unsupported platform"
71 #endif
72
73 #define MEMORY_MAP_DECREMENT 0x200000000000
74 #define MAX_LIB_COUNT 128
75
76 // STEP 1:
77
78 /* here you need to specify the parameter for the target function */
79 static void *(*o_function)(u8 *buf, int len);
80
81 /* use stdin (1) or a file on the commandline (0) */
82 static u32 use_stdin = 1;
83
84 /* This is were the testcase data is written into */
85 static u8 buf[10000]; // this is the maximum size for a test case! set it!
86
87 /* If you want to have debug output set this to 1, can also be set with
88 AFL_DEBUG */
89 static u32 debug = 0;
90
91 // END STEP 1
92
93 typedef struct library_list {
94
95 u8 *name;
96 u64 addr_start, addr_end;
97
98 } library_list_t;
99
100 #ifdef __ANDROID__
101 u32 __afl_map_size = MAP_SIZE;
102 u32 do_exit;
103 #else
104 __thread u32 __afl_map_size = MAP_SIZE;
105 __thread u32 do_exit;
106 #endif
107
108 static pid_t pid = 65537;
109 static pthread_t __afl_thread;
110 static u8 __afl_dummy[MAP_SIZE];
111 static u8 * __afl_area_ptr = __afl_dummy;
112 static u8 * inputfile; // this will point to argv[1]
113 static u32 len;
114
115 static library_list_t liblist[MAX_LIB_COUNT];
116 static u32 liblist_cnt;
117
118 static void sigtrap_handler(int signum, siginfo_t *si, void *context);
119 static void fuzz(void);
120
121 /* read the library information */
read_library_information(void)122 void read_library_information(void) {
123
124 #if defined(__linux__)
125 FILE *f;
126 u8 buf[1024], *b, *m, *e, *n;
127
128 if ((f = fopen("/proc/self/maps", "r")) == NULL)
129 FATAL("cannot open /proc/self/maps");
130
131 if (debug) fprintf(stderr, "Library list:\n");
132 while (fgets(buf, sizeof(buf), f)) {
133
134 if (strstr(buf, " r-x")) {
135
136 if (liblist_cnt >= MAX_LIB_COUNT) {
137
138 WARNF("too many libraries to old, maximum count of %d reached",
139 liblist_cnt);
140 return;
141
142 }
143
144 b = buf;
145 m = index(buf, '-');
146 e = index(buf, ' ');
147 if ((n = strrchr(buf, '/')) == NULL) n = strrchr(buf, ' ');
148 if (n &&
149 ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
150 n = NULL;
151 else
152 n++;
153 if (b && m && e && n && *n) {
154
155 *m++ = 0;
156 *e = 0;
157 if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
158
159 liblist[liblist_cnt].name = strdup(n);
160 liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
161 liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
162 if (debug)
163 fprintf(
164 stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
165 liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
166 liblist[liblist_cnt].addr_start,
167 liblist[liblist_cnt].addr_end - 1);
168 liblist_cnt++;
169
170 }
171
172 }
173
174 }
175
176 if (debug) fprintf(stderr, "\n");
177
178 #elif defined(__FreeBSD__)
179 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
180 char * buf, *start, *end;
181 size_t miblen = sizeof(mib) / sizeof(mib[0]);
182 size_t len;
183
184 if (debug) fprintf(stderr, "Library list:\n");
185 if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
186
187 len = len * 4 / 3;
188
189 buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
190 if (buf == MAP_FAILED) { return; }
191
192 if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
193
194 munmap(buf, len);
195 return;
196
197 }
198
199 start = buf;
200 end = buf + len;
201
202 while (start < end) {
203
204 struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
205 size_t size = region->kve_structsize;
206
207 if (size == 0) { break; }
208
209 if ((region->kve_protection & KVME_PROT_READ) &&
210 !(region->kve_protection & KVME_PROT_EXEC)) {
211
212 liblist[liblist_cnt].name =
213 region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
214 liblist[liblist_cnt].addr_start = region->kve_start;
215 liblist[liblist_cnt].addr_end = region->kve_end;
216
217 if (debug) {
218
219 fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
220 liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
221 liblist[liblist_cnt].addr_start,
222 liblist[liblist_cnt].addr_end - 1);
223
224 }
225
226 liblist_cnt++;
227
228 }
229
230 start += size;
231
232 }
233
234 #endif
235
236 }
237
find_library(char * name)238 library_list_t *find_library(char *name) {
239
240 #if defined(__linux__)
241 u32 i;
242
243 for (i = 0; i < liblist_cnt; i++)
244 if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i];
245 #elif defined(__APPLE__) && defined(__LP64__)
246 kern_return_t err;
247 static library_list_t lib;
248
249 // get the list of all loaded modules from dyld
250 // the task_info mach API will get the address of the dyld all_image_info
251 // struct for the given task from which we can get the names and load
252 // addresses of all modules
253 task_dyld_info_data_t task_dyld_info;
254 mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
255 err = task_info(mach_task_self(), TASK_DYLD_INFO,
256 (task_info_t)&task_dyld_info, &count);
257
258 const struct dyld_all_image_infos *all_image_infos =
259 (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
260 const struct dyld_image_info *image_infos = all_image_infos->infoArray;
261
262 for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
263
264 const char * image_name = image_infos[i].imageFilePath;
265 mach_vm_address_t image_load_address =
266 (mach_vm_address_t)image_infos[i].imageLoadAddress;
267 if (strstr(image_name, name)) {
268
269 lib.name = name;
270 lib.addr_start = (u64)image_load_address;
271 lib.addr_end = 0;
272 return &lib;
273
274 }
275
276 }
277
278 #endif
279
280 return NULL;
281
282 }
283
284 /* for having an easy breakpoint location after loading the shared library */
285 // this seems to work for clang too. nice :) requires gcc 4.4+
286 #pragma GCC push_options
287 #pragma GCC optimize("O0")
breakpoint(void)288 void breakpoint(void) {
289
290 if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
291
292 }
293
294 #pragma GCC pop_options
295
296 /* Error reporting to forkserver controller */
297
send_forkserver_error(int error)298 void send_forkserver_error(int error) {
299
300 u32 status;
301 if (!error || error > 0xffff) return;
302 status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
303 if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
304
305 }
306
307 /* SHM setup. */
308
__afl_map_shm(void)309 static void __afl_map_shm(void) {
310
311 char *id_str = getenv(SHM_ENV_VAR);
312 char *ptr;
313
314 if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
315
316 u32 val = atoi(ptr);
317 if (val > 0) __afl_map_size = val;
318
319 }
320
321 if (__afl_map_size > MAP_SIZE) {
322
323 if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
324
325 fprintf(stderr,
326 "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
327 "be able to run this instrumented program!\n",
328 __afl_map_size);
329 if (id_str) {
330
331 send_forkserver_error(FS_ERROR_MAP_SIZE);
332 exit(-1);
333
334 }
335
336 } else {
337
338 fprintf(stderr,
339 "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
340 "be able to run this instrumented program!\n",
341 __afl_map_size);
342
343 }
344
345 }
346
347 if (id_str) {
348
349 #ifdef USEMMAP
350 const char * shm_file_path = id_str;
351 int shm_fd = -1;
352 unsigned char *shm_base = NULL;
353
354 /* create the shared memory segment as if it was a file */
355 shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
356 if (shm_fd == -1) {
357
358 fprintf(stderr, "shm_open() failed\n");
359 send_forkserver_error(FS_ERROR_SHM_OPEN);
360 exit(1);
361
362 }
363
364 /* map the shared memory segment to the address space of the process */
365 shm_base =
366 mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
367
368 if (shm_base == MAP_FAILED) {
369
370 close(shm_fd);
371 shm_fd = -1;
372
373 fprintf(stderr, "mmap() failed\n");
374 send_forkserver_error(FS_ERROR_MMAP);
375 exit(2);
376
377 }
378
379 __afl_area_ptr = shm_base;
380 #else
381 u32 shm_id = atoi(id_str);
382
383 __afl_area_ptr = shmat(shm_id, 0, 0);
384
385 #endif
386
387 if (__afl_area_ptr == (void *)-1) {
388
389 send_forkserver_error(FS_ERROR_SHMAT);
390 exit(1);
391
392 }
393
394 /* Write something into the bitmap so that the parent doesn't give up */
395
396 __afl_area_ptr[0] = 1;
397
398 }
399
400 }
401
402 /* Fork server logic. */
__afl_start_forkserver(void)403 inline static void __afl_start_forkserver(void) {
404
405 u8 tmp[4] = {0, 0, 0, 0};
406 u32 status = 0;
407
408 if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
409 status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
410 if (status) status |= (FS_OPT_ENABLED);
411 memcpy(tmp, &status, 4);
412
413 /* Phone home and tell the parent that we're OK. */
414 if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1;
415 // fprintf(stderr, "write0 %d\n", do_exit);
416
417 }
418
__afl_next_testcase(u8 * buf,u32 max_len)419 inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
420
421 s32 status;
422
423 /* Wait for parent by reading from the pipe. Abort if read fails. */
424 if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1;
425 // fprintf(stderr, "read %d\n", do_exit);
426
427 /* we have a testcase - read it if we read from stdin */
428 if (use_stdin) {
429
430 if ((status = read(0, buf, max_len)) <= 0) exit(-1);
431
432 } else
433
434 status = 1;
435 // fprintf(stderr, "stdin: %d %d\n", use_stdin, status);
436
437 /* report that we are starting the target */
438 if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
439 // fprintf(stderr, "write1 %d\n", do_exit);
440
441 __afl_area_ptr[0] = 1; // put something in the map
442
443 return status;
444
445 }
446
__afl_end_testcase(int status)447 inline static void __afl_end_testcase(int status) {
448
449 if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
450 // fprintf(stderr, "write2 %d\n", do_exit);
451 if (do_exit) exit(0);
452
453 }
454
455 #ifdef __aarch64__
456 #define SHADOW(addr) \
457 ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
458 MEMORY_MAP_DECREMENT - \
459 ((uintptr_t)addr & 0x7) * 0x10000000000))
460 #else
461 #define SHADOW(addr) \
462 ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
463 MEMORY_MAP_DECREMENT - \
464 ((uintptr_t)addr & 0x3) * 0x10000000000))
465 #endif
466
setup_trap_instrumentation(void)467 void setup_trap_instrumentation(void) {
468
469 library_list_t *lib_base = NULL;
470 size_t lib_size = 0;
471 u8 * lib_addr;
472 char * line = NULL;
473 size_t nread, len = 0;
474 char * filename = getenv("AFL_UNTRACER_FILE");
475 if (!filename) filename = getenv("TRAPFUZZ_FILE");
476 if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
477
478 FILE *patches = fopen(filename, "r");
479 if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
480
481 // Index into the coverage bitmap for the current trap instruction.
482 #ifdef __aarch64__
483 uint64_t bitmap_index = 0;
484 #ifdef __APPLE__
485 pthread_jit_write_protect_np(0);
486 #endif
487 #else
488 uint32_t bitmap_index = 0;
489 #endif
490
491 while ((nread = getline(&line, &len, patches)) != -1) {
492
493 char *end = line + len;
494
495 char *col = strchr(line, ':');
496 if (col) {
497
498 // It's a library:size pair
499 *col++ = 0;
500
501 lib_base = find_library(line);
502 if (!lib_base) FATAL("Library %s does not appear to be loaded", line);
503
504 // we ignore the defined lib_size
505 lib_size = strtoul(col, NULL, 16);
506 #if (__linux__)
507 if (lib_size < lib_base->addr_end - lib_base->addr_start)
508 lib_size = lib_base->addr_end - lib_base->addr_start;
509 #endif
510 if (lib_size % 0x1000 != 0)
511 WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000",
512 lib_size);
513
514 lib_addr = (u8 *)lib_base->addr_start;
515 // Make library code writable.
516 if (mprotect((void *)lib_addr, lib_size,
517 PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
518 FATAL("Failed to mprotect library %s writable", line);
519
520 // Create shadow memory.
521 #ifdef __aarch64__
522 for (int i = 0; i < 8; i++) {
523
524 #else
525 for (int i = 0; i < 4; i++) {
526
527 #endif
528
529 void *shadow_addr = SHADOW(lib_addr + i);
530 void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
531 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
532 if (debug)
533 fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow,
534 shadow + lib_size - 1, lib_addr);
535 if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory");
536
537 }
538
539 // Done, continue with next line.
540 continue;
541
542 }
543
544 // It's an offset, parse it and do the patching.
545 unsigned long offset = strtoul(line, NULL, 16);
546
547 if (offset > lib_size)
548 FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
549 offset, lib_size);
550
551 if (bitmap_index >= __afl_map_size)
552 FATAL("Too many basic blocks to instrument");
553
554 #ifdef __arch64__
555 uint64_t
556 #else
557 uint32_t
558 #endif
559 *shadow = SHADOW(lib_addr + offset);
560 if (*shadow != 0) continue; // skip duplicates
561
562 // Make lookup entry in shadow memory.
563
564 #if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
565 defined(__i386__))
566
567 // this is for Intel x64
568
569 uint8_t orig_byte = lib_addr[offset];
570 *shadow = (bitmap_index << 8) | orig_byte;
571 lib_addr[offset] = 0xcc; // replace instruction with debug trap
572 if (debug)
573 fprintf(stderr,
574 "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %08x\n",
575 lib_addr, offset, lib_addr + offset, orig_byte, shadow,
576 bitmap_index, *shadow);
577
578 #elif defined(__aarch64__)
579
580 // this is for aarch64
581
582 uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
583 uint32_t orig_bytes = *patch_bytes;
584 *shadow = (bitmap_index << 32) | orig_bytes;
585 *patch_bytes = 0xd4200000; // replace instruction with debug trap
586 if (debug)
587 fprintf(stderr,
588 "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
589 lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
590 bitmap_index, *shadow);
591
592 #else
593 // this will be ARM and AARCH64
594 // for ARM we will need to identify if the code is in thumb or ARM
595 #error "non x86_64/aarch64 not supported yet"
596 //__arm__:
597 // linux thumb: 0xde01
598 // linux arm: 0xe7f001f0
599 //__aarch64__:
600 // linux aarch64: 0xd4200000
601 #endif
602
603 bitmap_index++;
604
605 }
606
607 free(line);
608 fclose(patches);
609
610 // Install signal handler for SIGTRAP.
611 struct sigaction s;
612 s.sa_flags = SA_SIGINFO;
613 s.sa_sigaction = sigtrap_handler;
614 sigemptyset(&s.sa_mask);
615 sigaction(SIGTRAP, &s, 0);
616
617 if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index);
618 __afl_map_size = bitmap_index;
619 if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3);
620
621 }
622
623 /* the signal handler for the traps / debugging interrupts
624 No debug output here because this would cost speed */
625 static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
626
627 uint64_t addr;
628 // Must re-execute the instruction, so decrement PC by one instruction.
629 ucontext_t *ctx = (ucontext_t *)context;
630 #if defined(__APPLE__) && defined(__LP64__)
631 #if defined(__x86_64__)
632 ctx->uc_mcontext->__ss.__rip -= 1;
633 addr = ctx->uc_mcontext->__ss.__rip;
634 #else
635 ctx->uc_mcontext->__ss.__pc -= 4;
636 addr = ctx->uc_mcontext->__ss.__pc;
637 #endif
638 #elif defined(__linux__)
639 #if defined(__x86_64__) || defined(__i386__)
640 ctx->uc_mcontext.gregs[REG_RIP] -= 1;
641 addr = ctx->uc_mcontext.gregs[REG_RIP];
642 #elif defined(__aarch64__)
643 ctx->uc_mcontext.pc -= 4;
644 addr = ctx->uc_mcontext.pc;
645 #else
646 #error "Unsupported processor"
647 #endif
648 #elif defined(__FreeBSD__) && defined(__LP64__)
649 ctx->uc_mcontext.mc_rip -= 1;
650 addr = ctx->uc_mcontext.mc_rip;
651 #else
652 #error "Unsupported platform"
653 #endif
654
655 // fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr,
656 // si->si_addr);
657
658 // If the trap didn't come from our instrumentation, then we probably will
659 // just segfault here
660 uint8_t *faultaddr;
661 if (unlikely(si->si_addr))
662 faultaddr = (u8 *)si->si_addr - 1;
663 else
664 faultaddr = (u8 *)addr;
665 // if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr));
666 uint32_t shadow = *SHADOW(faultaddr);
667 uint8_t orig_byte = shadow & 0xff;
668 uint32_t index = shadow >> 8;
669
670 // if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n",
671 // shadow, orig_byte, index);
672
673 // Index zero is invalid so that it is still possible to catch actual trap
674 // instructions in instrumented libraries.
675 if (unlikely(index == 0)) abort();
676
677 // Restore original instruction
678 *faultaddr = orig_byte;
679
680 __afl_area_ptr[index] = 128;
681
682 }
683
684 /* the MAIN function */
685 int main(int argc, char *argv[]) {
686
687 #if defined(__linux__)
688 (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR
689 #elif defined(__FreeBSD__) && __FreeBSD_version >= 1200000
690 int no_randomize = PROC_ASLR_FORCE_DISABLE;
691 (void)procctl(P_PID, 0, PROC_ASLR_CTL, &no_randomize);
692 #endif
693
694 pid = getpid();
695 if (getenv("AFL_DEBUG")) debug = 1;
696
697 /* by default we use stdin, but also a filename can be passed, in this
698 case the input is argv[1] and we have to disable stdin */
699 if (argc > 1) {
700
701 use_stdin = 0;
702 inputfile = argv[1];
703
704 }
705
706 // STEP 2: load the library you want to fuzz and lookup the functions,
707 // inclusive of the cleanup functions
708 // NOTE: above the main() you have to define the functions!
709
710 void *dl = dlopen("./libtestinstr.so", RTLD_LAZY);
711 if (!dl) FATAL("could not find target library");
712 o_function = dlsym(dl, "testinstr");
713 if (!o_function) FATAL("could not resolve target function from library");
714 if (debug) fprintf(stderr, "Function address: %p\n", o_function);
715
716 // END STEP 2
717
718 /* setup instrumentation, shared memory and forkserver */
719 breakpoint();
720 read_library_information();
721 setup_trap_instrumentation();
722 __afl_map_shm();
723 __afl_start_forkserver();
724
725 while (1) {
726
727 // instead of fork() we could also use the snapshot lkm or do our own mini
728 // snapshot feature like in https://github.com/marcinguy/fuzzer
729 // -> snapshot.c
730 if ((pid = fork()) == -1) PFATAL("fork failed");
731
732 if (pid) {
733
734 u32 status;
735 if (waitpid(pid, &status, 0) < 0) exit(1);
736 /* report the test case is done and wait for the next */
737 __afl_end_testcase(status);
738
739 } else {
740
741 pid = getpid();
742 while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
743
744 // in this function the fuzz magic happens, this is STEP 3
745 fuzz();
746
747 // we can use _exit which is faster because our target library
748 // was loaded via dlopen and therefore cannot have deconstructors
749 // registered.
750 _exit(0);
751
752 }
753
754 }
755
756 }
757
758 return 0;
759
760 }
761
762 #ifndef _DEBUG
763 inline
764 #endif
765 static void
766 fuzz(void) {
767
768 // STEP 3: call the function to fuzz, also the functions you might
769 // need to call to prepare the function and - important! -
770 // to clean everything up
771
772 // in this example we use the input file, not stdin!
773 (*o_function)(buf, len);
774
775 // normally you also need to cleanup
776 //(*o_LibFree)(foo);
777
778 // END STEP 3
779
780 }
781
782