|
GNU libmicrohttpd 1.0.9
|
Direct in-process fuzzer for src/microhttpd/memorypool.c. More...

Go to the source code of this file.
Macros | |
| #define | FUZZ_HARNESS_NAME "fuzz_memorypool" |
| #define | FZ_ALIGN_SIZE (2 * sizeof (void *)) |
| #define | FZ_RED_ZONE_SIZE ((size_t) 0) |
| #define | FZ_MAX_BLOCKS 24 |
| #define | FZ_MAX_OPS 64 |
| #define | FZ_PAT_MAX 96 |
| #define | FZ_NUM_POOL_SIZES (sizeof (fz_pool_sizes) / sizeof (fz_pool_sizes[0])) |
| #define | SZ_TINY(n) |
| #define | SZ_FRAC(k) |
| #define | SZ_FREE ((uint8_t) 2u) |
| #define | SZ_FREE_M(d) |
| #define | SZ_FREE_P(d) |
| #define | SZ_HUGE ((uint8_t) 3u) |
| #define | PS_1 0 |
| #define | PS_16 2 |
| #define | PS_32 4 |
| #define | PS_64 6 |
| #define | PS_128 8 |
| #define | PS_256 11 |
| #define | PS_512 14 |
| #define | PS_1024 16 |
| #define | PS_1500 18 |
| #define | PS_32768 23 |
| #define | OPR(o, b, s) |
| #define | MSEED(a) |
Enumerations | |
| enum | fz_op { FZ_OP_ALLOC = 0 , FZ_OP_ALLOC_ALL , FZ_OP_TRY_ALLOC , FZ_OP_SQUEEZE , FZ_OP_REALLOC , FZ_OP_REALLOC_NEW , FZ_OP_DEALLOC , FZ_OP_RESET , FZ_OP_GET_FREE , FZ_OP_RESIZABLE , FZ_OP_VERIFY , FZ_OP_RECREATE , FZ_OP_COUNT } |
Functions | |
| static void | print_stats (void) |
| static void | fz_report (const char *op, const char *what) |
| static size_t | fz_round (size_t n) |
| static uint8_t | fz_pat (uint8_t tag, size_t idx) |
| static void | fz_fill (uint8_t *ptr, uint8_t tag, size_t from, size_t to) |
| static void | fz_verify (const uint8_t *ptr, size_t size, uint8_t tag, const char *op, const char *what) |
| static void | fz_verify_all (struct fz_pool *st, const char *op) |
| static void | fz_check_ptr (struct fz_pool *st, void *p, size_t size, const char *op) |
| static void | fz_check_invariants (struct fz_pool *st, const char *op) |
| static struct fz_block * | fz_add (struct fz_pool *st, void *ptr, size_t size, bool from_end) |
| static void | fz_del (struct fz_pool *st, struct fz_block *b) |
| static struct fz_block * | fz_pick (struct fz_pool *st, uint8_t sel, bool front_only) |
| static size_t | fz_size (uint8_t sel, size_t cap, size_t freem) |
| static void | fz_pool_close (struct fz_pool *st) |
| static bool | fz_pool_open (struct fz_pool *st, uint8_t sel) |
| static void | fz_op_alloc (struct fz_pool *st, const uint8_t *op, bool prefer_end) |
| static void | fz_op_alloc_all (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_try_alloc (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_squeeze (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_realloc (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_realloc_new (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_dealloc (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_reset (struct fz_pool *st, const uint8_t *op) |
| static void | fz_op_resizable (struct fz_pool *st, const uint8_t *op) |
| static void | fz_do_op (struct fz_pool *st, const uint8_t *op, bool prefer_end) |
| int | LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) |
| static uint8_t | gen_size_sel (struct fuzz_rng *rng) |
| static size_t | fuzz_generate (struct fuzz_rng *rng, uint8_t *buf, size_t cap) |
| static size_t | fuzz_seed_count (void) |
| static const uint8_t * | fuzz_seed_get (size_t idx, size_t *len) |
Variables | |
| static const size_t | fz_pool_sizes [] |
| static int | full_dealloc_enabled |
| static int | wrap_realloc_enabled |
| static int | known_bugs_read |
| static unsigned long | stat_ops |
| static unsigned long | stat_alloc_ok |
| static unsigned long | stat_alloc_fail |
| static unsigned long | stat_realloc_moved |
| static unsigned long | stat_resets |
| static const uint8_t | gen_ops [] |
| static const uint8_t | seed_grow_shrink [] |
| static const uint8_t | seed_two_blocks_realloc [] |
| static const uint8_t | seed_from_end [] |
| static const uint8_t | seed_fill_exactly [] |
| static const uint8_t | seed_squeeze [] |
| static const uint8_t | seed_squeeze_small [] |
| static const uint8_t | seed_reset_keep [] |
| static const uint8_t | seed_reset_full [] |
| static const uint8_t | seed_boundary [] |
| static const uint8_t | seed_wrap [] |
| static const uint8_t | seed_tiny_pool [] |
| static const uint8_t | seed_zero_sizes [] |
| static const uint8_t | seed_many_small [] |
| static const uint8_t | seed_recreate [] |
| static const uint8_t | seed_connection_cycle [] |
| static const uint8_t | seed_dealloc_end_full [] |
| static const uint8_t | seed_realloc_wrap [] |
| static const struct mp_seed | mp_seeds [] |
Direct in-process fuzzer for src/microhttpd/memorypool.c.
memorypool.c is the per-connection allocator: a bump allocator that hands out "normal" blocks from the start of the pool and small, never-reallocated blocks from its end, plus an in-place resize and a reset that moves one surviving block back to the beginning. Every request buffer, every header name and value of every connection lives in it, so a single mis-computed offset here is a cross-request information leak or a heap overflow – and one that ASAN alone cannot see, because the whole pool is one malloc()ed object. (It does see it in a build where MHD_ASAN_POISON_ACTIVE is defined, i.e. where sanitizer/asan_interface.h was found and memorypool.c poisons the unallocated parts of the pool itself. The harness works either way and knows the red zone size that mode adds between two blocks.)
The harness therefore keeps its own model of the pool and checks it against the allocator after every single operation:
Documented preconditions are respected, since violating them would only produce findings about the harness: blocks allocated "from the end" are never passed to MHD_pool_reallocate(), MHD_pool_reset() is never asked for more than the pool size nor for more copy_bytes than the kept block holds, and a block is only ever deallocated with the size it was allocated with.
Two open defects of memorypool.c are reachable and would otherwise make every run abort; each is gated behind an environment variable, documented in full at full_dealloc_enabled and wrap_realloc_enabled below and in README section 6.1, with a byte-exact reproducer in the built-in seed corpus. Nothing else is gated.
Input format: byte 0 pool size selector (index into fz_pool_sizes[]) byte 1 flags 0x01 verify every live block after every operation 0x02 prefer allocating "from the end" rest unused byte 2.. a stream of 3-byte operation records [0] opcode (see enum fz_op) [1] block selector / auxiliary nibbles [2] size selector (see fz_size())
Definition in file fuzz_memorypool.c.
| #define FUZZ_HARNESS_NAME "fuzz_memorypool" |
Definition at line 88 of file fuzz_memorypool.c.
Referenced by print_stats().
| #define FZ_ALIGN_SIZE (2 * sizeof (void *)) |
Alignment of every block the pool hands out; memorypool.c aligns to two words "as GNU libc does".
Definition at line 101 of file fuzz_memorypool.c.
Referenced by fz_check_ptr(), fz_op_realloc(), and fz_round().
| #define FZ_MAX_BLOCKS 24 |
Maximum number of live allocations the model tracks. An operation that would exceed this is skipped, so the model never loses a block.
Definition at line 118 of file fuzz_memorypool.c.
Referenced by fz_op_alloc(), fz_op_alloc_all(), fz_op_realloc_new(), fz_op_squeeze(), and fz_op_try_alloc().
| #define FZ_MAX_OPS 64 |
Maximum number of operations executed for one input.
Definition at line 123 of file fuzz_memorypool.c.
Referenced by fuzz_generate(), and LLVMFuzzerTestOneInput().
| #define FZ_NUM_POOL_SIZES (sizeof (fz_pool_sizes) / sizeof (fz_pool_sizes[0])) |
Definition at line 150 of file fuzz_memorypool.c.
Referenced by fuzz_generate(), and fz_pool_open().
| #define FZ_PAT_MAX 96 |
Number of bytes of each allocation that carry the check pattern. Bounding this keeps the harness fast; the interesting bugs of a bump allocator are all at the start of a block or at its (ASAN-guarded) end.
Definition at line 131 of file fuzz_memorypool.c.
Referenced by fz_fill(), and fz_verify().
| #define FZ_RED_ZONE_SIZE ((size_t) 0) |
Size of the red zone memorypool.c keeps between two blocks. It only exists in a build with user memory poisoning, i.e. when the pool itself is instrumented; without it the pool is packed tight.
Definition at line 111 of file fuzz_memorypool.c.
Referenced by fz_pool_open().
| #define MSEED | ( | a | ) |
Definition at line 1577 of file fuzz_memorypool.c.
| #define OPR | ( | o, | |
| b, | |||
| s ) |
Definition at line 1385 of file fuzz_memorypool.c.
| #define PS_1 0 |
Definition at line 1374 of file fuzz_memorypool.c.
| #define PS_1024 16 |
Definition at line 1381 of file fuzz_memorypool.c.
| #define PS_128 8 |
Definition at line 1378 of file fuzz_memorypool.c.
| #define PS_1500 18 |
Definition at line 1382 of file fuzz_memorypool.c.
| #define PS_16 2 |
Definition at line 1375 of file fuzz_memorypool.c.
| #define PS_256 11 |
Definition at line 1379 of file fuzz_memorypool.c.
| #define PS_32 4 |
Definition at line 1376 of file fuzz_memorypool.c.
| #define PS_32768 23 |
Definition at line 1383 of file fuzz_memorypool.c.
| #define PS_512 14 |
Definition at line 1380 of file fuzz_memorypool.c.
| #define PS_64 6 |
Definition at line 1377 of file fuzz_memorypool.c.
| #define SZ_FRAC | ( | k | ) |
Definition at line 1367 of file fuzz_memorypool.c.
| #define SZ_FREE ((uint8_t) 2u) |
Definition at line 1368 of file fuzz_memorypool.c.
| #define SZ_FREE_M | ( | d | ) |
Definition at line 1369 of file fuzz_memorypool.c.
| #define SZ_FREE_P | ( | d | ) |
Definition at line 1370 of file fuzz_memorypool.c.
| #define SZ_HUGE ((uint8_t) 3u) |
Definition at line 1371 of file fuzz_memorypool.c.
| #define SZ_TINY | ( | n | ) |
Definition at line 1366 of file fuzz_memorypool.c.
| enum fz_op |
| Enumerator | |
|---|---|
| FZ_OP_ALLOC | |
| FZ_OP_ALLOC_ALL | allocate exactly MHD_pool_get_free() bytes |
| FZ_OP_TRY_ALLOC | |
| FZ_OP_SQUEEZE | try_alloc + shrink + retry |
| FZ_OP_REALLOC | MHD_pool_reallocate() of a live block |
| FZ_OP_REALLOC_NEW | MHD_pool_reallocate() with old == NULL |
| FZ_OP_DEALLOC | |
| FZ_OP_RESET | |
| FZ_OP_GET_FREE | |
| FZ_OP_RESIZABLE | |
| FZ_OP_VERIFY | re-check every live block |
| FZ_OP_RECREATE | |
| FZ_OP_COUNT | |
Definition at line 154 of file fuzz_memorypool.c.
|
static |
Definition at line 1323 of file fuzz_memorypool.c.
References fuzz_below(), fuzz_byte(), fuzz_chance(), FZ_MAX_OPS, FZ_NUM_POOL_SIZES, gen_ops, and gen_size_sel().

|
static |
Definition at line 1601 of file fuzz_memorypool.c.
References mp_seeds.
|
static |
Definition at line 1608 of file fuzz_memorypool.c.
References mp_seeds.
|
static |
Definition at line 527 of file fuzz_memorypool.c.
References fz_fill().
Referenced by fz_op_alloc(), fz_op_alloc_all(), fz_op_realloc_new(), fz_op_reset(), fz_op_squeeze(), and fz_op_try_alloc().


|
static |
Invariants that must hold after every single operation.
Definition at line 503 of file fuzz_memorypool.c.
References fz_report(), fz_verify_all(), and MHD_pool_get_free().
Referenced by fz_do_op().


|
static |
Check a pointer the pool just returned: inside the pool, aligned, and not overlapping any block that is still live. The caller has already removed the block being replaced (if any) from the model.
Definition at line 460 of file fuzz_memorypool.c.
References FZ_ALIGN_SIZE, and fz_report().
Referenced by fz_op_alloc(), fz_op_alloc_all(), fz_op_realloc(), fz_op_realloc_new(), fz_op_reset(), fz_op_squeeze(), and fz_op_try_alloc().


|
static |
Definition at line 544 of file fuzz_memorypool.c.
Referenced by fz_op_dealloc(), and fz_op_realloc().

|
static |
Definition at line 1160 of file fuzz_memorypool.c.
References fz_check_invariants(), FZ_OP_ALLOC, fz_op_alloc(), FZ_OP_ALLOC_ALL, fz_op_alloc_all(), FZ_OP_COUNT, FZ_OP_DEALLOC, fz_op_dealloc(), FZ_OP_GET_FREE, FZ_OP_REALLOC, fz_op_realloc(), FZ_OP_REALLOC_NEW, fz_op_realloc_new(), FZ_OP_RECREATE, FZ_OP_RESET, fz_op_reset(), FZ_OP_RESIZABLE, fz_op_resizable(), FZ_OP_SQUEEZE, fz_op_squeeze(), FZ_OP_TRY_ALLOC, fz_op_try_alloc(), FZ_OP_VERIFY, fz_pool_close(), fz_pool_open(), fz_verify_all(), and stat_ops.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Write the check pattern into ptr[from..to).
Definition at line 392 of file fuzz_memorypool.c.
References fz_pat(), and FZ_PAT_MAX.
Referenced by fz_add(), and fz_op_realloc().


|
static |
MHD_pool_allocate(), from the front or from the end.
Definition at line 674 of file fuzz_memorypool.c.
References fz_add(), fz_check_ptr(), FZ_MAX_BLOCKS, fz_report(), fz_round(), fz_size(), MHD_pool_allocate(), MHD_pool_get_free(), NULL, stat_alloc_fail, and stat_alloc_ok.
Referenced by fz_do_op().


|
static |
Allocate exactly MHD_pool_get_free() bytes. response.c:2203 does this and dereferences the result without a NULL check, so it must always succeed, and it must leave the pool without any free space.
Definition at line 722 of file fuzz_memorypool.c.
References fz_add(), fz_check_ptr(), FZ_MAX_BLOCKS, fz_report(), MHD_pool_allocate(), MHD_pool_get_free(), NULL, stat_alloc_fail, and stat_alloc_ok.
Referenced by fz_do_op().


|
static |
MHD_pool_deallocate() of a live block, or of NULL ("the NULL is tolerated"). A block is always deallocated with the size it currently has: memorypool.c asserts that the block lies inside the allocated area, and splitting a block is explicitly disallowed.
Definition at line 1013 of file fuzz_memorypool.c.
References full_dealloc_enabled, fz_del(), fz_pick(), fz_report(), fz_verify(), MHD_pool_deallocate(), MHD_pool_get_free(), and NULL.
Referenced by fz_do_op().


|
static |
MHD_pool_reallocate() of a live block that was allocated from the front. Blocks allocated "from the end" are excluded: memorypool.c documents ("Blocks 'from the end' must not be reallocated") and asserts that.
Definition at line 900 of file fuzz_memorypool.c.
References FZ_ALIGN_SIZE, fz_check_ptr(), fz_del(), fz_fill(), fz_pick(), fz_report(), fz_size(), fz_verify(), MHD_pool_get_free(), MHD_pool_is_resizable_inplace(), MHD_pool_reallocate(), NULL, SIZE_MAX, stat_realloc_moved, and wrap_realloc_enabled.
Referenced by fz_do_op().


|
static |
MHD_pool_reallocate() with old == NULL, which is the documented way to obtain a fresh relocatable block (connection.c:2121 uses it for the very first write buffer).
Definition at line 975 of file fuzz_memorypool.c.
References fz_add(), fz_check_ptr(), FZ_MAX_BLOCKS, fz_report(), fz_round(), fz_size(), MHD_pool_get_free(), MHD_pool_reallocate(), NULL, stat_alloc_fail, and stat_alloc_ok.
Referenced by fz_do_op().


|
static |
MHD_pool_reset(). Preconditions: copy_bytes <= new_size, new_size <= size of the pool, and the kept block must really hold copy_bytes bytes.
Definition at line 1071 of file fuzz_memorypool.c.
References fz_add(), fz_check_ptr(), fz_pick(), fz_report(), fz_size(), fz_verify(), MHD_pool_get_free(), MHD_pool_reset(), NULL, and stat_resets.
Referenced by fz_do_op().


|
static |
MHD_pool_is_resizable_inplace() on a live block, or on NULL.
Definition at line 1120 of file fuzz_memorypool.c.
References fz_pick(), fz_report(), MHD_pool_is_resizable_inplace(), MHD_pool_reallocate(), and NULL.
Referenced by fz_do_op().


|
static |
The logic of MHD_connection_alloc_memory_() (connection.c:706): when MHD_pool_try_alloc() fails it names the number of bytes that have to be freed in the relocatable area; freeing exactly that many bytes by shrinking a block that is resizable in-place must make the very same allocation succeed. If it does not, MHD returns "out of memory" for a request it has the memory for.
Definition at line 820 of file fuzz_memorypool.c.
References fz_add(), fz_check_ptr(), FZ_MAX_BLOCKS, fz_report(), fz_size(), fz_verify(), MHD_pool_get_free(), MHD_pool_is_resizable_inplace(), MHD_pool_reallocate(), MHD_pool_try_alloc(), NULL, and SIZE_MAX.
Referenced by fz_do_op().


|
static |
MHD_pool_try_alloc(). Checks the contract of required_bytes.
Definition at line 757 of file fuzz_memorypool.c.
References fz_add(), fz_check_ptr(), FZ_MAX_BLOCKS, fz_report(), fz_round(), fz_size(), MHD_pool_get_free(), MHD_pool_try_alloc(), NULL, SIZE_MAX, stat_alloc_fail, and stat_alloc_ok.
Referenced by fz_do_op().


|
static |
Byte idx of the check pattern of a block with seed tag.
Definition at line 379 of file fuzz_memorypool.c.
Referenced by fz_fill(), and fz_verify().

|
static |
Pick a live block.
| st | the model |
| sel | selector byte |
| front_only | only consider blocks that may be reallocated |
Definition at line 560 of file fuzz_memorypool.c.
References NULL.
Referenced by fz_op_dealloc(), fz_op_realloc(), fz_op_reset(), and fz_op_resizable().

|
static |
Definition at line 622 of file fuzz_memorypool.c.
References MHD_pool_destroy(), and NULL.
Referenced by fz_do_op(), fz_pool_open(), and LLVMFuzzerTestOneInput().


|
static |
Create a pool and learn its base address and its exact size.
Definition at line 636 of file fuzz_memorypool.c.
References FZ_NUM_POOL_SIZES, fz_pool_close(), fz_pool_sizes, FZ_RED_ZONE_SIZE, fz_report(), fz_round(), MHD_pool_create(), MHD_pool_get_free(), MHD_pool_reset(), and NULL.
Referenced by fz_do_op(), and LLVMFuzzerTestOneInput().


|
static |
Report a finding, prefixed with the name of the operation that was running.
Definition at line 353 of file fuzz_memorypool.c.
References fuzz_report_finding().
Referenced by fz_check_invariants(), fz_check_ptr(), fz_op_alloc(), fz_op_alloc_all(), fz_op_dealloc(), fz_op_realloc(), fz_op_realloc_new(), fz_op_reset(), fz_op_resizable(), fz_op_squeeze(), fz_op_try_alloc(), fz_pool_open(), and fz_verify().


|
static |
The ROUND_TO_ALIGN() of memorypool.c, wrap-around included: a size that is too close to SIZE_MAX rounds to 0, which is how the allocator detects it.
Definition at line 369 of file fuzz_memorypool.c.
References FZ_ALIGN_SIZE.
Referenced by fz_op_alloc(), fz_op_realloc_new(), fz_op_try_alloc(), and fz_pool_open().

|
static |
Turn a selector byte into a size. The four classes matter: tiny sizes are what headers use, fractions of the pool are what the request buffers use, sizes around the currently free amount are where the off-by-one-block bugs live, and sizes close to SIZE_MAX exercise the "value wrap" guards of the allocator.
Definition at line 598 of file fuzz_memorypool.c.
References SIZE_MAX.
Referenced by fz_op_alloc(), fz_op_realloc(), fz_op_realloc_new(), fz_op_reset(), fz_op_squeeze(), and fz_op_try_alloc().

|
static |
Verify that the first bytes of ptr still carry the pattern of tag. The expected bytes are built in an exactly sized malloc()ed buffer, so that a comparison that runs off either end is caught by ASAN rather than silently passing.
Definition at line 413 of file fuzz_memorypool.c.
References fz_pat(), FZ_PAT_MAX, fz_report(), and NULL.
Referenced by fz_op_dealloc(), fz_op_realloc(), fz_op_reset(), fz_op_squeeze(), and fz_verify_all().


|
static |
Verify every live block.
Definition at line 440 of file fuzz_memorypool.c.
References fz_verify().
Referenced by fz_check_invariants(), fz_do_op(), and LLVMFuzzerTestOneInput().


|
static |
Size selector bytes that are worth trying often: the boundary cases (exactly the free space, one alignment unit more or less) and the value-wrap guards.
Definition at line 1298 of file fuzz_memorypool.c.
References fuzz_below().
Referenced by fuzz_generate().


| int LLVMFuzzerTestOneInput | ( | const uint8_t * | data, |
| size_t | size ) |
The fuzz target. Signature is the libFuzzer one on purpose, so that the very same harness can be linked with libFuzzer or AFL++ later.
< see queue_unprocessed_conn()
Definition at line 1217 of file fuzz_memorypool.c.
References data, full_dealloc_enabled, fz_do_op(), FZ_MAX_OPS, fz_pool_close(), fz_pool_open(), fz_verify_all(), known_bugs_read, MHD_init_mem_pools_(), NULL, print_stats(), and wrap_realloc_enabled.

|
static |
Definition at line 335 of file fuzz_memorypool.c.
References FUZZ_HARNESS_NAME, fuzz_verbose, stat_alloc_fail, stat_alloc_ok, stat_ops, stat_realloc_moved, and stat_resets.
Referenced by LLVMFuzzerTestOneInput().

|
static |
F1 – MHD_pool_deallocate() of a "from the end" block of a pool that is exactly full. This is a live defect in memorypool.c and is therefore off by default; set MHD_FUZZ_POOL_FULL_DEALLOC=1 to reach it (seed fuzz_memorypool-15.bin is the byte-exact reproducer).
MHD_pool_deallocate() decides whether a block came from the front or from the end with
if (block_offset <= pool->pos) memorypool.c:666
which is ambiguous when pool->pos == pool->end, i.e. when the pool has no free space left: a "from the end" block then starts exactly at pool->pos and is treated as a front block. With –enable-asserts
mhd_assert ((block_offset != pool->pos) || (block_size == 0)); :655 mhd_assert (alg_end <= pool->pos); :671
both fail, i.e. the process aborts; without them the block is simply not returned to the pool (pool->end is left alone), so the memory is lost until the pool is reset or destroyed. Reproducer:
p = MHD_pool_create (128); e = MHD_pool_allocate (p, 16, true); (void) MHD_pool_allocate (p, MHD_pool_get_free (p), false); MHD_pool_deallocate (p, e, 16); <- abort / 16 bytes lost
Nothing in memorypool.h forbids this; MHD_pool_deallocate() documents only that "the NULL is tolerated" and has an explicit branch for blocks allocated from the end. MHD's own call sites never hit it, because the three MHD_pool_deallocate() calls in connection.c and response.c all pass the read or the write buffer, which are front allocations – so this is a latent defect of a supported branch of the API rather than something reachable from the network today. A dispatch on block_offset < pool->end would resolve the ambiguity.
Definition at line 270 of file fuzz_memorypool.c.
Referenced by fz_op_dealloc(), and LLVMFuzzerTestOneInput().
|
static |
Pool sizes to choose from. MHD uses 128..32768 in practice (the default is 32768 and MHD_OPTION_CONNECTION_MEMORY_LIMIT can set anything); everything at or below 32k is malloc()ed by MHD_pool_create(), so the harness knows the exact usable size and ASAN's redzone sits right behind the pool. The last two entries are larger than that on purpose: they take the mmap() path of MHD_pool_create() and the munmap() path of MHD_pool_destroy(). Both are powers of two and therefore a multiple of any page size, so the resulting pool is exactly that large either way and the check below stays exact.
Definition at line 145 of file fuzz_memorypool.c.
Referenced by fz_pool_open().
|
static |
Opcodes, weighted: the allocating operations and the reallocation are what move the pool's internal offsets around, so they get most of the probability mass, while the read-only queries and the destructive reset and re-create are rarer.
Definition at line 1276 of file fuzz_memorypool.c.
Referenced by fuzz_generate().
|
static |
Definition at line 324 of file fuzz_memorypool.c.
Referenced by LLVMFuzzerTestOneInput().
|
static |
Definition at line 1579 of file fuzz_memorypool.c.
Referenced by fuzz_seed_count(), and fuzz_seed_get().
|
static |
Definition at line 1463 of file fuzz_memorypool.c.
|
static |
Definition at line 1533 of file fuzz_memorypool.c.
|
static |
Definition at line 1552 of file fuzz_memorypool.c.
|
static |
Definition at line 1419 of file fuzz_memorypool.c.
|
static |
Definition at line 1409 of file fuzz_memorypool.c.
|
static |
Definition at line 1387 of file fuzz_memorypool.c.
|
static |
Definition at line 1503 of file fuzz_memorypool.c.
|
static |
Definition at line 1564 of file fuzz_memorypool.c.
|
static |
Definition at line 1518 of file fuzz_memorypool.c.
|
static |
Definition at line 1455 of file fuzz_memorypool.c.
|
static |
Definition at line 1445 of file fuzz_memorypool.c.
|
static |
Definition at line 1428 of file fuzz_memorypool.c.
|
static |
Definition at line 1437 of file fuzz_memorypool.c.
|
static |
Definition at line 1484 of file fuzz_memorypool.c.
|
static |
Definition at line 1398 of file fuzz_memorypool.c.
|
static |
Definition at line 1473 of file fuzz_memorypool.c.
|
static |
Definition at line 1493 of file fuzz_memorypool.c.
|
static |
Definition at line 329 of file fuzz_memorypool.c.
Referenced by fz_op_alloc(), fz_op_alloc_all(), fz_op_realloc_new(), fz_op_try_alloc(), and print_stats().
|
static |
Definition at line 328 of file fuzz_memorypool.c.
Referenced by fz_op_alloc(), fz_op_alloc_all(), fz_op_realloc_new(), fz_op_try_alloc(), and print_stats().
|
static |
Statistics, printed at exit with –verbose.
Definition at line 327 of file fuzz_memorypool.c.
Referenced by fz_do_op(), and print_stats().
|
static |
Definition at line 330 of file fuzz_memorypool.c.
Referenced by fz_op_realloc(), and print_stats().
|
static |
Definition at line 331 of file fuzz_memorypool.c.
Referenced by fz_op_reset(), and print_stats().
|
static |
F2 – MHD_pool_reallocate() reports success for a new_size that wrapped. Also a live defect, off by default; set MHD_FUZZ_POOL_WRAP_REALLOC=1 to reach it (seed fuzz_memorypool-16.bin is the byte-exact reproducer).
Every other entry point of memorypool.c detects a size that is too close to SIZE_MAX explicitly:
asize = ROUND_TO_ALIGN_PLUS_RED_ZONE (size); if ( (0 == asize) && (0 != size) ) return NULL; // "size too close to SIZE_MAX"
– MHD_pool_allocate(), MHD_pool_try_alloc() and the "need to allocate a new block" tail of MHD_pool_reallocate() all do it. The in-place branch of MHD_pool_reallocate() instead relies on
const size_t new_apos =
ROUND_TO_ALIGN_PLUS_RED_ZONE (old_offset + new_size);
if ( (new_apos > pool->end) ||
(new_apos < pool->pos) ) // "Value wrap"
return NULL;
which does not catch the wrap when the wrapped value happens to land on pool->pos. For a zero-length block sitting at the front boundary (old_size == 0, old_offset == pool->pos, which is exactly what MHD_pool_reset (pool, NULL, 0, 0) returns – see connection.c:3021 – or MHD_pool_allocate (pool, 0, false)) and any new_size in [SIZE_MAX - 14, SIZE_MAX], old_offset + new_size wraps to old_offset - 1 - k, which rounds back up to exactly old_offset, i.e. to pool->pos: neither test fires, pool->pos is left alone and the function returns old, i.e. it reports success.
p = MHD_pool_create (1024); b = MHD_pool_reset (p, NULL, 0, 0); r = MHD_pool_reallocate (p, b, 0, SIZE_MAX - 4); // r == b, not NULL: the caller now believes it owns // SIZE_MAX - 4 bytes at the start of a 1024 byte pool, // while MHD_pool_get_free() still reports the full 1024.
The documented contract is "@return new address of the block, or NULL
if the pool cannot support @a new_size bytes", so this is a plain contract violation, and one that hands the caller a buffer size the allocation does not have. No MHD call site can reach it today: every new_size MHD passes is derived from the pool size (connection.c:1636, 2031, 2082, 2121, 2170, 6935), so it is a latent defect rather than something reachable from the network. Checking the addition itself, e.g. if (new_size > pool->size - old_offset) return NULL;, would close it.
Definition at line 322 of file fuzz_memorypool.c.
Referenced by fz_op_realloc(), and LLVMFuzzerTestOneInput().