• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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