libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

fuzz_common.h (29696B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2026 Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19  */
     20 /**
     21  * @file fuzz/fuzz_common.h
     22  * @brief shared, header-only fuzzing driver for the libextractor fuzzers
     23  * @author Christian Grothoff
     24  *
     25  * Every harness in this directory is a single translation unit that
     26  * includes this header.  The header provides:
     27  *  - a deterministic, seeded PRNG (splitmix64 / xoshiro256**),
     28  *  - a generic byte-level mutator,
     29  *  - crash bookkeeping (the input of the currently running iteration is
     30  *    dumped to the crash directory whenever the process dies),
     31  *  - a standalone @c main() driver (generator + mutator loop, corpus
     32  *    replay, single-file replay) so that the harnesses are usable with
     33  *    a plain gcc + ASAN/UBSAN build, i.e. without clang/libFuzzer.
     34  *
     35  * The harness itself must provide:
     36  *  - @c LLVMFuzzerTestOneInput() (the actual fuzz target),
     37  *  - @c fuzz_generate() (a structure-aware input generator),
     38  *  - @c fuzz_seed_count() / @c fuzz_seed_get() (a built-in seed corpus).
     39  *
     40  * Define @c FUZZ_NO_MAIN when linking against libFuzzer or AFL++'s
     41  * driver, which supply their own @c main().  Anything the fuzz *target*
     42  * needs must stay outside the @c FUZZ_NO_MAIN block; see
     43  * BUILD-INTEGRATION.md section 6.
     44  */
     45 #ifndef LE_FUZZ_COMMON_H
     46 #define LE_FUZZ_COMMON_H 1
     47 
     48 #include <stdint.h>
     49 #include <stddef.h>
     50 #include <stdio.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 #include <unistd.h>
     54 #include <fcntl.h>
     55 #include <signal.h>
     56 #include <errno.h>
     57 #include <sys/stat.h>
     58 #include <sys/types.h>
     59 #include <dirent.h>
     60 
     61 #ifndef FUZZ_HARNESS_NAME
     62 #define FUZZ_HARNESS_NAME "fuzz"
     63 #endif
     64 
     65 /**
     66  * Not every harness uses every helper; silence -Wunused-function.
     67  */
     68 #define FUZZ_UNUSED __attribute__ ((unused))
     69 
     70 /**
     71  * Hard upper bound on the size of a single fuzz input.  libextractor
     72  * parses container formats whose interesting structures (a ZIP central
     73  * directory, an OLE2 FAT, a RIFF chunk tree) live well past the first
     74  * few kilobytes, so this is considerably larger than a protocol fuzzer
     75  * would need.
     76  */
     77 #ifndef FUZZ_MAX_INPUT
     78 #define FUZZ_MAX_INPUT (256 * 1024)
     79 #endif
     80 
     81 /**
     82  * Default number of iterations of the built-in driver.  Kept small so
     83  * that "make check" stays in the "couple of seconds" range; raise with
     84  * --iterations=N or the LE_FUZZ_ITERATIONS environment variable.
     85  */
     86 #ifndef FUZZ_DEFAULT_ITERATIONS
     87 #define FUZZ_DEFAULT_ITERATIONS 3000
     88 #endif
     89 
     90 /**
     91  * Default per-iteration watchdog, in seconds.
     92  */
     93 #ifndef FUZZ_DEFAULT_TIMEOUT
     94 #define FUZZ_DEFAULT_TIMEOUT 20
     95 #endif
     96 
     97 
     98 /* ------------------------------------------------------------------ */
     99 /* Interface to be implemented by each harness                        */
    100 /* ------------------------------------------------------------------ */
    101 
    102 /**
    103  * The fuzz target.  Signature is the libFuzzer one on purpose, so that
    104  * the very same harness can be linked with libFuzzer or AFL++.
    105  */
    106 int
    107 LLVMFuzzerTestOneInput (const uint8_t *data,
    108                         size_t size);
    109 
    110 struct fuzz_rng;
    111 
    112 /**
    113  * Structure-aware generator used by the built-in standalone driver.
    114  * Must write at most @a cap bytes to @a buf and return the number of
    115  * bytes written.  Purely random bytes almost never form a file that
    116  * gets past a plugin's magic-number check, so this is what actually
    117  * makes the gcc-only driver useful.
    118  */
    119 FUZZ_UNUSED static size_t
    120 fuzz_generate (struct fuzz_rng *rng,
    121                uint8_t *buf,
    122                size_t cap);
    123 
    124 /**
    125  * @return number of entries in the built-in seed corpus
    126  */
    127 FUZZ_UNUSED static size_t
    128 fuzz_seed_count (void);
    129 
    130 /**
    131  * @param idx index of the seed to retrieve
    132  * @param[out] len set to the length of the seed
    133  * @return pointer to the seed bytes
    134  */
    135 FUZZ_UNUSED static const uint8_t *
    136 fuzz_seed_get (size_t idx,
    137                size_t *len);
    138 
    139 
    140 /* ------------------------------------------------------------------ */
    141 /* Deterministic PRNG                                                  */
    142 /* ------------------------------------------------------------------ */
    143 
    144 struct fuzz_rng
    145 {
    146   uint64_t s[4];
    147 };
    148 
    149 
    150 FUZZ_UNUSED static uint64_t
    151 fuzz_splitmix64 (uint64_t *x)
    152 {
    153   uint64_t z;
    154 
    155   *x += UINT64_C (0x9E3779B97F4A7C15);
    156   z = *x;
    157   z = (z ^ (z >> 30)) * UINT64_C (0xBF58476D1CE4E5B9);
    158   z = (z ^ (z >> 27)) * UINT64_C (0x94D049BB133111EB);
    159   return z ^ (z >> 31);
    160 }
    161 
    162 
    163 FUZZ_UNUSED static void
    164 fuzz_rng_seed (struct fuzz_rng *r,
    165                uint64_t seed)
    166 {
    167   uint64_t x = seed;
    168   unsigned int i;
    169 
    170   for (i = 0; i < 4; i++)
    171     r->s[i] = fuzz_splitmix64 (&x);
    172 }
    173 
    174 
    175 FUZZ_UNUSED static uint64_t
    176 fuzz_rot64 (uint64_t x,
    177             unsigned int k)
    178 {
    179   return (x << k) | (x >> (64 - k));
    180 }
    181 
    182 
    183 /**
    184  * xoshiro256** -- small, fast, deterministic and identical on every
    185  * platform, which is what we need for reproducible fuzzing runs.
    186  */
    187 FUZZ_UNUSED static uint64_t
    188 fuzz_next (struct fuzz_rng *r)
    189 {
    190   const uint64_t res = fuzz_rot64 (r->s[1] * 5, 7) * 9;
    191   const uint64_t t = r->s[1] << 17;
    192 
    193   r->s[2] ^= r->s[0];
    194   r->s[3] ^= r->s[1];
    195   r->s[1] ^= r->s[2];
    196   r->s[0] ^= r->s[3];
    197   r->s[2] ^= t;
    198   r->s[3] = fuzz_rot64 (r->s[3], 45);
    199   return res;
    200 }
    201 
    202 
    203 /**
    204  * @return uniformly distributed value in [0, n), 0 if @a n is 0
    205  */
    206 FUZZ_UNUSED static uint32_t
    207 fuzz_below (struct fuzz_rng *r,
    208             uint32_t n)
    209 {
    210   if (0 == n)
    211     return 0;
    212   return (uint32_t) (fuzz_next (r) % n);
    213 }
    214 
    215 
    216 FUZZ_UNUSED static uint8_t
    217 fuzz_byte (struct fuzz_rng *r)
    218 {
    219   return (uint8_t) (fuzz_next (r) & 0xFF);
    220 }
    221 
    222 
    223 /**
    224  * @return true with a probability of 1/@a n
    225  */
    226 FUZZ_UNUSED static int
    227 fuzz_chance (struct fuzz_rng *r,
    228              uint32_t n)
    229 {
    230   return 0 == fuzz_below (r, n);
    231 }
    232 
    233 
    234 /**
    235  * Append @a n little-endian bytes of @a v to @a buf.
    236  *
    237  * @param buf buffer to append to
    238  * @param[in,out] len current length, updated
    239  * @param cap capacity of @a buf
    240  * @param v value to append
    241  * @param n number of bytes of @a v to append
    242  */
    243 FUZZ_UNUSED static void
    244 fuzz_put_le (uint8_t *buf,
    245              size_t *len,
    246              size_t cap,
    247              uint64_t v,
    248              unsigned int n)
    249 {
    250   unsigned int i;
    251 
    252   for (i = 0; i < n; i++)
    253   {
    254     if (*len >= cap)
    255       return;
    256     buf[(*len)++] = (uint8_t) (v >> (8 * i));
    257   }
    258 }
    259 
    260 
    261 /**
    262  * Append @a n big-endian bytes of @a v to @a buf.
    263  *
    264  * @param buf buffer to append to
    265  * @param[in,out] len current length, updated
    266  * @param cap capacity of @a buf
    267  * @param v value to append
    268  * @param n number of bytes of @a v to append
    269  */
    270 FUZZ_UNUSED static void
    271 fuzz_put_be (uint8_t *buf,
    272              size_t *len,
    273              size_t cap,
    274              uint64_t v,
    275              unsigned int n)
    276 {
    277   unsigned int i;
    278 
    279   for (i = 0; i < n; i++)
    280   {
    281     if (*len >= cap)
    282       return;
    283     buf[(*len)++] = (uint8_t) (v >> (8 * (n - 1 - i)));
    284   }
    285 }
    286 
    287 
    288 /**
    289  * Append @a n bytes from @a src to @a buf, truncating at @a cap.
    290  */
    291 FUZZ_UNUSED static void
    292 fuzz_put_mem (uint8_t *buf,
    293               size_t *len,
    294               size_t cap,
    295               const void *src,
    296               size_t n)
    297 {
    298   if (*len + n > cap)
    299     n = (*len > cap) ? 0 : (cap - *len);
    300   memcpy (buf + *len, src, n);
    301   *len += n;
    302 }
    303 
    304 
    305 /**
    306  * Append the NUL-terminated string @a s (without its NUL) to @a buf.
    307  */
    308 FUZZ_UNUSED static void
    309 fuzz_put_str (uint8_t *buf,
    310               size_t *len,
    311               size_t cap,
    312               const char *s)
    313 {
    314   fuzz_put_mem (buf, len, cap, s, strlen (s));
    315 }
    316 
    317 
    318 /* ------------------------------------------------------------------ */
    319 /* Global driver state                                                 */
    320 /* ------------------------------------------------------------------ */
    321 
    322 /**
    323  * Non-zero if the input of the current iteration comes from a trusted
    324  * source (the built-in generator, the built-in seed corpus, --file or
    325  * --corpus-dir) and has NOT been mutated afterwards.  Harnesses use
    326  * this to enable "ground truth" oracles.  Random mutations invalidate
    327  * such declarations, hence the flag.
    328  */
    329 FUZZ_UNUSED static int fuzz_pristine;
    330 
    331 /**
    332  * Non-zero to let the harness be chatty about what it is doing.
    333  */
    334 FUZZ_UNUSED static int fuzz_verbose;
    335 
    336 /**
    337  * Non-zero to skip the replay of the built-in seed corpus at the start
    338  * of a run (useful when a seed is known to trigger an already-reported
    339  * finding and one wants to look for others).
    340  */
    341 FUZZ_UNUSED static int fuzz_skip_seeds;
    342 
    343 /* Only read by the built-in driver; under -DFUZZ_NO_MAIN (the libFuzzer
    344    and AFL++ builds, see contrib/oss-fuzz/build.sh) they are written but
    345    never read, which is not a defect. */
    346 FUZZ_UNUSED static uint64_t fuzz_cur_seed;
    347 FUZZ_UNUSED static uint64_t fuzz_cur_iter;
    348 static const uint8_t *fuzz_cur_input;
    349 static size_t fuzz_cur_input_len;
    350 static const char *fuzz_crash_dir = "crashes";
    351 
    352 /* Pre-rendered, so that the death/signal handlers stay
    353    async-signal-safe (no snprintf, no malloc). */
    354 static char fuzz_crash_path[512];
    355 static char fuzz_crash_msg[512];
    356 static volatile sig_atomic_t fuzz_dumped;
    357 
    358 
    359 FUZZ_UNUSED static void
    360 fuzz_write_all (int fd,
    361                 const void *buf,
    362                 size_t len)
    363 {
    364   const char *p = (const char *) buf;
    365 
    366   while (0 != len)
    367   {
    368     ssize_t w = write (fd, p, len);
    369 
    370     if (0 >= w)
    371       break;
    372     p += w;
    373     len -= (size_t) w;
    374   }
    375 }
    376 
    377 
    378 FUZZ_UNUSED static void
    379 fuzz_msg (const char *s)
    380 {
    381   fuzz_write_all (STDERR_FILENO, s, strlen (s));
    382 }
    383 
    384 
    385 /**
    386  * Dump the input of the currently running iteration so that the
    387  * failure can be replayed with --file=...  Async-signal-safe.
    388  */
    389 FUZZ_UNUSED static void
    390 fuzz_dump_current (void)
    391 {
    392   int fd;
    393 
    394   if (fuzz_dumped)
    395     return;
    396   fuzz_dumped = 1;
    397   if ( (NULL == fuzz_cur_input) ||
    398        ('\0' == fuzz_crash_path[0]) )
    399     return;
    400   (void) mkdir (fuzz_crash_dir, 0755);
    401   fd = open (fuzz_crash_path,
    402              O_WRONLY | O_CREAT | O_TRUNC,
    403              0644);
    404   if (0 > fd)
    405   {
    406     fuzz_msg ("\n*** FUZZ: failed to write crash file ***\n");
    407     return;
    408   }
    409   fuzz_write_all (fd, fuzz_cur_input, fuzz_cur_input_len);
    410   (void) close (fd);
    411   fuzz_msg ("\n*** FUZZ: reproducer written to ");
    412   fuzz_msg (fuzz_crash_path);
    413   fuzz_msg (" ***\n*** FUZZ: ");
    414   fuzz_msg (fuzz_crash_msg);
    415   fuzz_msg (" ***\n");
    416 }
    417 
    418 
    419 FUZZ_UNUSED static void
    420 fuzz_death_callback (void)
    421 {
    422   fuzz_dump_current ();
    423 }
    424 
    425 
    426 FUZZ_UNUSED static void
    427 fuzz_sig_handler (int sig)
    428 {
    429   fuzz_dump_current ();
    430   if (SIGALRM == sig)
    431   {
    432     fuzz_msg ("*** FUZZ: HANG detected (watchdog fired) ***\n");
    433     _exit (99);
    434   }
    435   /* restore default handler and re-raise so that the usual
    436      ASAN/abort diagnostics are produced */
    437   signal (sig, SIG_DFL);
    438   raise (sig);
    439 }
    440 
    441 
    442 /**
    443  * Report a logical (non-memory-safety) finding: dump the reproducer
    444  * and abort so that the failure is impossible to overlook.
    445  *
    446  * @param what human readable description of the contract violation
    447  */
    448 FUZZ_UNUSED static void
    449 fuzz_report_finding (const char *what)
    450 {
    451   size_t l = strlen (what);
    452 
    453   if (l >= sizeof (fuzz_crash_msg))
    454     l = sizeof (fuzz_crash_msg) - 1;
    455   memcpy (fuzz_crash_msg, what, l);
    456   fuzz_crash_msg[l] = '\0';
    457   fuzz_msg ("\n*** FUZZ FINDING: ");
    458   fuzz_msg (fuzz_crash_msg);
    459   fuzz_msg (" ***\n");
    460   fuzz_dump_current ();
    461   abort ();
    462 }
    463 
    464 
    465 /* Weak declaration: resolved when built with ASAN (gcc or clang),
    466    NULL otherwise.  ASAN calls this right before it terminates the
    467    process, which is the only reliable hook when abort_on_error=0. */
    468 extern void
    469 __sanitizer_set_death_callback (void (*cb)(void)) __attribute__ ((weak));
    470 
    471 
    472 /**
    473  * Ignore SIGPIPE.  Idempotent, so it is safe to call on every execution.
    474  *
    475  * This deliberately lives OUTSIDE the #ifndef FUZZ_NO_MAIN block below,
    476  * because it is needed by the fuzz *target*, not merely by the built-in
    477  * driver: fuzz_extract runs plugins in-process but the core library
    478  * still writes to pipes in some code paths, and fuzz_ipc writes into a
    479  * socketpair whose peer end it closes on purpose.  None of the external
    480  * engines ignores SIGPIPE for us -- libFuzzer has no -handle_sigpipe
    481  * flag at all -- so without this an OSS-Fuzz build simply stops fuzzing
    482  * after a few dozen executions, with no report.
    483  */
    484 FUZZ_UNUSED static void
    485 fuzz_ignore_sigpipe (void)
    486 {
    487   static int sigpipe_ignored;
    488 
    489   if (sigpipe_ignored)
    490     return;
    491   sigpipe_ignored = 1;
    492   (void) signal (SIGPIPE, SIG_IGN);
    493 }
    494 
    495 
    496 /**
    497  * Read an unsigned integer from the environment.
    498  *
    499  * @param name variable to read
    500  * @param dflt value to return if unset or unparsable
    501  * @return the configured value
    502  */
    503 FUZZ_UNUSED static unsigned long
    504 fuzz_env_ulong (const char *name,
    505                 unsigned long dflt)
    506 {
    507   const char *e = getenv (name);
    508   char *end;
    509   unsigned long v;
    510 
    511   if (NULL == e)
    512     return dflt;
    513   errno = 0;
    514   v = strtoul (e, &end, 0);
    515   if ( (end == e) ||
    516        (0 != errno) )
    517     return dflt;
    518   return v;
    519 }
    520 
    521 
    522 #ifndef FUZZ_NO_MAIN
    523 
    524 static void
    525 fuzz_install_handlers (void)
    526 {
    527   struct sigaction sa;
    528 
    529   if (NULL != __sanitizer_set_death_callback)
    530     __sanitizer_set_death_callback (&fuzz_death_callback);
    531   memset (&sa, 0, sizeof (sa));
    532   sa.sa_handler = &fuzz_sig_handler;
    533   sigemptyset (&sa.sa_mask);
    534   sa.sa_flags = 0;
    535   (void) sigaction (SIGABRT, &sa, NULL);
    536   (void) sigaction (SIGSEGV, &sa, NULL);
    537   (void) sigaction (SIGBUS, &sa, NULL);
    538   (void) sigaction (SIGILL, &sa, NULL);
    539   (void) sigaction (SIGFPE, &sa, NULL);
    540   (void) sigaction (SIGALRM, &sa, NULL);
    541   fuzz_ignore_sigpipe ();
    542 }
    543 
    544 
    545 /**
    546  * Remember which input we are about to feed to the target, and
    547  * pre-render the name of the file it would be dumped to.
    548  */
    549 static void
    550 fuzz_set_current (const uint8_t *data,
    551                   size_t size,
    552                   const char *tag)
    553 {
    554   fuzz_cur_input = data;
    555   fuzz_cur_input_len = size;
    556   fuzz_dumped = 0;
    557   (void) snprintf (fuzz_crash_path,
    558                    sizeof (fuzz_crash_path),
    559                    "%s/crash-%s-seed%llu-iter%llu.bin",
    560                    fuzz_crash_dir,
    561                    FUZZ_HARNESS_NAME,
    562                    (unsigned long long) fuzz_cur_seed,
    563                    (unsigned long long) fuzz_cur_iter);
    564   (void) snprintf (fuzz_crash_msg,
    565                    sizeof (fuzz_crash_msg),
    566                    "harness=%s seed=%llu iteration=%llu source=%s",
    567                    FUZZ_HARNESS_NAME,
    568                    (unsigned long long) fuzz_cur_seed,
    569                    (unsigned long long) fuzz_cur_iter,
    570                    tag);
    571 }
    572 
    573 
    574 /* ------------------------------------------------------------------ */
    575 /* Generic byte-level mutator                                          */
    576 /* ------------------------------------------------------------------ */
    577 
    578 static const uint8_t fuzz_interesting[] = {
    579   0x00, 0x01, 0x02, 0x04, 0x07, 0x08, 0x09, 0x0A, 0x0D, 0x10, 0x1A,
    580   0x20, 0x22, 0x25, 0x27, 0x2C, 0x2E, 0x2F, 0x30, 0x3A, 0x3B, 0x3D,
    581   0x5C, 0x7B, 0x7D, 0x7F, 0x80, 0xC0, 0xFE, 0xFF
    582 };
    583 
    584 /**
    585  * Byte strings that are structurally meaningful to at least one of the
    586  * formats libextractor parses: container magic numbers, chunk tags and
    587  * the length fields that guard them.
    588  */
    589 static const char *const fuzz_interesting_str[] = {
    590   "RIFF", "WAVE", "AVI ", "LIST", "INFO", "fmt ", "data",
    591   "PK\x03\x04", "PK\x01\x02", "PK\x05\x06",
    592   "\x89PNG\r\n\x1a\n", "IHDR", "tEXt", "zTXt", "iTXt", "IEND",
    593   "GIF89a", "GIF87a", "\xff\xd8\xff\xe0", "\xff\xd8\xff\xe1", "Exif",
    594   "\x7f" "ELF", "%!PS-Adobe-", "%%Title:", "%%Creator:",
    595   "{\\rtf1", "\\info", "\\title", "\\*\\", "\\u", "\\'",
    596   "NESM\x1a", "NSFE", "PSID", "RSID", "SCRM", "IMPM",
    597   "Extended Module: ", "MThd", "MTrk", "fLaC", "OggS",
    598   "\x1f\x8b\x08", "BZh9", "!<arch>\n", "debian-binary",
    599   "moov", "mvhd", "ftyp", "mdat", "cmov",
    600   "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1",
    601   "\x00\x05\x16\x07\x00\x02\x00\x00",
    602   "\xf7\x02", "\xf7\x03", "\xed\xab\xee\xdb",
    603   "mimetypeapplication/vnd.oasis.opendocument.",
    604   "meta.xml", "content.xml", "docProps/core.xml", "word/document.xml",
    605   ".TH ", ".SH ", "\r\n", "\n", "\xff\xff\xff\xff", "\x00\x00\x00\x00"
    606 };
    607 
    608 
    609 /**
    610  * Apply a single random mutation to @a buf.
    611  *
    612  * @param rng the PRNG state
    613  * @param[in,out] buf the buffer to mutate
    614  * @param len current length
    615  * @param cap capacity of @a buf
    616  * @return new length
    617  */
    618 static size_t
    619 fuzz_mutate_once (struct fuzz_rng *rng,
    620                   uint8_t *buf,
    621                   size_t len,
    622                   size_t cap)
    623 {
    624   uint32_t op;
    625 
    626   if (0 == len)
    627   {
    628     buf[0] = fuzz_byte (rng);
    629     return 1;
    630   }
    631   op = fuzz_below (rng, 11);
    632   switch (op)
    633   {
    634   case 0:                      /* bit flip */
    635     {
    636       size_t p = fuzz_below (rng, (uint32_t) len);
    637 
    638       buf[p] = (uint8_t) (buf[p] ^ (1u << fuzz_below (rng, 8)));
    639       break;
    640     }
    641   case 1:                      /* random byte */
    642     buf[fuzz_below (rng, (uint32_t) len)] = fuzz_byte (rng);
    643     break;
    644   case 2:                      /* interesting byte */
    645     buf[fuzz_below (rng, (uint32_t) len)] =
    646       fuzz_interesting[fuzz_below (rng,
    647                                    (uint32_t) (sizeof (fuzz_interesting)))];
    648     break;
    649   case 3:                      /* add/sub small value */
    650     {
    651       size_t p = fuzz_below (rng, (uint32_t) len);
    652 
    653       buf[p] = (uint8_t) (buf[p] + (int) fuzz_below (rng, 17) - 8);
    654       break;
    655     }
    656   case 4:                      /* erase a run */
    657     {
    658       size_t p = fuzz_below (rng, (uint32_t) len);
    659       size_t n = 1 + fuzz_below (rng, (uint32_t) (len - p));
    660 
    661       memmove (buf + p, buf + p + n, len - p - n);
    662       len -= n;
    663       break;
    664     }
    665   case 5:                      /* insert repeated byte */
    666     {
    667       size_t p = fuzz_below (rng, (uint32_t) len + 1);
    668       size_t n = 1 + fuzz_below (rng, 64);
    669       uint8_t v = fuzz_byte (rng);
    670 
    671       if (len + n > cap)
    672         n = cap - len;
    673       if (0 == n)
    674         break;
    675       memmove (buf + p + n, buf + p, len - p);
    676       memset (buf + p, v, n);
    677       len += n;
    678       break;
    679     }
    680   case 6:                      /* duplicate a chunk */
    681     {
    682       size_t p = fuzz_below (rng, (uint32_t) len);
    683       size_t n = 1 + fuzz_below (rng, (uint32_t) (len - p));
    684       size_t d = fuzz_below (rng, (uint32_t) len + 1);
    685 
    686       if (len + n > cap)
    687         n = cap - len;
    688       if (0 == n)
    689         break;
    690       memmove (buf + d + n, buf + d, len - d);
    691       memmove (buf + d, buf + ((p >= d) ? (p + n) : p), n);
    692       len += n;
    693       break;
    694     }
    695   case 7:                      /* insert an interesting token */
    696     {
    697       const char *s =
    698         fuzz_interesting_str[fuzz_below (rng,
    699                                          (uint32_t)
    700                                          (sizeof (fuzz_interesting_str)
    701                                           / sizeof (fuzz_interesting_str[0])))];
    702       size_t n = strlen (s);
    703       size_t p = fuzz_below (rng, (uint32_t) len + 1);
    704 
    705       if (len + n > cap)
    706         break;
    707       memmove (buf + p + n, buf + p, len - p);
    708       memcpy (buf + p, s, n);
    709       len += n;
    710       break;
    711     }
    712   case 8:                      /* swap two bytes */
    713     {
    714       size_t a = fuzz_below (rng, (uint32_t) len);
    715       size_t b = fuzz_below (rng, (uint32_t) len);
    716       uint8_t t = buf[a];
    717 
    718       buf[a] = buf[b];
    719       buf[b] = t;
    720       break;
    721     }
    722   case 9:                      /* overwrite a 16/32 bit field with an
    723                                   extreme value; length fields are where
    724                                   the parser bugs are */
    725     {
    726       static const uint32_t vals[] = {
    727         0, 1, 2, 0x7F, 0x80, 0xFF, 0x100, 0x7FFF, 0x8000, 0xFFFF,
    728         0x10000, 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF
    729       };
    730       size_t p = fuzz_below (rng, (uint32_t) len);
    731       unsigned int n = (0 == fuzz_below (rng, 2)) ? 2 : 4;
    732       uint32_t v = vals[fuzz_below (rng,
    733                                     (uint32_t) (sizeof (vals)
    734                                                 / sizeof (vals[0])))];
    735       unsigned int k;
    736 
    737       if (p + n > len)
    738         break;
    739       /* Keep both loops braced.  uncrustify 0.78 spins forever on an
    740          unbraced if/else whose body is an unbraced for whose statement
    741          carries a trailing comment, which hangs the pre-commit hook. */
    742       if (0 == fuzz_below (rng, 2))
    743       {
    744         /* little endian */
    745         for (k = 0; k < n; k++)
    746           buf[p + k] = (uint8_t) (v >> (8 * k));
    747       }
    748       else
    749       {
    750         /* big endian */
    751         for (k = 0; k < n; k++)
    752           buf[p + k] = (uint8_t) (v >> (8 * (n - 1 - k)));
    753       }
    754       break;
    755     }
    756   default:                     /* truncate */
    757     len = 1 + fuzz_below (rng, (uint32_t) len);
    758     break;
    759   }
    760   return len;
    761 }
    762 
    763 
    764 /* ------------------------------------------------------------------ */
    765 /* Standalone driver                                                   */
    766 /* ------------------------------------------------------------------ */
    767 
    768 static int
    769 fuzz_run_file (const char *path)
    770 {
    771   FILE *f;
    772   uint8_t *buf;
    773   size_t n;
    774 
    775   f = fopen (path, "rb");
    776   if (NULL == f)
    777   {
    778     fprintf (stderr,
    779              "%s: cannot open '%s': %s\n",
    780              FUZZ_HARNESS_NAME,
    781              path,
    782              strerror (errno));
    783     return 1;
    784   }
    785   buf = (uint8_t *) malloc (FUZZ_MAX_INPUT);
    786   if (NULL == buf)
    787   {
    788     (void) fclose (f);
    789     return 1;
    790   }
    791   n = fread (buf, 1, FUZZ_MAX_INPUT, f);
    792   (void) fclose (f);
    793   fuzz_pristine = 1;
    794   fuzz_set_current (buf, n, path);
    795   alarm (FUZZ_DEFAULT_TIMEOUT);
    796   (void) LLVMFuzzerTestOneInput (buf, n);
    797   alarm (0);
    798   fuzz_cur_input = NULL; /* nothing to dump for an at-exit report */
    799   free (buf);
    800   return 0;
    801 }
    802 
    803 
    804 static int
    805 fuzz_run_corpus_dir (const char *dir)
    806 {
    807   DIR *d;
    808   struct dirent *de;
    809   char path[1024];
    810   int ret = 0;
    811   unsigned int cnt = 0;
    812 
    813   d = opendir (dir);
    814   if (NULL == d)
    815   {
    816     fprintf (stderr,
    817              "%s: cannot open corpus dir '%s': %s\n",
    818              FUZZ_HARNESS_NAME,
    819              dir,
    820              strerror (errno));
    821     return 1;
    822   }
    823   while (NULL != (de = readdir (d)))
    824   {
    825     struct stat sb;
    826 
    827     if ('.' == de->d_name[0])
    828       continue;
    829     (void) snprintf (path, sizeof (path), "%s/%s", dir, de->d_name);
    830     if ( (0 != stat (path, &sb)) ||
    831          (! S_ISREG (sb.st_mode)) )
    832       continue;
    833     fuzz_cur_iter = cnt++;
    834     ret |= fuzz_run_file (path);
    835   }
    836   (void) closedir (d);
    837   printf ("%s: replayed %u corpus file(s) from %s\n",
    838           FUZZ_HARNESS_NAME, cnt, dir);
    839   return ret;
    840 }
    841 
    842 
    843 static void
    844 fuzz_usage (const char *argv0)
    845 {
    846   printf (
    847     "Usage: %s [OPTIONS] [FILE...]\n"
    848     "\n"
    849     "In-process fuzzing harness '%s' for GNU libextractor.\n"
    850     "\n"
    851     "  --iterations=N    number of generate/mutate iterations (default %d)\n"
    852     "  --seed=N          PRNG seed; runs are fully reproducible (default 1)\n"
    853     "  --corpus-dir=DIR  replay every regular file in DIR and exit\n"
    854     "  --file=PATH       replay a single input and exit (crash reproduction)\n"
    855     "  --crash-dir=DIR   where to write reproducers (default 'crashes')\n"
    856     "  --timeout=SEC     per-iteration watchdog (default %d, 0 disables)\n"
    857     "  --write-corpus=DIR  write the built-in seed corpus to DIR and exit\n"
    858     "  --skip-seeds      do not replay the built-in seed corpus first\n"
    859     "  --verbose         be chatty about what the harness does\n"
    860     "  --help            this text\n"
    861     "\n"
    862     "Environment: LE_FUZZ_ITERATIONS, LE_FUZZ_SEED, LE_FUZZ_TIMEOUT,\n"
    863     "             LE_FUZZ_CRASH_DIR, LE_FUZZ_VERBOSE, LE_FUZZ_SKIP_SEEDS\n"
    864     "\n"
    865     "Bare FILE arguments are equivalent to --file=FILE (libFuzzer-style).\n",
    866     argv0, FUZZ_HARNESS_NAME,
    867     (int) FUZZ_DEFAULT_ITERATIONS, (int) FUZZ_DEFAULT_TIMEOUT);
    868 }
    869 
    870 
    871 static int
    872 fuzz_write_corpus (const char *dir)
    873 {
    874   size_t i;
    875   size_t n = fuzz_seed_count ();
    876 
    877   if ( (0 != mkdir (dir, 0755)) &&
    878        (EEXIST != errno) )
    879   {
    880     fprintf (stderr, "%s: mkdir '%s': %s\n",
    881              FUZZ_HARNESS_NAME, dir, strerror (errno));
    882     return 1;
    883   }
    884   for (i = 0; i < n; i++)
    885   {
    886     char path[1024];
    887     size_t len;
    888     const uint8_t *s = fuzz_seed_get (i, &len);
    889     FILE *f;
    890 
    891     (void) snprintf (path, sizeof (path), "%s/%s-%03u.bin",
    892                      dir, FUZZ_HARNESS_NAME, (unsigned int) i);
    893     f = fopen (path, "wb");
    894     if (NULL == f)
    895     {
    896       fprintf (stderr, "%s: fopen '%s': %s\n",
    897                FUZZ_HARNESS_NAME, path, strerror (errno));
    898       return 1;
    899     }
    900     if ( (0 != len) &&
    901          (len != fwrite (s, 1, len, f)) )
    902     {
    903       (void) fclose (f);
    904       return 1;
    905     }
    906     (void) fclose (f);
    907   }
    908   printf ("%s: wrote %u seed(s) to %s\n",
    909           FUZZ_HARNESS_NAME, (unsigned int) n, dir);
    910   return 0;
    911 }
    912 
    913 
    914 int
    915 main (int argc, char *const *argv)
    916 {
    917   uint64_t iterations = FUZZ_DEFAULT_ITERATIONS;
    918   uint64_t seed = 1;
    919   unsigned int timeout = FUZZ_DEFAULT_TIMEOUT;
    920   const char *corpus_dir = NULL;
    921   const char *single_file = NULL;
    922   const char *write_corpus = NULL;
    923   struct fuzz_rng rng;
    924   uint8_t *buf;
    925   uint64_t i;
    926   int j;
    927   const char *e;
    928   int ret = 0;
    929 
    930   iterations = fuzz_env_ulong ("LE_FUZZ_ITERATIONS", iterations);
    931   seed = fuzz_env_ulong ("LE_FUZZ_SEED", seed);
    932   timeout = (unsigned int) fuzz_env_ulong ("LE_FUZZ_TIMEOUT", timeout);
    933   e = getenv ("LE_FUZZ_CRASH_DIR");
    934   if (NULL != e)
    935     fuzz_crash_dir = e;
    936   fuzz_verbose = (0 != fuzz_env_ulong ("LE_FUZZ_VERBOSE", 0));
    937   fuzz_skip_seeds = (0 != fuzz_env_ulong ("LE_FUZZ_SKIP_SEEDS", 0));
    938 
    939   for (j = 1; j < argc; j++)
    940   {
    941     const char *a = argv[j];
    942 
    943     if (0 == strncmp (a, "--iterations=", 13))
    944       iterations = strtoull (a + 13, NULL, 10);
    945     else if (0 == strncmp (a, "--seed=", 7))
    946       seed = strtoull (a + 7, NULL, 10);
    947     else if (0 == strncmp (a, "--corpus-dir=", 13))
    948       corpus_dir = a + 13;
    949     else if (0 == strncmp (a, "--file=", 7))
    950       single_file = a + 7;
    951     else if (0 == strncmp (a, "--crash-dir=", 12))
    952       fuzz_crash_dir = a + 12;
    953     else if (0 == strncmp (a, "--timeout=", 10))
    954       timeout = (unsigned int) strtoul (a + 10, NULL, 10);
    955     else if (0 == strncmp (a, "--write-corpus=", 15))
    956       write_corpus = a + 15;
    957     else if (0 == strcmp (a, "--skip-seeds"))
    958       fuzz_skip_seeds = 1;
    959     else if (0 == strcmp (a, "--verbose"))
    960       fuzz_verbose = 1;
    961     else if ( (0 == strcmp (a, "--help")) ||
    962               (0 == strcmp (a, "-h")) )
    963     {
    964       fuzz_usage (argv[0]);
    965       return 0;
    966     }
    967     else if ('-' == a[0])
    968     {
    969       fprintf (stderr, "%s: unknown option '%s'\n", FUZZ_HARNESS_NAME, a);
    970       fuzz_usage (argv[0]);
    971       return 2;
    972     }
    973     else
    974       single_file = a;
    975   }
    976 
    977   fuzz_cur_seed = seed;
    978   fuzz_install_handlers ();
    979 
    980   if (NULL != write_corpus)
    981     return fuzz_write_corpus (write_corpus);
    982 
    983   if (NULL != single_file)
    984   {
    985     printf ("%s: replaying %s\n", FUZZ_HARNESS_NAME, single_file);
    986     ret = fuzz_run_file (single_file);
    987     printf ("%s: replay finished without a finding\n", FUZZ_HARNESS_NAME);
    988     return ret;
    989   }
    990   if (NULL != corpus_dir)
    991     return fuzz_run_corpus_dir (corpus_dir);
    992 
    993   buf = (uint8_t *) malloc (FUZZ_MAX_INPUT);
    994   if (NULL == buf)
    995     return 1;
    996   fuzz_rng_seed (&rng, seed);
    997   printf ("%s: seed=%llu iterations=%llu\n",
    998           FUZZ_HARNESS_NAME,
    999           (unsigned long long) seed,
   1000           (unsigned long long) iterations);
   1001   fflush (stdout);
   1002 
   1003   for (i = 0; i < iterations; i++)
   1004   {
   1005     size_t len;
   1006     const char *tag;
   1007     uint32_t mode;
   1008 
   1009     fuzz_cur_iter = i;
   1010     if ( (! fuzz_skip_seeds) &&
   1011          (i < fuzz_seed_count ()) )
   1012     {
   1013       size_t sl;
   1014       const uint8_t *s = fuzz_seed_get ((size_t) i, &sl);
   1015 
   1016       if (sl > FUZZ_MAX_INPUT)
   1017         sl = FUZZ_MAX_INPUT;
   1018       memcpy (buf, s, sl);
   1019       len = sl;
   1020       fuzz_pristine = 1;
   1021       tag = "builtin-seed";
   1022     }
   1023     else
   1024     {
   1025       mode = fuzz_below (&rng, 100);
   1026       if (mode < 45)
   1027       {
   1028         fuzz_pristine = 1;
   1029         len = fuzz_generate (&rng, buf, FUZZ_MAX_INPUT);
   1030         tag = "generated";
   1031       }
   1032       else
   1033       {
   1034         unsigned int k;
   1035         unsigned int nmut;
   1036 
   1037         if (mode < 80)
   1038         {
   1039           len = fuzz_generate (&rng, buf, FUZZ_MAX_INPUT);
   1040           tag = "generated+mutated";
   1041         }
   1042         else
   1043         {
   1044           size_t sl;
   1045           const uint8_t *s;
   1046 
   1047           if (0 == fuzz_seed_count ())
   1048           {
   1049             len = fuzz_generate (&rng, buf, FUZZ_MAX_INPUT);
   1050           }
   1051           else
   1052           {
   1053             s = fuzz_seed_get (fuzz_below (&rng,
   1054                                            (uint32_t) fuzz_seed_count ()),
   1055                                &sl);
   1056             if (sl > FUZZ_MAX_INPUT)
   1057               sl = FUZZ_MAX_INPUT;
   1058             memcpy (buf, s, sl);
   1059             len = sl;
   1060           }
   1061           tag = "seed+mutated";
   1062         }
   1063         fuzz_pristine = 0;
   1064         nmut = 1 + fuzz_below (&rng, 8);
   1065         for (k = 0; k < nmut; k++)
   1066           len = fuzz_mutate_once (&rng, buf, len, FUZZ_MAX_INPUT);
   1067       }
   1068     }
   1069     fuzz_set_current (buf, len, tag);
   1070     if (0 != timeout)
   1071       alarm (timeout);
   1072     (void) LLVMFuzzerTestOneInput (buf, len);
   1073     if (0 != timeout)
   1074       alarm (0);
   1075   }
   1076   fuzz_cur_input = NULL; /* nothing to dump for an at-exit report */
   1077   free (buf);
   1078   printf ("%s: %llu iterations completed, no findings\n",
   1079           FUZZ_HARNESS_NAME,
   1080           (unsigned long long) iterations);
   1081   return ret;
   1082 }
   1083 
   1084 
   1085 #endif /* ! FUZZ_NO_MAIN */
   1086 
   1087 #endif /* LE_FUZZ_COMMON_H */