libextractor

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

fuzz_common.h (29558B)


      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   free (buf);
    799   return 0;
    800 }
    801 
    802 
    803 static int
    804 fuzz_run_corpus_dir (const char *dir)
    805 {
    806   DIR *d;
    807   struct dirent *de;
    808   char path[1024];
    809   int ret = 0;
    810   unsigned int cnt = 0;
    811 
    812   d = opendir (dir);
    813   if (NULL == d)
    814   {
    815     fprintf (stderr,
    816              "%s: cannot open corpus dir '%s': %s\n",
    817              FUZZ_HARNESS_NAME,
    818              dir,
    819              strerror (errno));
    820     return 1;
    821   }
    822   while (NULL != (de = readdir (d)))
    823   {
    824     struct stat sb;
    825 
    826     if ('.' == de->d_name[0])
    827       continue;
    828     (void) snprintf (path, sizeof (path), "%s/%s", dir, de->d_name);
    829     if ( (0 != stat (path, &sb)) ||
    830          (! S_ISREG (sb.st_mode)) )
    831       continue;
    832     fuzz_cur_iter = cnt++;
    833     ret |= fuzz_run_file (path);
    834   }
    835   (void) closedir (d);
    836   printf ("%s: replayed %u corpus file(s) from %s\n",
    837           FUZZ_HARNESS_NAME, cnt, dir);
    838   return ret;
    839 }
    840 
    841 
    842 static void
    843 fuzz_usage (const char *argv0)
    844 {
    845   printf (
    846     "Usage: %s [OPTIONS] [FILE...]\n"
    847     "\n"
    848     "In-process fuzzing harness '%s' for GNU libextractor.\n"
    849     "\n"
    850     "  --iterations=N    number of generate/mutate iterations (default %d)\n"
    851     "  --seed=N          PRNG seed; runs are fully reproducible (default 1)\n"
    852     "  --corpus-dir=DIR  replay every regular file in DIR and exit\n"
    853     "  --file=PATH       replay a single input and exit (crash reproduction)\n"
    854     "  --crash-dir=DIR   where to write reproducers (default 'crashes')\n"
    855     "  --timeout=SEC     per-iteration watchdog (default %d, 0 disables)\n"
    856     "  --write-corpus=DIR  write the built-in seed corpus to DIR and exit\n"
    857     "  --skip-seeds      do not replay the built-in seed corpus first\n"
    858     "  --verbose         be chatty about what the harness does\n"
    859     "  --help            this text\n"
    860     "\n"
    861     "Environment: LE_FUZZ_ITERATIONS, LE_FUZZ_SEED, LE_FUZZ_TIMEOUT,\n"
    862     "             LE_FUZZ_CRASH_DIR, LE_FUZZ_VERBOSE, LE_FUZZ_SKIP_SEEDS\n"
    863     "\n"
    864     "Bare FILE arguments are equivalent to --file=FILE (libFuzzer-style).\n",
    865     argv0, FUZZ_HARNESS_NAME,
    866     (int) FUZZ_DEFAULT_ITERATIONS, (int) FUZZ_DEFAULT_TIMEOUT);
    867 }
    868 
    869 
    870 static int
    871 fuzz_write_corpus (const char *dir)
    872 {
    873   size_t i;
    874   size_t n = fuzz_seed_count ();
    875 
    876   if ( (0 != mkdir (dir, 0755)) &&
    877        (EEXIST != errno) )
    878   {
    879     fprintf (stderr, "%s: mkdir '%s': %s\n",
    880              FUZZ_HARNESS_NAME, dir, strerror (errno));
    881     return 1;
    882   }
    883   for (i = 0; i < n; i++)
    884   {
    885     char path[1024];
    886     size_t len;
    887     const uint8_t *s = fuzz_seed_get (i, &len);
    888     FILE *f;
    889 
    890     (void) snprintf (path, sizeof (path), "%s/%s-%03u.bin",
    891                      dir, FUZZ_HARNESS_NAME, (unsigned int) i);
    892     f = fopen (path, "wb");
    893     if (NULL == f)
    894     {
    895       fprintf (stderr, "%s: fopen '%s': %s\n",
    896                FUZZ_HARNESS_NAME, path, strerror (errno));
    897       return 1;
    898     }
    899     if ( (0 != len) &&
    900          (len != fwrite (s, 1, len, f)) )
    901     {
    902       (void) fclose (f);
    903       return 1;
    904     }
    905     (void) fclose (f);
    906   }
    907   printf ("%s: wrote %u seed(s) to %s\n",
    908           FUZZ_HARNESS_NAME, (unsigned int) n, dir);
    909   return 0;
    910 }
    911 
    912 
    913 int
    914 main (int argc, char *const *argv)
    915 {
    916   uint64_t iterations = FUZZ_DEFAULT_ITERATIONS;
    917   uint64_t seed = 1;
    918   unsigned int timeout = FUZZ_DEFAULT_TIMEOUT;
    919   const char *corpus_dir = NULL;
    920   const char *single_file = NULL;
    921   const char *write_corpus = NULL;
    922   struct fuzz_rng rng;
    923   uint8_t *buf;
    924   uint64_t i;
    925   int j;
    926   const char *e;
    927   int ret = 0;
    928 
    929   iterations = fuzz_env_ulong ("LE_FUZZ_ITERATIONS", iterations);
    930   seed = fuzz_env_ulong ("LE_FUZZ_SEED", seed);
    931   timeout = (unsigned int) fuzz_env_ulong ("LE_FUZZ_TIMEOUT", timeout);
    932   e = getenv ("LE_FUZZ_CRASH_DIR");
    933   if (NULL != e)
    934     fuzz_crash_dir = e;
    935   fuzz_verbose = (0 != fuzz_env_ulong ("LE_FUZZ_VERBOSE", 0));
    936   fuzz_skip_seeds = (0 != fuzz_env_ulong ("LE_FUZZ_SKIP_SEEDS", 0));
    937 
    938   for (j = 1; j < argc; j++)
    939   {
    940     const char *a = argv[j];
    941 
    942     if (0 == strncmp (a, "--iterations=", 13))
    943       iterations = strtoull (a + 13, NULL, 10);
    944     else if (0 == strncmp (a, "--seed=", 7))
    945       seed = strtoull (a + 7, NULL, 10);
    946     else if (0 == strncmp (a, "--corpus-dir=", 13))
    947       corpus_dir = a + 13;
    948     else if (0 == strncmp (a, "--file=", 7))
    949       single_file = a + 7;
    950     else if (0 == strncmp (a, "--crash-dir=", 12))
    951       fuzz_crash_dir = a + 12;
    952     else if (0 == strncmp (a, "--timeout=", 10))
    953       timeout = (unsigned int) strtoul (a + 10, NULL, 10);
    954     else if (0 == strncmp (a, "--write-corpus=", 15))
    955       write_corpus = a + 15;
    956     else if (0 == strcmp (a, "--skip-seeds"))
    957       fuzz_skip_seeds = 1;
    958     else if (0 == strcmp (a, "--verbose"))
    959       fuzz_verbose = 1;
    960     else if ( (0 == strcmp (a, "--help")) ||
    961               (0 == strcmp (a, "-h")) )
    962     {
    963       fuzz_usage (argv[0]);
    964       return 0;
    965     }
    966     else if ('-' == a[0])
    967     {
    968       fprintf (stderr, "%s: unknown option '%s'\n", FUZZ_HARNESS_NAME, a);
    969       fuzz_usage (argv[0]);
    970       return 2;
    971     }
    972     else
    973       single_file = a;
    974   }
    975 
    976   fuzz_cur_seed = seed;
    977   fuzz_install_handlers ();
    978 
    979   if (NULL != write_corpus)
    980     return fuzz_write_corpus (write_corpus);
    981 
    982   if (NULL != single_file)
    983   {
    984     printf ("%s: replaying %s\n", FUZZ_HARNESS_NAME, single_file);
    985     ret = fuzz_run_file (single_file);
    986     printf ("%s: replay finished without a finding\n", FUZZ_HARNESS_NAME);
    987     return ret;
    988   }
    989   if (NULL != corpus_dir)
    990     return fuzz_run_corpus_dir (corpus_dir);
    991 
    992   buf = (uint8_t *) malloc (FUZZ_MAX_INPUT);
    993   if (NULL == buf)
    994     return 1;
    995   fuzz_rng_seed (&rng, seed);
    996   printf ("%s: seed=%llu iterations=%llu\n",
    997           FUZZ_HARNESS_NAME,
    998           (unsigned long long) seed,
    999           (unsigned long long) iterations);
   1000   fflush (stdout);
   1001 
   1002   for (i = 0; i < iterations; i++)
   1003   {
   1004     size_t len;
   1005     const char *tag;
   1006     uint32_t mode;
   1007 
   1008     fuzz_cur_iter = i;
   1009     if ( (! fuzz_skip_seeds) &&
   1010          (i < fuzz_seed_count ()) )
   1011     {
   1012       size_t sl;
   1013       const uint8_t *s = fuzz_seed_get ((size_t) i, &sl);
   1014 
   1015       if (sl > FUZZ_MAX_INPUT)
   1016         sl = FUZZ_MAX_INPUT;
   1017       memcpy (buf, s, sl);
   1018       len = sl;
   1019       fuzz_pristine = 1;
   1020       tag = "builtin-seed";
   1021     }
   1022     else
   1023     {
   1024       mode = fuzz_below (&rng, 100);
   1025       if (mode < 45)
   1026       {
   1027         fuzz_pristine = 1;
   1028         len = fuzz_generate (&rng, buf, FUZZ_MAX_INPUT);
   1029         tag = "generated";
   1030       }
   1031       else
   1032       {
   1033         unsigned int k;
   1034         unsigned int nmut;
   1035 
   1036         if (mode < 80)
   1037         {
   1038           len = fuzz_generate (&rng, buf, FUZZ_MAX_INPUT);
   1039           tag = "generated+mutated";
   1040         }
   1041         else
   1042         {
   1043           size_t sl;
   1044           const uint8_t *s;
   1045 
   1046           if (0 == fuzz_seed_count ())
   1047           {
   1048             len = fuzz_generate (&rng, buf, FUZZ_MAX_INPUT);
   1049           }
   1050           else
   1051           {
   1052             s = fuzz_seed_get (fuzz_below (&rng,
   1053                                            (uint32_t) fuzz_seed_count ()),
   1054                                &sl);
   1055             if (sl > FUZZ_MAX_INPUT)
   1056               sl = FUZZ_MAX_INPUT;
   1057             memcpy (buf, s, sl);
   1058             len = sl;
   1059           }
   1060           tag = "seed+mutated";
   1061         }
   1062         fuzz_pristine = 0;
   1063         nmut = 1 + fuzz_below (&rng, 8);
   1064         for (k = 0; k < nmut; k++)
   1065           len = fuzz_mutate_once (&rng, buf, len, FUZZ_MAX_INPUT);
   1066       }
   1067     }
   1068     fuzz_set_current (buf, len, tag);
   1069     if (0 != timeout)
   1070       alarm (timeout);
   1071     (void) LLVMFuzzerTestOneInput (buf, len);
   1072     if (0 != timeout)
   1073       alarm (0);
   1074   }
   1075   free (buf);
   1076   printf ("%s: %llu iterations completed, no findings\n",
   1077           FUZZ_HARNESS_NAME,
   1078           (unsigned long long) iterations);
   1079   return ret;
   1080 }
   1081 
   1082 
   1083 #endif /* ! FUZZ_NO_MAIN */
   1084 
   1085 #endif /* LE_FUZZ_COMMON_H */