libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

fuzz_memorypool.c (48519B)


      1 /*
      2   This file is part of libmicrohttpd
      3   Copyright (C) 2026 Christian Grothoff
      4 
      5   This library is free software; you can redistribute it and/or
      6   modify it under the terms of the GNU Lesser General Public
      7   License as published by the Free Software Foundation; either
      8   version 2.1 of the License, or (at your option) any later version.
      9 
     10   This library is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13   Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General Public
     16   License along with this library.
     17   If not, see <http://www.gnu.org/licenses/>.
     18 */
     19 
     20 /**
     21  * @file fuzz/fuzz_memorypool.c
     22  * @brief Direct in-process fuzzer for src/microhttpd/memorypool.c
     23  * @author Christian Grothoff
     24  *
     25  * memorypool.c is the per-connection allocator: a bump allocator that
     26  * hands out "normal" blocks from the start of the pool and small,
     27  * never-reallocated blocks from its end, plus an in-place resize and a
     28  * reset that moves one surviving block back to the beginning.  Every
     29  * request buffer, every header name and value of every connection lives
     30  * in it, so a single mis-computed offset here is a cross-request
     31  * information leak or a heap overflow -- and one that ASAN alone cannot
     32  * see, because the whole pool is one malloc()ed object.  (It does see it
     33  * in a build where MHD_ASAN_POISON_ACTIVE is defined, i.e. where
     34  * `sanitizer/asan_interface.h` was found and memorypool.c poisons the
     35  * unallocated parts of the pool itself.  The harness works either way
     36  * and knows the red zone size that mode adds between two blocks.)
     37  *
     38  * The harness therefore keeps its own model of the pool and checks it
     39  * against the allocator after every single operation:
     40  *
     41  *  - every returned pointer lies inside the pool, is aligned, and does
     42  *    not overlap any other live allocation;
     43  *  - every live allocation carries a position-dependent byte pattern
     44  *    that is re-verified later; the allocator moves data around in
     45  *    MHD_pool_reallocate() and MHD_pool_reset(), and the pattern is what
     46  *    proves the move was correct;
     47  *  - the sum of the live allocations plus MHD_pool_get_free() never
     48  *    exceeds the size of the pool, MHD_pool_get_free() never grows
     49  *    across an allocation and never shrinks across a deallocation;
     50  *  - the implications the rest of MHD relies on hold:
     51  *      * MHD_pool_allocate (pool, MHD_pool_get_free (pool), false) must
     52  *        succeed (response.c:2203 does exactly this), and more generally
     53  *        an allocation must not fail while get_free() reports room for
     54  *        its rounded-up size;
     55  *      * if MHD_pool_is_resizable_inplace() says yes, a reallocation
     56  *        that fits must succeed *and must not move the block*
     57  *        (connection.c:729/750/2082/2121 assert precisely that);
     58  *      * after freeing the number of bytes MHD_pool_try_alloc() asked
     59  *        for in @a required_bytes, the same call must succeed -- this is
     60  *        the whole point of that out parameter and the logic of
     61  *        MHD_connection_alloc_memory_().
     62  *
     63  * Documented preconditions are respected, since violating them would
     64  * only produce findings about the harness: blocks allocated "from the
     65  * end" are never passed to MHD_pool_reallocate(), MHD_pool_reset() is
     66  * never asked for more than the pool size nor for more copy_bytes than
     67  * the kept block holds, and a block is only ever deallocated with the
     68  * size it was allocated with.
     69  *
     70  * Two *open* defects of memorypool.c are reachable and would otherwise
     71  * make every run abort; each is gated behind an environment variable,
     72  * documented in full at full_dealloc_enabled and wrap_realloc_enabled
     73  * below and in README section 6.1, with a byte-exact reproducer in the
     74  * built-in seed corpus.  Nothing else is gated.
     75  *
     76  * Input format:
     77  *   byte 0    pool size selector (index into fz_pool_sizes[])
     78  *   byte 1    flags
     79  *               0x01  verify every live block after every operation
     80  *               0x02  prefer allocating "from the end"
     81  *               rest  unused
     82  *   byte 2..  a stream of 3-byte operation records
     83  *               [0] opcode          (see enum fz_op)
     84  *               [1] block selector / auxiliary nibbles
     85  *               [2] size selector   (see fz_size())
     86  */
     87 
     88 #define FUZZ_HARNESS_NAME "fuzz_memorypool"
     89 #include "fuzz_common.h"
     90 
     91 /* internal.h pulls in MHD_config.h and <microhttpd.h> in the right
     92    order; including <microhttpd.h> first would redefine _MHD_EXTERN. */
     93 #include "internal.h"
     94 #include "memorypool.h"
     95 
     96 
     97 /**
     98  * Alignment of every block the pool hands out; memorypool.c aligns to
     99  * two words "as GNU libc does".
    100  */
    101 #define FZ_ALIGN_SIZE (2 * sizeof (void *))
    102 
    103 /**
    104  * Size of the red zone memorypool.c keeps between two blocks.  It only
    105  * exists in a build with user memory poisoning, i.e. when the pool
    106  * itself is instrumented; without it the pool is packed tight.
    107  */
    108 #ifdef MHD_ASAN_POISON_ACTIVE
    109 #define FZ_RED_ZONE_SIZE FZ_ALIGN_SIZE
    110 #else  /* ! MHD_ASAN_POISON_ACTIVE */
    111 #define FZ_RED_ZONE_SIZE ((size_t) 0)
    112 #endif /* ! MHD_ASAN_POISON_ACTIVE */
    113 
    114 /**
    115  * Maximum number of live allocations the model tracks.  An operation
    116  * that would exceed this is skipped, so the model never loses a block.
    117  */
    118 #define FZ_MAX_BLOCKS 24
    119 
    120 /**
    121  * Maximum number of operations executed for one input.
    122  */
    123 #define FZ_MAX_OPS 64
    124 
    125 /**
    126  * Number of bytes of each allocation that carry the check pattern.
    127  * Bounding this keeps the harness fast; the interesting bugs of a bump
    128  * allocator are all at the start of a block or at its (ASAN-guarded)
    129  * end.
    130  */
    131 #define FZ_PAT_MAX 96
    132 
    133 /**
    134  * Pool sizes to choose from.  MHD uses 128..32768 in practice (the
    135  * default is 32768 and MHD_OPTION_CONNECTION_MEMORY_LIMIT can set
    136  * anything); everything at or below 32k is malloc()ed by
    137  * MHD_pool_create(), so the harness knows the exact usable size and
    138  * ASAN's redzone sits right behind the pool.  The last two entries are
    139  * larger than that on purpose: they take the mmap() path of
    140  * MHD_pool_create() and the munmap() path of MHD_pool_destroy().  Both
    141  * are powers of two and therefore a multiple of any page size, so the
    142  * resulting pool is exactly that large either way and the check below
    143  * stays exact.
    144  */
    145 static const size_t fz_pool_sizes[] = {
    146   1, 15, 16, 17, 32, 48, 64, 96, 128, 129, 192, 256, 320, 384, 512,
    147   768, 1024, 1400, 1500, 2048, 4096, 8192, 16384, 32768, 65536, 131072
    148 };
    149 
    150 #define FZ_NUM_POOL_SIZES \
    151   (sizeof (fz_pool_sizes) / sizeof (fz_pool_sizes[0]))
    152 
    153 
    154 enum fz_op
    155 {
    156   FZ_OP_ALLOC = 0,       /**< MHD_pool_allocate() */
    157   FZ_OP_ALLOC_ALL,       /**< allocate exactly MHD_pool_get_free() bytes */
    158   FZ_OP_TRY_ALLOC,       /**< MHD_pool_try_alloc() */
    159   FZ_OP_SQUEEZE,         /**< try_alloc + shrink + retry */
    160   FZ_OP_REALLOC,         /**< MHD_pool_reallocate() of a live block */
    161   FZ_OP_REALLOC_NEW,     /**< MHD_pool_reallocate() with old == NULL */
    162   FZ_OP_DEALLOC,         /**< MHD_pool_deallocate() */
    163   FZ_OP_RESET,           /**< MHD_pool_reset() */
    164   FZ_OP_GET_FREE,        /**< MHD_pool_get_free() */
    165   FZ_OP_RESIZABLE,       /**< MHD_pool_is_resizable_inplace() */
    166   FZ_OP_VERIFY,          /**< re-check every live block */
    167   FZ_OP_RECREATE,        /**< MHD_pool_destroy() + MHD_pool_create() */
    168   FZ_OP_COUNT
    169 };
    170 
    171 
    172 /**
    173  * One live allocation.
    174  */
    175 struct fz_block
    176 {
    177   /**
    178    * Address returned by the pool.
    179    */
    180   uint8_t *ptr;
    181 
    182   /**
    183    * Current size of the block, i.e. the number of bytes the harness is
    184    * allowed to touch and the size it will pass to the pool again.
    185    */
    186   size_t size;
    187 
    188   /**
    189    * Seed of the check pattern of this block.
    190    */
    191   uint8_t tag;
    192 
    193   /**
    194    * True if the block was allocated "from the end" (MHD_pool_allocate()
    195    * with @a from_end, or MHD_pool_try_alloc()).  Such blocks must never
    196    * be passed to MHD_pool_reallocate().
    197    */
    198   bool from_end;
    199 };
    200 
    201 
    202 /**
    203  * The model of one pool.
    204  */
    205 struct fz_pool
    206 {
    207   struct MemoryPool *pool;
    208 
    209   /**
    210    * Address of the first byte of the pool, as returned by
    211    * MHD_pool_reset() for an empty pool -- that is a real MHD call site
    212    * (connection.c:3021 uses the result as the new read buffer).
    213    */
    214   uint8_t *base;
    215 
    216   /**
    217    * Total size of the pool in bytes.
    218    */
    219   size_t cap;
    220 
    221   struct fz_block blk[FZ_MAX_BLOCKS];
    222 
    223   unsigned int nblk;
    224 
    225   uint8_t next_tag;
    226 
    227   /**
    228    * Verify every live block after every operation.
    229    */
    230   bool paranoid;
    231 };
    232 
    233 
    234 /**
    235  * F1 -- MHD_pool_deallocate() of a "from the end" block of a pool that
    236  * is *exactly* full.  This is a live defect in memorypool.c and is
    237  * therefore off by default; set MHD_FUZZ_POOL_FULL_DEALLOC=1 to reach
    238  * it (seed fuzz_memorypool-15.bin is the byte-exact reproducer).
    239  *
    240  * MHD_pool_deallocate() decides whether a block came from the front or
    241  * from the end with
    242  *
    243  *     if (block_offset <= pool->pos)     memorypool.c:666
    244  *
    245  * which is ambiguous when pool->pos == pool->end, i.e. when the pool has
    246  * no free space left: a "from the end" block then starts exactly at
    247  * pool->pos and is treated as a front block.  With --enable-asserts
    248  *
    249  *     mhd_assert ((block_offset != pool->pos) || (block_size == 0));   :655
    250  *     mhd_assert (alg_end <= pool->pos);                               :671
    251  *
    252  * both fail, i.e. the process aborts; without them the block is simply
    253  * not returned to the pool (pool->end is left alone), so the memory is
    254  * lost until the pool is reset or destroyed.  Reproducer:
    255  *
    256  *     p = MHD_pool_create (128);
    257  *     e = MHD_pool_allocate (p, 16, true);
    258  *     (void) MHD_pool_allocate (p, MHD_pool_get_free (p), false);
    259  *     MHD_pool_deallocate (p, e, 16);      <- abort / 16 bytes lost
    260  *
    261  * Nothing in memorypool.h forbids this; MHD_pool_deallocate() documents
    262  * only that "the NULL is tolerated" and has an explicit branch for
    263  * blocks allocated from the end.  MHD's own call sites never hit it,
    264  * because the three MHD_pool_deallocate() calls in connection.c and
    265  * response.c all pass the read or the write buffer, which are front
    266  * allocations -- so this is a latent defect of a supported branch of the
    267  * API rather than something reachable from the network today.  A
    268  * dispatch on `block_offset < pool->end` would resolve the ambiguity.
    269  */
    270 static int full_dealloc_enabled;
    271 
    272 /**
    273  * F2 -- MHD_pool_reallocate() reports success for a @a new_size that
    274  * wrapped.  Also a live defect, off by default; set
    275  * MHD_FUZZ_POOL_WRAP_REALLOC=1 to reach it (seed
    276  * fuzz_memorypool-16.bin is the byte-exact reproducer).
    277  *
    278  * Every other entry point of memorypool.c detects a size that is too
    279  * close to SIZE_MAX explicitly:
    280  *
    281  *     asize = ROUND_TO_ALIGN_PLUS_RED_ZONE (size);
    282  *     if ( (0 == asize) && (0 != size) )
    283  *       return NULL;                 // "size too close to SIZE_MAX"
    284  *
    285  * -- MHD_pool_allocate(), MHD_pool_try_alloc() and the "need to
    286  * allocate a new block" tail of MHD_pool_reallocate() all do it.  The
    287  * in-place branch of MHD_pool_reallocate() instead relies on
    288  *
    289  *     const size_t new_apos =
    290  *       ROUND_TO_ALIGN_PLUS_RED_ZONE (old_offset + new_size);
    291  *     if ( (new_apos > pool->end) ||
    292  *          (new_apos < pool->pos) )  // "Value wrap"
    293  *       return NULL;
    294  *
    295  * which does not catch the wrap when the wrapped value happens to land
    296  * on pool->pos.  For a zero-length block sitting at the front boundary
    297  * (old_size == 0, old_offset == pool->pos, which is exactly what
    298  * MHD_pool_reset (pool, NULL, 0, 0) returns -- see connection.c:3021 --
    299  * or MHD_pool_allocate (pool, 0, false)) and any new_size in
    300  * [SIZE_MAX - 14, SIZE_MAX], old_offset + new_size wraps to
    301  * old_offset - 1 - k, which rounds back up to exactly old_offset, i.e.
    302  * to pool->pos: neither test fires, pool->pos is left alone and the
    303  * function returns @a old, i.e. it reports success.
    304  *
    305  *     p = MHD_pool_create (1024);
    306  *     b = MHD_pool_reset (p, NULL, 0, 0);
    307  *     r = MHD_pool_reallocate (p, b, 0, SIZE_MAX - 4);
    308  *     // r == b, not NULL: the caller now believes it owns
    309  *     // SIZE_MAX - 4 bytes at the start of a 1024 byte pool,
    310  *     // while MHD_pool_get_free() still reports the full 1024.
    311  *
    312  * The documented contract is "@return new address of the block, or NULL
    313  * if the pool cannot support @a new_size bytes", so this is a plain
    314  * contract violation, and one that hands the caller a buffer size the
    315  * allocation does not have.  No MHD call site can reach it today: every
    316  * new_size MHD passes is derived from the pool size (connection.c:1636,
    317  * 2031, 2082, 2121, 2170, 6935), so it is a latent defect rather than
    318  * something reachable from the network.  Checking the addition itself,
    319  * e.g. `if (new_size > pool->size - old_offset) return NULL;`, would
    320  * close it.
    321  */
    322 static int wrap_realloc_enabled;
    323 
    324 static int known_bugs_read;
    325 
    326 /** Statistics, printed at exit with --verbose. */
    327 static unsigned long stat_ops;
    328 static unsigned long stat_alloc_ok;
    329 static unsigned long stat_alloc_fail;
    330 static unsigned long stat_realloc_moved;
    331 static unsigned long stat_resets;
    332 
    333 
    334 static void
    335 print_stats (void)
    336 {
    337   if (! fuzz_verbose)
    338     return;
    339   fprintf (stderr,
    340            "%s: ops=%lu allocations=%lu (failed %lu) "
    341            "moved reallocations=%lu resets=%lu\n",
    342            FUZZ_HARNESS_NAME,
    343            stat_ops, stat_alloc_ok, stat_alloc_fail,
    344            stat_realloc_moved, stat_resets);
    345 }
    346 
    347 
    348 /**
    349  * Report a finding, prefixed with the name of the operation that was
    350  * running.
    351  */
    352 static void
    353 fz_report (const char *op,
    354            const char *what)
    355 {
    356   char msg[256];
    357 
    358   (void) snprintf (msg, sizeof (msg), "%s: %s", op, what);
    359   fuzz_report_finding (msg);
    360 }
    361 
    362 
    363 /**
    364  * The ROUND_TO_ALIGN() of memorypool.c, wrap-around included: a size
    365  * that is too close to SIZE_MAX rounds to 0, which is how the allocator
    366  * detects it.
    367  */
    368 static size_t
    369 fz_round (size_t n)
    370 {
    371   return (n + (FZ_ALIGN_SIZE - 1)) / FZ_ALIGN_SIZE * FZ_ALIGN_SIZE;
    372 }
    373 
    374 
    375 /**
    376  * Byte @a idx of the check pattern of a block with seed @a tag.
    377  */
    378 static uint8_t
    379 fz_pat (uint8_t tag,
    380         size_t idx)
    381 {
    382   return (uint8_t) ((((unsigned int) tag) * 131u)
    383                     + ((unsigned int) (idx * 17u))
    384                     + 0x5Au);
    385 }
    386 
    387 
    388 /**
    389  * Write the check pattern into @a ptr[from..to).
    390  */
    391 static void
    392 fz_fill (uint8_t *ptr,
    393          uint8_t tag,
    394          size_t from,
    395          size_t to)
    396 {
    397   size_t i;
    398 
    399   if (to > FZ_PAT_MAX)
    400     to = FZ_PAT_MAX;
    401   for (i = from; i < to; i++)
    402     ptr[i] = fz_pat (tag, i);
    403 }
    404 
    405 
    406 /**
    407  * Verify that the first bytes of @a ptr still carry the pattern of
    408  * @a tag.  The expected bytes are built in an exactly sized malloc()ed
    409  * buffer, so that a comparison that runs off either end is caught by
    410  * ASAN rather than silently passing.
    411  */
    412 static void
    413 fz_verify (const uint8_t *ptr,
    414            size_t size,
    415            uint8_t tag,
    416            const char *op,
    417            const char *what)
    418 {
    419   size_t n = (size < FZ_PAT_MAX) ? size : (size_t) FZ_PAT_MAX;
    420   uint8_t *expect;
    421   size_t i;
    422 
    423   if (0 == n)
    424     return;
    425   expect = (uint8_t *) malloc (n);
    426   if (NULL == expect)
    427     abort ();
    428   for (i = 0; i < n; i++)
    429     expect[i] = fz_pat (tag, i);
    430   if (0 != memcmp (expect, ptr, n))
    431     fz_report (op, what);
    432   free (expect);
    433 }
    434 
    435 
    436 /**
    437  * Verify every live block.
    438  */
    439 static void
    440 fz_verify_all (struct fz_pool *st,
    441                const char *op)
    442 {
    443   unsigned int i;
    444 
    445   for (i = 0; i < st->nblk; i++)
    446     fz_verify (st->blk[i].ptr,
    447                st->blk[i].size,
    448                st->blk[i].tag,
    449                op,
    450                "the contents of a live allocation changed");
    451 }
    452 
    453 
    454 /**
    455  * Check a pointer the pool just returned: inside the pool, aligned, and
    456  * not overlapping any block that is still live.  The caller has already
    457  * removed the block being replaced (if any) from the model.
    458  */
    459 static void
    460 fz_check_ptr (struct fz_pool *st,
    461               void *p,
    462               size_t size,
    463               const char *op)
    464 {
    465   const uint8_t *up = (const uint8_t *) p;
    466   size_t off;
    467   unsigned int i;
    468 
    469   if ( (up < st->base) ||
    470        (up > st->base + st->cap) )
    471   {
    472     fz_report (op, "returned a pointer outside of the pool");
    473     return;
    474   }
    475   off = (size_t) (up - st->base);
    476   if ( (size > st->cap) ||
    477        (off + size > st->cap) )
    478     fz_report (op, "returned a block that extends past the end of the pool");
    479   if (0 != (off % FZ_ALIGN_SIZE))
    480     fz_report (op, "returned a misaligned pointer");
    481   if (0 == size)
    482     return;
    483   for (i = 0; i < st->nblk; i++)
    484   {
    485     const uint8_t *q = st->blk[i].ptr;
    486 
    487     if (0 == st->blk[i].size)
    488       continue;
    489     if ( (up < q + st->blk[i].size) &&
    490          (q < up + size) )
    491     {
    492       fz_report (op, "returned a block overlapping another live allocation");
    493       return;
    494     }
    495   }
    496 }
    497 
    498 
    499 /**
    500  * Invariants that must hold after every single operation.
    501  */
    502 static void
    503 fz_check_invariants (struct fz_pool *st,
    504                      const char *op)
    505 {
    506   size_t total = 0;
    507   size_t freem;
    508   unsigned int i;
    509 
    510   freem = MHD_pool_get_free (st->pool);
    511   if (freem > st->cap)
    512     fz_report (op, "MHD_pool_get_free() exceeds the size of the pool");
    513   for (i = 0; i < st->nblk; i++)
    514     total += st->blk[i].size;
    515   if (total > st->cap)
    516     fz_report (op, "the live allocations alone exceed the size of the pool");
    517   else if (total + freem > st->cap)
    518     fz_report (op,
    519                "the live allocations plus the free space exceed the size "
    520                "of the pool");
    521   if (st->paranoid)
    522     fz_verify_all (st, op);
    523 }
    524 
    525 
    526 static struct fz_block *
    527 fz_add (struct fz_pool *st,
    528         void *ptr,
    529         size_t size,
    530         bool from_end)
    531 {
    532   struct fz_block *b = &st->blk[st->nblk++];
    533 
    534   b->ptr = (uint8_t *) ptr;
    535   b->size = size;
    536   b->tag = st->next_tag++;
    537   b->from_end = from_end;
    538   fz_fill (b->ptr, b->tag, 0, size);
    539   return b;
    540 }
    541 
    542 
    543 static void
    544 fz_del (struct fz_pool *st,
    545         struct fz_block *b)
    546 {
    547   *b = st->blk[--st->nblk];
    548 }
    549 
    550 
    551 /**
    552  * Pick a live block.
    553  *
    554  * @param st the model
    555  * @param sel selector byte
    556  * @param front_only only consider blocks that may be reallocated
    557  * @return NULL if there is no such block
    558  */
    559 static struct fz_block *
    560 fz_pick (struct fz_pool *st,
    561          uint8_t sel,
    562          bool front_only)
    563 {
    564   unsigned int i;
    565   unsigned int n = 0;
    566   unsigned int idx;
    567 
    568   for (i = 0; i < st->nblk; i++)
    569   {
    570     if ( (! front_only) ||
    571          (! st->blk[i].from_end) )
    572       n++;
    573   }
    574   if (0 == n)
    575     return NULL;
    576   idx = ((unsigned int) sel) % n;
    577   for (i = 0; i < st->nblk; i++)
    578   {
    579     if ( (front_only) &&
    580          (st->blk[i].from_end) )
    581       continue;
    582     if (0 == idx)
    583       return &st->blk[i];
    584     idx--;
    585   }
    586   return NULL; /* unreachable */
    587 }
    588 
    589 
    590 /**
    591  * Turn a selector byte into a size.  The four classes matter: tiny
    592  * sizes are what headers use, fractions of the pool are what the
    593  * request buffers use, sizes around the currently free amount are where
    594  * the off-by-one-block bugs live, and sizes close to SIZE_MAX exercise
    595  * the "value wrap" guards of the allocator.
    596  */
    597 static size_t
    598 fz_size (uint8_t sel,
    599          size_t cap,
    600          size_t freem)
    601 {
    602   size_t d;
    603 
    604   switch (sel & 0x03)
    605   {
    606   case 0:
    607     return (size_t) (sel >> 2);              /* 0 .. 63 */
    608   case 1:
    609     return (((size_t) ((sel >> 2) + 1)) * cap) / 64u;
    610   case 2:
    611     d = (size_t) ((sel >> 2) & 0x07u);
    612     if (0 != (sel & 0x20))
    613       return freem + d;
    614     return (freem > d) ? (freem - d) : 0;
    615   default:
    616     return SIZE_MAX - (size_t) (sel >> 2);
    617   }
    618 }
    619 
    620 
    621 static void
    622 fz_pool_close (struct fz_pool *st)
    623 {
    624   MHD_pool_destroy (st->pool);
    625   st->pool = NULL;
    626   st->nblk = 0;
    627 }
    628 
    629 
    630 /**
    631  * Create a pool and learn its base address and its exact size.
    632  *
    633  * @return false if the pool could not be created
    634  */
    635 static bool
    636 fz_pool_open (struct fz_pool *st,
    637               uint8_t sel)
    638 {
    639   size_t max = fz_pool_sizes[((size_t) sel) % FZ_NUM_POOL_SIZES];
    640   void *base;
    641 
    642   st->nblk = 0;
    643   st->pool = MHD_pool_create (max);
    644   if (NULL == st->pool)
    645     return false;
    646   st->cap = MHD_pool_get_free (st->pool) + FZ_RED_ZONE_SIZE;
    647   if (st->cap != fz_round (max))
    648     fz_report ("MHD_pool_create",
    649                "a fresh pool does not offer the requested size rounded "
    650                "up to the alignment");
    651   /* MHD_pool_reset() with nothing to keep returns the start of the
    652      pool; connection.c:3021 relies on exactly this call.  It is the
    653      only way to learn the base address through the public interface. */
    654   base = MHD_pool_reset (st->pool, NULL, 0, 0);
    655   if (NULL == base)
    656   {
    657     fz_report ("MHD_pool_reset", "returned NULL for an empty pool");
    658     fz_pool_close (st);
    659     return false;
    660   }
    661   st->base = (uint8_t *) base;
    662   return true;
    663 }
    664 
    665 
    666 /* ------------------------------------------------------------------ */
    667 /* The individual operations                                           */
    668 /* ------------------------------------------------------------------ */
    669 
    670 /**
    671  * MHD_pool_allocate(), from the front or from the end.
    672  */
    673 static void
    674 fz_op_alloc (struct fz_pool *st,
    675              const uint8_t *op,
    676              bool prefer_end)
    677 {
    678   static const char *const nm[2] = { "MHD_pool_allocate",
    679                                      "MHD_pool_allocate (from_end)" };
    680   const bool from_end = (0 != (op[1] & 0x01)) || prefer_end;
    681   const char *name = nm[from_end ? 1 : 0];
    682   size_t freem;
    683   size_t after;
    684   size_t size;
    685   void *p;
    686 
    687   if (st->nblk >= FZ_MAX_BLOCKS)
    688     return;
    689   freem = MHD_pool_get_free (st->pool);
    690   size = fz_size (op[2], st->cap, freem);
    691   p = MHD_pool_allocate (st->pool, size, from_end);
    692   after = MHD_pool_get_free (st->pool);
    693   if (NULL == p)
    694   {
    695     stat_alloc_fail++;
    696     if (after != freem)
    697       fz_report (name, "a failed allocation changed the amount of free space");
    698     if ( (0 != fz_round (size)) &&
    699          (fz_round (size) <= freem) )
    700       fz_report (name,
    701                  "allocation failed although MHD_pool_get_free() reported "
    702                  "room for it");
    703     return;
    704   }
    705   stat_alloc_ok++;
    706   if (after > freem)
    707     fz_report (name, "MHD_pool_get_free() increased across an allocation");
    708   else if (freem - after < size)
    709     fz_report (name,
    710                "MHD_pool_get_free() dropped by less than the allocated size");
    711   fz_check_ptr (st, p, size, name);
    712   (void) fz_add (st, p, size, from_end);
    713 }
    714 
    715 
    716 /**
    717  * Allocate exactly MHD_pool_get_free() bytes.  response.c:2203 does
    718  * this and dereferences the result without a NULL check, so it must
    719  * always succeed, and it must leave the pool without any free space.
    720  */
    721 static void
    722 fz_op_alloc_all (struct fz_pool *st,
    723                  const uint8_t *op)
    724 {
    725   static const char name[] = "MHD_pool_allocate (all free)";
    726   const bool from_end = (0 != (op[1] & 0x01));
    727   size_t freem;
    728   void *p;
    729 
    730   if (st->nblk >= FZ_MAX_BLOCKS)
    731     return;
    732   freem = MHD_pool_get_free (st->pool);
    733   if (0 == freem)
    734     return;
    735   p = MHD_pool_allocate (st->pool, freem, from_end);
    736   if (NULL == p)
    737   {
    738     stat_alloc_fail++;
    739     fz_report (name,
    740                "allocating exactly MHD_pool_get_free() bytes failed");
    741     return;
    742   }
    743   stat_alloc_ok++;
    744   fz_check_ptr (st, p, freem, name);
    745   if (0 != MHD_pool_get_free (st->pool))
    746     fz_report (name,
    747                "the pool still reports free space after all of it was "
    748                "allocated");
    749   (void) fz_add (st, p, freem, from_end);
    750 }
    751 
    752 
    753 /**
    754  * MHD_pool_try_alloc().  Checks the contract of @a required_bytes.
    755  */
    756 static void
    757 fz_op_try_alloc (struct fz_pool *st,
    758                  const uint8_t *op)
    759 {
    760   static const char name[] = "MHD_pool_try_alloc";
    761   size_t freem;
    762   size_t after;
    763   size_t size;
    764   size_t need;
    765   void *p;
    766 
    767   if (st->nblk >= FZ_MAX_BLOCKS)
    768     return;
    769   freem = MHD_pool_get_free (st->pool);
    770   size = fz_size (op[2], st->cap, freem);
    771   need = 0x5A5A5A5Au; /* poor man's "was it written at all" */
    772   p = MHD_pool_try_alloc (st->pool, size, &need);
    773   after = MHD_pool_get_free (st->pool);
    774   if (NULL == p)
    775   {
    776     stat_alloc_fail++;
    777     if (after != freem)
    778       fz_report (name, "a failed allocation changed the amount of free space");
    779     if (0 == need)
    780       fz_report (name,
    781                  "the allocation failed but no additional memory is "
    782                  "reported to be required");
    783     else if ( (SIZE_MAX != need) &&
    784               (need > st->cap) )
    785       fz_report (name,
    786                  "more memory is reported to be required than the pool "
    787                  "has in total");
    788     if ( (0 != fz_round (size)) &&
    789          (fz_round (size) <= freem) )
    790       fz_report (name,
    791                  "allocation failed although MHD_pool_get_free() reported "
    792                  "room for it");
    793     return;
    794   }
    795   stat_alloc_ok++;
    796   if (0 != need)
    797     fz_report (name,
    798                "the allocation succeeded but required_bytes was not "
    799                "cleared");
    800   if (after > freem)
    801     fz_report (name, "MHD_pool_get_free() increased across an allocation");
    802   else if (freem - after < size)
    803     fz_report (name,
    804                "MHD_pool_get_free() dropped by less than the allocated size");
    805   fz_check_ptr (st, p, size, name);
    806   /* try_alloc always allocates "from the end" */
    807   (void) fz_add (st, p, size, true);
    808 }
    809 
    810 
    811 /**
    812  * The logic of MHD_connection_alloc_memory_() (connection.c:706): when
    813  * MHD_pool_try_alloc() fails it names the number of bytes that have to
    814  * be freed in the relocatable area; freeing exactly that many bytes by
    815  * shrinking a block that is resizable in-place must make the very same
    816  * allocation succeed.  If it does not, MHD returns "out of memory" for
    817  * a request it has the memory for.
    818  */
    819 static void
    820 fz_op_squeeze (struct fz_pool *st,
    821                const uint8_t *op)
    822 {
    823   static const char name[] = "MHD_pool_try_alloc (squeeze)";
    824   size_t size;
    825   size_t need = 0;
    826   size_t need2 = 0;
    827   void *p;
    828   unsigned int i;
    829   struct fz_block *victim = NULL;
    830 
    831   if (st->nblk >= FZ_MAX_BLOCKS)
    832     return;
    833   size = fz_size (op[2], st->cap, MHD_pool_get_free (st->pool));
    834   p = MHD_pool_try_alloc (st->pool, size, &need);
    835   if (NULL != p)
    836   {
    837     fz_check_ptr (st, p, size, name);
    838     (void) fz_add (st, p, size, true);
    839     return;
    840   }
    841   if ( (0 == need) ||
    842        (SIZE_MAX == need) )
    843     return;
    844   for (i = 0; i < st->nblk; i++)
    845   {
    846     if (st->blk[i].from_end)
    847       continue;
    848     if (st->blk[i].size < need)
    849       continue;
    850     if (! MHD_pool_is_resizable_inplace (st->pool,
    851                                          st->blk[i].ptr,
    852                                          st->blk[i].size))
    853       continue;
    854     victim = &st->blk[i];
    855     break;
    856   }
    857   if (NULL == victim)
    858     return;
    859   {
    860     const size_t new_size = victim->size - need;
    861     void *shrunk = MHD_pool_reallocate (st->pool,
    862                                         victim->ptr,
    863                                         victim->size,
    864                                         new_size);
    865 
    866     if (NULL == shrunk)
    867     {
    868       fz_report (name,
    869                  "shrinking a block that is resizable in-place failed");
    870       return;
    871     }
    872     if (shrunk != victim->ptr)
    873       fz_report (name,
    874                  "shrinking a block that is resizable in-place moved it");
    875     victim->ptr = (uint8_t *) shrunk;
    876     victim->size = new_size;
    877     fz_verify (victim->ptr, victim->size, victim->tag, name,
    878                "shrinking a block damaged its contents");
    879   }
    880   p = MHD_pool_try_alloc (st->pool, size, &need2);
    881   if (NULL == p)
    882   {
    883     fz_report (name,
    884                "the allocation still fails after freeing the number of "
    885                "bytes that required_bytes asked for");
    886     return;
    887   }
    888   fz_check_ptr (st, p, size, name);
    889   (void) fz_add (st, p, size, true);
    890 }
    891 
    892 
    893 /**
    894  * MHD_pool_reallocate() of a live block that was allocated from the
    895  * front.  Blocks allocated "from the end" are excluded: memorypool.c
    896  * documents ("Blocks 'from the end' must not be reallocated") and
    897  * asserts that.
    898  */
    899 static void
    900 fz_op_realloc (struct fz_pool *st,
    901                const uint8_t *op)
    902 {
    903   static const char name[] = "MHD_pool_reallocate";
    904   struct fz_block *b = fz_pick (st, op[1], true);
    905   struct fz_block saved;
    906   size_t freem;
    907   size_t after;
    908   size_t new_size;
    909   bool inplace;
    910   void *p;
    911 
    912   if (NULL == b)
    913     return;
    914   freem = MHD_pool_get_free (st->pool);
    915   new_size = fz_size (op[2], st->cap, freem);
    916   if ( (0 == b->size) &&
    917        (new_size > SIZE_MAX - FZ_ALIGN_SIZE) &&
    918        (! wrap_realloc_enabled) )
    919     return; /* open finding F2, see above */
    920   inplace = MHD_pool_is_resizable_inplace (st->pool, b->ptr, b->size);
    921   saved = *b;
    922   p = MHD_pool_reallocate (st->pool, b->ptr, b->size, new_size);
    923   after = MHD_pool_get_free (st->pool);
    924   if (NULL == p)
    925   {
    926     /* "old continues to be valid for old_size" */
    927     if (after != freem)
    928       fz_report (name,
    929                  "a failed reallocation changed the amount of free space");
    930     fz_verify (saved.ptr, saved.size, saved.tag, name,
    931                "a failed reallocation damaged the old block");
    932     if ( (inplace) &&
    933          (new_size <= saved.size + freem) )
    934       fz_report (name,
    935                  "reallocation failed although the block is resizable "
    936                  "in-place and the pool has the required free space");
    937     return;
    938   }
    939   if ( (inplace) &&
    940        (p != saved.ptr) )
    941     fz_report (name,
    942                "a block that MHD_pool_is_resizable_inplace() accepted was "
    943                "moved");
    944   if ( (new_size >= saved.size) &&
    945        (after > freem) )
    946     fz_report (name,
    947                "MHD_pool_get_free() increased across a growing "
    948                "reallocation");
    949   /* the old location is gone as far as the model is concerned */
    950   fz_del (st, b);
    951   if (p != saved.ptr)
    952     stat_realloc_moved++;
    953   fz_check_ptr (st, p, new_size, name);
    954   fz_verify ((const uint8_t *) p,
    955              (new_size < saved.size) ? new_size : saved.size,
    956              saved.tag,
    957              name,
    958              "reallocation did not preserve the contents of the block");
    959   b = &st->blk[st->nblk++];
    960   b->ptr = (uint8_t *) p;
    961   b->size = new_size;
    962   b->tag = saved.tag;
    963   b->from_end = false;
    964   if (new_size > saved.size)
    965     fz_fill (b->ptr, b->tag, saved.size, new_size);
    966 }
    967 
    968 
    969 /**
    970  * MHD_pool_reallocate() with @a old == NULL, which is the documented
    971  * way to obtain a fresh relocatable block (connection.c:2121 uses it
    972  * for the very first write buffer).
    973  */
    974 static void
    975 fz_op_realloc_new (struct fz_pool *st,
    976                    const uint8_t *op)
    977 {
    978   static const char name[] = "MHD_pool_reallocate (fresh)";
    979   size_t freem;
    980   size_t size;
    981   void *p;
    982 
    983   if (st->nblk >= FZ_MAX_BLOCKS)
    984     return;
    985   freem = MHD_pool_get_free (st->pool);
    986   size = fz_size (op[2], st->cap, freem);
    987   p = MHD_pool_reallocate (st->pool, NULL, 0, size);
    988   if (NULL == p)
    989   {
    990     stat_alloc_fail++;
    991     if ( (0 != fz_round (size)) &&
    992          (fz_round (size) <= freem) )
    993       fz_report (name,
    994                  "allocation failed although MHD_pool_get_free() reported "
    995                  "room for it");
    996     return;
    997   }
    998   stat_alloc_ok++;
    999   if (MHD_pool_get_free (st->pool) > freem)
   1000     fz_report (name, "MHD_pool_get_free() increased across an allocation");
   1001   fz_check_ptr (st, p, size, name);
   1002   (void) fz_add (st, p, size, false);
   1003 }
   1004 
   1005 
   1006 /**
   1007  * MHD_pool_deallocate() of a live block, or of NULL ("the NULL is
   1008  * tolerated").  A block is always deallocated with the size it
   1009  * currently has: memorypool.c asserts that the block lies inside the
   1010  * allocated area, and splitting a block is explicitly disallowed.
   1011  */
   1012 static void
   1013 fz_op_dealloc (struct fz_pool *st,
   1014                const uint8_t *op)
   1015 {
   1016   static const char name[] = "MHD_pool_deallocate";
   1017   struct fz_block *b = fz_pick (st, op[1], false);
   1018   size_t freem;
   1019   size_t after;
   1020 
   1021   freem = MHD_pool_get_free (st->pool);
   1022   if ( (NULL != b) &&
   1023        (b->from_end) &&
   1024        (0 != b->size) &&
   1025        (0 == freem) &&
   1026        (! full_dealloc_enabled) )
   1027   {
   1028     /* See the comment on full_dealloc_enabled: this is an open finding,
   1029        not a precondition of MHD_pool_deallocate().  The lowest-addressed
   1030        live "from the end" block of non-zero size starts exactly at
   1031        pool->end, which for a full pool is also pool->pos -- the
   1032        ambiguous case.  Any block above it is unaffected, so only that
   1033        one block is spared.  Zero-sized blocks do not count: they consume
   1034        nothing, so they can sit below pool->end once a later
   1035        deallocation has moved pool->end back up past them. */
   1036     unsigned int i;
   1037 
   1038     for (i = 0; i < st->nblk; i++)
   1039     {
   1040       if ( (st->blk[i].from_end) &&
   1041            (0 != st->blk[i].size) &&
   1042            (st->blk[i].ptr < b->ptr) )
   1043         break;
   1044     }
   1045     if (i == st->nblk)
   1046       return;
   1047   }
   1048   if (NULL == b)
   1049   {
   1050     MHD_pool_deallocate (st->pool, NULL, 0);
   1051   }
   1052   else
   1053   {
   1054     fz_verify (b->ptr, b->size, b->tag, name,
   1055                "the contents of the block changed before it was freed");
   1056     MHD_pool_deallocate (st->pool, b->ptr, b->size);
   1057     fz_del (st, b);
   1058   }
   1059   after = MHD_pool_get_free (st->pool);
   1060   if (after < freem)
   1061     fz_report (name, "deallocation reduced the amount of free space");
   1062 }
   1063 
   1064 
   1065 /**
   1066  * MHD_pool_reset().  Preconditions: copy_bytes <= new_size,
   1067  * new_size <= size of the pool, and the kept block must really hold
   1068  * copy_bytes bytes.
   1069  */
   1070 static void
   1071 fz_op_reset (struct fz_pool *st,
   1072              const uint8_t *op)
   1073 {
   1074   static const char name[] = "MHD_pool_reset";
   1075   struct fz_block *b = fz_pick (st, (uint8_t) (op[1] & 0x0F), false);
   1076   size_t new_size;
   1077   size_t copy;
   1078   uint8_t tag = 0;
   1079   void *p;
   1080 
   1081   new_size = fz_size (op[2], st->cap, MHD_pool_get_free (st->pool));
   1082   if (new_size > st->cap)
   1083     new_size = st->cap;
   1084   copy = 0;
   1085   if (NULL != b)
   1086   {
   1087     copy = (b->size * ((size_t) (op[1] >> 4))) / 15u;
   1088     if (copy > b->size)
   1089       copy = b->size;
   1090     if (copy > new_size)
   1091       copy = new_size;
   1092     tag = b->tag;
   1093     fz_verify (b->ptr, b->size, b->tag, name,
   1094                "the contents of the kept block changed before the reset");
   1095   }
   1096   p = MHD_pool_reset (st->pool,
   1097                       (NULL != b) ? b->ptr : NULL,
   1098                       copy,
   1099                       new_size);
   1100   stat_resets++;
   1101   /* every allocation is gone now */
   1102   st->nblk = 0;
   1103   if (NULL == p)
   1104   {
   1105     fz_report (name, "returned NULL");
   1106     return;
   1107   }
   1108   fz_check_ptr (st, p, new_size, name);
   1109   fz_verify ((const uint8_t *) p, copy, tag, name,
   1110              "the kept bytes did not survive the reset");
   1111   b = fz_add (st, p, new_size, false);
   1112   /* fz_add() has just re-tagged and re-filled the whole block */
   1113 }
   1114 
   1115 
   1116 /**
   1117  * MHD_pool_is_resizable_inplace() on a live block, or on NULL.
   1118  */
   1119 static void
   1120 fz_op_resizable (struct fz_pool *st,
   1121                  const uint8_t *op)
   1122 {
   1123   static const char name[] = "MHD_pool_is_resizable_inplace";
   1124   struct fz_block *b = fz_pick (st, op[1], false);
   1125   bool r;
   1126 
   1127   if ( (NULL == b) ||
   1128        (0 != (op[1] & 0x80)) )
   1129   {
   1130     if (MHD_pool_is_resizable_inplace (st->pool, NULL, 0))
   1131       fz_report (name, "an unallocated block is reported as resizable");
   1132     return;
   1133   }
   1134   r = MHD_pool_is_resizable_inplace (st->pool, b->ptr, b->size);
   1135   if ( (r) &&
   1136        (b->from_end) &&
   1137        (0 != b->size) )
   1138     fz_report (name,
   1139                "a block allocated from the end is reported as resizable "
   1140                "in-place");
   1141   if (! r)
   1142     return;
   1143   /* A block that is resizable in-place must survive a resize to its own
   1144      size without moving; connection.c asserts this after every such
   1145      reallocation. */
   1146   {
   1147     void *p = MHD_pool_reallocate (st->pool, b->ptr, b->size, b->size);
   1148 
   1149     if (NULL == p)
   1150       fz_report (name,
   1151                  "reallocating a resizable block to its own size failed");
   1152     else if (p != b->ptr)
   1153       fz_report (name,
   1154                  "reallocating a resizable block to its own size moved it");
   1155   }
   1156 }
   1157 
   1158 
   1159 static void
   1160 fz_do_op (struct fz_pool *st,
   1161           const uint8_t *op,
   1162           bool prefer_end)
   1163 {
   1164   const char *name = "operation";
   1165 
   1166   stat_ops++;
   1167   switch ((enum fz_op) (op[0] % (uint8_t) FZ_OP_COUNT))
   1168   {
   1169   case FZ_OP_ALLOC:
   1170     fz_op_alloc (st, op, prefer_end);
   1171     break;
   1172   case FZ_OP_ALLOC_ALL:
   1173     fz_op_alloc_all (st, op);
   1174     break;
   1175   case FZ_OP_TRY_ALLOC:
   1176     fz_op_try_alloc (st, op);
   1177     break;
   1178   case FZ_OP_SQUEEZE:
   1179     fz_op_squeeze (st, op);
   1180     break;
   1181   case FZ_OP_REALLOC:
   1182     fz_op_realloc (st, op);
   1183     break;
   1184   case FZ_OP_REALLOC_NEW:
   1185     fz_op_realloc_new (st, op);
   1186     break;
   1187   case FZ_OP_DEALLOC:
   1188     fz_op_dealloc (st, op);
   1189     break;
   1190   case FZ_OP_RESET:
   1191     fz_op_reset (st, op);
   1192     break;
   1193   case FZ_OP_GET_FREE:
   1194     name = "MHD_pool_get_free";
   1195     break;
   1196   case FZ_OP_RESIZABLE:
   1197     fz_op_resizable (st, op);
   1198     break;
   1199   case FZ_OP_VERIFY:
   1200     name = "verify";
   1201     fz_verify_all (st, name);
   1202     break;
   1203   case FZ_OP_RECREATE:
   1204     fz_pool_close (st);
   1205     if (! fz_pool_open (st, op[1]))
   1206       return;
   1207     break;
   1208   case FZ_OP_COUNT:
   1209   default:
   1210     break;
   1211   }
   1212   fz_check_invariants (st, name);
   1213 }
   1214 
   1215 
   1216 int
   1217 LLVMFuzzerTestOneInput (const uint8_t *data,
   1218                         size_t size)
   1219 {
   1220   static bool inited = false;
   1221   struct fz_pool st;
   1222   size_t nops;
   1223   size_t i;
   1224 
   1225   if (size < 5)
   1226     return 0;
   1227   if (! inited)
   1228   {
   1229     inited = true;
   1230     /* Sets the page size used by MHD_pool_create(); MHD does this once
   1231        from MHD_start_daemon(). */
   1232     MHD_init_mem_pools_ ();
   1233     (void) atexit (&print_stats);
   1234   }
   1235   if (! known_bugs_read)
   1236   {
   1237     const char *e;
   1238 
   1239     known_bugs_read = 1;
   1240     e = getenv ("MHD_FUZZ_POOL_FULL_DEALLOC");
   1241     if (NULL != e)
   1242       full_dealloc_enabled = (0 != atoi (e));
   1243     e = getenv ("MHD_FUZZ_POOL_WRAP_REALLOC");
   1244     if (NULL != e)
   1245       wrap_realloc_enabled = (0 != atoi (e));
   1246   }
   1247   memset (&st, 0, sizeof (st));
   1248   st.paranoid = (0 != (data[1] & 0x01));
   1249   if (! fz_pool_open (&st, data[0]))
   1250     return 0;
   1251   nops = (size - 2) / 3;
   1252   if (nops > FZ_MAX_OPS)
   1253     nops = FZ_MAX_OPS;
   1254   for (i = 0; i < nops; i++)
   1255   {
   1256     if (NULL == st.pool)
   1257       break;
   1258     fz_do_op (&st, data + 2 + 3 * i, (0 != (data[1] & 0x02)));
   1259   }
   1260   fz_verify_all (&st, "final");
   1261   fz_pool_close (&st);  /* MHD_pool_destroy() tolerates a NULL pool */
   1262   return 0;
   1263 }
   1264 
   1265 
   1266 /* ------------------------------------------------------------------ */
   1267 /* Generator                                                           */
   1268 /* ------------------------------------------------------------------ */
   1269 
   1270 /**
   1271  * Opcodes, weighted: the allocating operations and the reallocation are
   1272  * what move the pool's internal offsets around, so they get most of the
   1273  * probability mass, while the read-only queries and the destructive
   1274  * reset and re-create are rarer.
   1275  */
   1276 static const uint8_t gen_ops[] = {
   1277   FZ_OP_ALLOC, FZ_OP_ALLOC, FZ_OP_ALLOC, FZ_OP_ALLOC,
   1278   FZ_OP_ALLOC_ALL,
   1279   FZ_OP_TRY_ALLOC, FZ_OP_TRY_ALLOC,
   1280   FZ_OP_SQUEEZE, FZ_OP_SQUEEZE,
   1281   FZ_OP_REALLOC, FZ_OP_REALLOC, FZ_OP_REALLOC, FZ_OP_REALLOC,
   1282   FZ_OP_REALLOC_NEW,
   1283   FZ_OP_DEALLOC, FZ_OP_DEALLOC, FZ_OP_DEALLOC,
   1284   FZ_OP_RESET,
   1285   FZ_OP_GET_FREE,
   1286   FZ_OP_RESIZABLE, FZ_OP_RESIZABLE,
   1287   FZ_OP_VERIFY,
   1288   FZ_OP_RECREATE
   1289 };
   1290 
   1291 
   1292 /**
   1293  * Size selector bytes that are worth trying often: the boundary cases
   1294  * (exactly the free space, one alignment unit more or less) and the
   1295  * value-wrap guards.
   1296  */
   1297 static uint8_t
   1298 gen_size_sel (struct fuzz_rng *rng)
   1299 {
   1300   const uint32_t k = fuzz_below (rng, 100);
   1301   uint32_t d;
   1302   uint32_t sign;
   1303 
   1304   if (k < 35)                                  /* tiny */
   1305     return (uint8_t) ((fuzz_below (rng, 64) << 2) | 0u);
   1306   if (k < 60)                                  /* fraction of the pool */
   1307     return (uint8_t) ((fuzz_below (rng, 64) << 2) | 1u);
   1308   if (k < 95)
   1309   {                                            /* around the free space */
   1310     /* Two statements, not one expression: the order in which the
   1311        operands of '|' are evaluated is unspecified, and both calls
   1312        advance the PRNG, so a single expression would make the generated
   1313        stream compiler-dependent. */
   1314     d = fuzz_below (rng, 8);
   1315     sign = fuzz_below (rng, 2);
   1316     return (uint8_t) ((d << 2) | (sign << 5) | 2u);
   1317   }
   1318   return (uint8_t) ((fuzz_below (rng, 64) << 2) | 3u);   /* value wrap */
   1319 }
   1320 
   1321 
   1322 static size_t
   1323 fuzz_generate (struct fuzz_rng *rng,
   1324                uint8_t *buf,
   1325                size_t cap)
   1326 {
   1327   size_t len = 0;
   1328   unsigned int nops;
   1329   unsigned int i;
   1330   unsigned int psel;
   1331   uint8_t flags = 0;
   1332 
   1333   if (cap < 8)
   1334     return 0;
   1335   /* Small pools are where the interesting paths are, so bias towards
   1336      them, but keep the whole table reachable. */
   1337   if (fuzz_chance (rng, 3))
   1338     psel = fuzz_below (rng, (uint32_t) FZ_NUM_POOL_SIZES);
   1339   else
   1340     psel = fuzz_below (rng, 16);
   1341   buf[len++] = (uint8_t) psel;
   1342   /* One PRNG call per statement, see gen_size_sel(). */
   1343   if (fuzz_chance (rng, 4))
   1344     flags |= 0x01;
   1345   if (fuzz_chance (rng, 8))
   1346     flags |= 0x02;
   1347   buf[len++] = flags;
   1348   nops = 1 + fuzz_below (rng, FZ_MAX_OPS);
   1349   for (i = 0; i < nops; i++)
   1350   {
   1351     if (len + 3 > cap)
   1352       break;
   1353     buf[len++] = gen_ops[fuzz_below (rng, (uint32_t) (sizeof (gen_ops)))];
   1354     buf[len++] = fuzz_byte (rng);
   1355     buf[len++] = gen_size_sel (rng);
   1356   }
   1357   return len;
   1358 }
   1359 
   1360 
   1361 /* ------------------------------------------------------------------ */
   1362 /* Seed corpus                                                         */
   1363 /* ------------------------------------------------------------------ */
   1364 
   1365 /* Size selectors, see fz_size() */
   1366 #define SZ_TINY(n)    ((uint8_t) ((((unsigned int) (n)) << 2) | 0u))
   1367 #define SZ_FRAC(k)    ((uint8_t) ((((unsigned int) (k)) << 2) | 1u))
   1368 #define SZ_FREE       ((uint8_t) 2u)
   1369 #define SZ_FREE_M(d)  ((uint8_t) ((((unsigned int) (d)) << 2) | 2u))
   1370 #define SZ_FREE_P(d)  ((uint8_t) ((((unsigned int) (d)) << 2) | 0x20u | 2u))
   1371 #define SZ_HUGE       ((uint8_t) 3u)
   1372 
   1373 /* Pool size selectors, indices into fz_pool_sizes[] */
   1374 #define PS_1     0
   1375 #define PS_16    2
   1376 #define PS_32    4
   1377 #define PS_64    6
   1378 #define PS_128   8
   1379 #define PS_256   11
   1380 #define PS_512   14
   1381 #define PS_1024  16
   1382 #define PS_1500  18
   1383 #define PS_32768 23
   1384 
   1385 #define OPR(o,b,s) ((uint8_t) (o)), ((uint8_t) (b)), (s)
   1386 
   1387 static const uint8_t seed_grow_shrink[] = {
   1388   PS_512, 0x01,
   1389   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (32)),
   1390   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (63)),
   1391   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (8)),
   1392   OPR (FZ_OP_REALLOC, 0x00, SZ_FRAC (32)),
   1393   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
   1394   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (1)),
   1395   OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0))
   1396 };
   1397 
   1398 static const uint8_t seed_two_blocks_realloc[] = {
   1399   PS_256, 0x01,
   1400   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (17)),
   1401   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (23)),
   1402   /* the first block is no longer the last one: it has to move */
   1403   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (60)),
   1404   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
   1405   OPR (FZ_OP_REALLOC, 0x01, SZ_TINY (40)),
   1406   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
   1407 };
   1408 
   1409 static const uint8_t seed_from_end[] = {
   1410   PS_128, 0x01,
   1411   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16)),
   1412   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (1)),
   1413   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (16)),
   1414   OPR (FZ_OP_RESIZABLE, 0x00, SZ_TINY (0)),
   1415   OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0)),
   1416   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16))
   1417 };
   1418 
   1419 static const uint8_t seed_fill_exactly[] = {
   1420   PS_128, 0x01,
   1421   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16)),
   1422   OPR (FZ_OP_ALLOC_ALL, 0x00, SZ_TINY (0)),
   1423   OPR (FZ_OP_GET_FREE, 0x00, SZ_TINY (0)),
   1424   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (1)),
   1425   OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_TINY (1))
   1426 };
   1427 
   1428 static const uint8_t seed_squeeze[] = {
   1429   PS_512, 0x01,
   1430   OPR (FZ_OP_ALLOC, 0x00, SZ_FREE),
   1431   OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (40)),
   1432   OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (7)),
   1433   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
   1434   OPR (FZ_OP_SQUEEZE, 0x00, SZ_FRAC (8))
   1435 };
   1436 
   1437 static const uint8_t seed_squeeze_small[] = {
   1438   PS_128, 0x01,
   1439   OPR (FZ_OP_REALLOC_NEW, 0x00, SZ_FREE_M (2)),
   1440   OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (17)),
   1441   OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (17)),
   1442   OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (17))
   1443 };
   1444 
   1445 static const uint8_t seed_reset_keep[] = {
   1446   PS_1500, 0x01,
   1447   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (60)),
   1448   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (12)),
   1449   OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (31)),
   1450   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
   1451   OPR (FZ_OP_RESET, 0xF0, SZ_TINY (4)),
   1452   OPR (FZ_OP_RESET, 0x00, SZ_TINY (0))
   1453 };
   1454 
   1455 static const uint8_t seed_reset_full[] = {
   1456   PS_256, 0x01,
   1457   OPR (FZ_OP_ALLOC, 0x00, SZ_FRAC (63)),
   1458   OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (63)),
   1459   OPR (FZ_OP_RESET, 0xF0, SZ_FREE_P (1)),
   1460   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
   1461 };
   1462 
   1463 static const uint8_t seed_boundary[] = {
   1464   PS_64, 0x01,
   1465   OPR (FZ_OP_ALLOC, 0x00, SZ_FREE_M (1)),
   1466   OPR (FZ_OP_ALLOC, 0x00, SZ_FREE),
   1467   OPR (FZ_OP_ALLOC, 0x01, SZ_FREE_P (1)),
   1468   OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_FREE),
   1469   OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0)),
   1470   OPR (FZ_OP_ALLOC, 0x00, SZ_FREE)
   1471 };
   1472 
   1473 static const uint8_t seed_wrap[] = {
   1474   PS_256, 0x00,
   1475   OPR (FZ_OP_ALLOC, 0x00, SZ_HUGE),
   1476   OPR (FZ_OP_ALLOC, 0x01, SZ_HUGE),
   1477   OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_HUGE),
   1478   OPR (FZ_OP_REALLOC_NEW, 0x00, SZ_HUGE),
   1479   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (16)),
   1480   OPR (FZ_OP_REALLOC, 0x00, SZ_HUGE),
   1481   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
   1482 };
   1483 
   1484 static const uint8_t seed_tiny_pool[] = {
   1485   PS_1, 0x01,
   1486   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (1)),
   1487   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (1)),
   1488   OPR (FZ_OP_GET_FREE, 0x00, SZ_TINY (0)),
   1489   OPR (FZ_OP_RESET, 0xF0, SZ_TINY (1)),
   1490   OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0))
   1491 };
   1492 
   1493 static const uint8_t seed_zero_sizes[] = {
   1494   PS_32, 0x01,
   1495   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (0)),
   1496   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (0)),
   1497   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (0)),
   1498   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (4)),
   1499   OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0)),
   1500   OPR (FZ_OP_RESET, 0x00, SZ_TINY (0))
   1501 };
   1502 
   1503 static const uint8_t seed_many_small[] = {
   1504   PS_1500, 0x01,
   1505   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5)),
   1506   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (5)),
   1507   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5)),
   1508   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (5)),
   1509   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5)),
   1510   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (5)),
   1511   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (33)),
   1512   OPR (FZ_OP_REALLOC, 0x01, SZ_TINY (33)),
   1513   OPR (FZ_OP_DEALLOC, 0x02, SZ_TINY (0)),
   1514   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
   1515   OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5))
   1516 };
   1517 
   1518 static const uint8_t seed_recreate[] = {
   1519   PS_32768, 0x00,
   1520   OPR (FZ_OP_ALLOC, 0x00, SZ_FRAC (60)),
   1521   OPR (FZ_OP_RECREATE, PS_16, SZ_TINY (0)),
   1522   OPR (FZ_OP_ALLOC, 0x00, SZ_FREE),
   1523   OPR (FZ_OP_RECREATE, PS_512, SZ_TINY (0)),
   1524   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (24)),
   1525   OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (2))
   1526 };
   1527 
   1528 /* The read-buffer life cycle of a connection: allocate the read buffer,
   1529    grow it to everything that is free, put the parsed headers "at the
   1530    end", shrink the read buffer to what was actually received, then
   1531    reset the pool keeping the received bytes -- connection.c does
   1532    exactly this for every keep-alive request. */
   1533 static const uint8_t seed_connection_cycle[] = {
   1534   PS_1500, 0x01,
   1535   OPR (FZ_OP_REALLOC_NEW, 0x00, SZ_FRAC (31)),
   1536   OPR (FZ_OP_REALLOC, 0x00, SZ_FREE),
   1537   OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_TINY (12)),
   1538   OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_TINY (20)),
   1539   OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (40)),
   1540   OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (60)),
   1541   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
   1542   OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (31)),
   1543   OPR (FZ_OP_REALLOC, 0x00, SZ_FREE),
   1544   OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
   1545 };
   1546 
   1547 
   1548 /* The reproducer of the open finding described at full_dealloc_enabled:
   1549    a 128 byte pool, one 16 byte block "from the end", the whole rest of
   1550    the pool allocated from the front, then that first block released.
   1551    Inert unless MHD_FUZZ_POOL_FULL_DEALLOC=1 is set. */
   1552 static const uint8_t seed_dealloc_end_full[] = {
   1553   PS_128, 0x01,
   1554   OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16)),
   1555   OPR (FZ_OP_ALLOC_ALL, 0x00, SZ_TINY (0)),
   1556   OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0))
   1557 };
   1558 
   1559 
   1560 /* The reproducer of the open finding F2: MHD_pool_reset() with nothing
   1561    to keep leaves a zero-length block at the front boundary, and
   1562    reallocating that to SIZE_MAX wraps.  Inert unless
   1563    MHD_FUZZ_POOL_WRAP_REALLOC=1 is set. */
   1564 static const uint8_t seed_realloc_wrap[] = {
   1565   PS_1024, 0x01,
   1566   OPR (FZ_OP_RESET, 0x00, SZ_TINY (0)),
   1567   OPR (FZ_OP_REALLOC, 0x00, SZ_HUGE)
   1568 };
   1569 
   1570 
   1571 struct mp_seed
   1572 {
   1573   const uint8_t *bytes;
   1574   size_t len;
   1575 };
   1576 
   1577 #define MSEED(a) { (a), sizeof (a) }
   1578 
   1579 static const struct mp_seed mp_seeds[] = {
   1580   MSEED (seed_grow_shrink),
   1581   MSEED (seed_two_blocks_realloc),
   1582   MSEED (seed_from_end),
   1583   MSEED (seed_fill_exactly),
   1584   MSEED (seed_squeeze),
   1585   MSEED (seed_squeeze_small),
   1586   MSEED (seed_reset_keep),
   1587   MSEED (seed_reset_full),
   1588   MSEED (seed_boundary),
   1589   MSEED (seed_wrap),
   1590   MSEED (seed_tiny_pool),
   1591   MSEED (seed_zero_sizes),
   1592   MSEED (seed_many_small),
   1593   MSEED (seed_recreate),
   1594   MSEED (seed_connection_cycle),
   1595   MSEED (seed_dealloc_end_full),
   1596   MSEED (seed_realloc_wrap)
   1597 };
   1598 
   1599 
   1600 static size_t
   1601 fuzz_seed_count (void)
   1602 {
   1603   return sizeof (mp_seeds) / sizeof (mp_seeds[0]);
   1604 }
   1605 
   1606 
   1607 static const uint8_t *
   1608 fuzz_seed_get (size_t idx,
   1609                size_t *len)
   1610 {
   1611   *len = mp_seeds[idx].len;
   1612   return mp_seeds[idx].bytes;
   1613 }