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