|
GNU libmicrohttpd 1.0.9
|
In-process fuzzer for MHD's external event loop and for the scheduling of the connection life cycle. More...
#include "fuzz_common.h"#include <microhttpd.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/select.h>#include <limits.h>
Go to the source code of this file.
Macros | |
| #define | FUZZ_HARNESS_NAME "fuzz_eventloop" |
| #define | MAX_CONNS 8 |
| #define | MAX_OPS 400 |
| #define | BIG_BODY_LEN 131072 |
| #define | DRAIN_BUF 4096 |
| #define | MAX_LIVE (MAX_CONNS + 4) |
| #define | OPB(o, a) |
Enumerations | |
| enum | op { OP_SEND_FRAG = 0 , OP_SEND_RAW = 1 , OP_FDSET = 2 , OP_RUN = 3 , OP_TIMEOUT = 4 , OP_CLOCK = 5 , OP_SUSPEND = 6 , OP_RESUME = 7 , OP_NEWCONN = 8 , OP_CLOSECONN = 9 , OP_SWITCH = 10 , OP_QUIESCE = 11 , OP_DRAIN = 12 , OP_CONNOPT = 13 , OP_INFO = 14 , OP_POLL = 15 } |
Functions | |
| static void | print_stats (void) |
| static void | panic_cb (void *cls, const char *file, unsigned int line, const char *reason) |
| static int | slot_of (const struct MHD_Connection *c) |
| static void | notify_conn_cb (void *cls, struct MHD_Connection *connection, void **socket_context, enum MHD_ConnectionNotificationCode toe) |
| static int | mhd_thinks_suspended (unsigned int i) |
| static void | do_suspend (unsigned int i) |
| static void | do_resume (unsigned int i) |
| static int | resume_all (void) |
| static int | scan_live_timeouts (uint64_t *max_ms) |
| static ssize_t | crc_cb (void *cls, uint64_t pos, char *buf, size_t max) |
| static void | crc_free (void *cls) |
| static struct MHD_Response * | make_response (void) |
| static enum MHD_Result | ahc (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **req_cls) |
| static void | check_timeouts (struct MHD_Daemon *d) |
| static void | check_fdsets (unsigned int setsize, MHD_socket max_fd, int had_max, int with_es) |
| static void | op_fdset (struct MHD_Daemon *d, unsigned int var) |
| static void | op_poll (void) |
| static void | drain_conn (unsigned int i) |
| static void | drain_all (void) |
| static void | op_run (struct MHD_Daemon *d, unsigned int var, unsigned int flavour) |
| static int | new_connection (struct MHD_Daemon *d) |
| static int | queue_unprocessed_conn (struct MHD_Daemon *d) |
| static void | close_conn (unsigned int i, int graceful) |
| static void | send_bytes (unsigned int i, const void *buf, size_t len) |
| static void | wait_for_expiry (struct MHD_Daemon *d) |
| static void | op_quiesce (struct MHD_Daemon *d) |
| static void | op_info (struct MHD_Daemon *d, unsigned int arg) |
| static void | op_connopt (unsigned int i, unsigned int val) |
| int | LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) |
| static void | sb_byte (struct sbuf *b, uint8_t v) |
| static void | sb_op (struct sbuf *b, unsigned int opc, unsigned int arg) |
| static unsigned int | gen_frag (struct fuzz_rng *rng) |
| static void | gen_loop_round (struct fuzz_rng *rng, struct sbuf *b) |
| 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 struct el_cfg | cfg |
| static const size_t | mem_limit_tbl [] = { 0, 256, 1024, 4096 } |
| static const unsigned int | timeout_tbl [] = { 1, 2, 0, 1 } |
| static const unsigned int | setsize_tbl [] |
| static int | csock [MAX_CONNS] |
| static unsigned int | nconns |
| static unsigned int | cur_conn |
| static struct live_conn | lives [MAX_LIVE] |
| static struct MHD_Daemon * | cur_daemon |
| static int | tearing_down |
| static MHD_socket | quiesced_fd = MHD_INVALID_SOCKET |
| static uint64_t | clk_ms |
| static uint64_t | deadline_ms |
| static int | deadline_valid |
| static fd_set | g_rs |
| static fd_set | g_ws |
| static fd_set | g_es |
| static MHD_socket | g_max_fd = MHD_INVALID_SOCKET |
| static unsigned int | g_setsize = (unsigned int) FD_SETSIZE |
| static int | g_have_sets |
| static char | big_body [BIG_BODY_LEN] |
| static int | big_body_ready |
| static int | expiry_budget = 2 |
| static int | expiry_budget_read |
| static unsigned long | stat_daemons |
| static unsigned long | stat_handler_calls |
| static unsigned long | stat_fdset_v1 |
| static unsigned long | stat_fdset_v2 |
| static unsigned long | stat_rfs_v1 |
| static unsigned long | stat_rfs_v2 |
| static unsigned long | stat_run |
| static unsigned long | stat_run_wait |
| static unsigned long | stat_timeouts |
| static unsigned long | stat_quiesce |
| static unsigned long | stat_suspend |
| static unsigned long | stat_resume |
| static unsigned long | stat_expiry_waits |
| static unsigned long | stat_queued_at_stop |
| static int | stats_registered |
| static const char *const | frag_tbl [16] |
| static const unsigned char | gen_frag_bias [] |
| static const struct seed_def | seeds [] |
| static uint8_t | seed_render_buf [64] |
In-process fuzzer for MHD's external event loop and for the scheduling of the connection life cycle.
fuzz_request.c already touches these entry points, but only as a side channel: it picks one event-loop mode per iteration and then always pumps in the same rhythm. The bugs this harness is after are in the scheduling – what MHD does when the application polls at adversarial times, ignores the timeout it was given, calls MHD_run_from_select() with descriptor sets that do not match what MHD asked for, or suspends/resumes connections across those calls.
The input is therefore not an HTTP request but a schedule: a short configuration block followed by a program of one-byte opcodes that is interpreted against a live struct MHD_Daemon with up to MAX_CONNS socketpair connections. Request bytes enter the program through two of those opcodes (a fragment table and a raw literal), so the parser is still driven, just not fuzzed.
byte 0 daemon configuration bits 0-1 MHD_OPTION_CONNECTION_TIMEOUT selector, index into {1, 2, 0, 1} seconds bit 2 give the daemon a real listening socket (port 0) instead of MHD_USE_NO_LISTEN_SOCKET, so that MHD_quiesce_daemon() has something to do and the listen FD shows up in the descriptor sets bit 3 pass MHD_OPTION_APP_FD_SETSIZE bits 4-5 MHD_OPTION_CONNECTION_MEMORY_LIMIT selector, index into {default, 256, 1024, 4096} bit 6 MHD_OPTION_CONNECTION_LIMIT = 2, so that MHD_add_connection() starts failing bit 7 shrink SO_SNDBUF/SO_RCVBUF of the socketpair, so that responses do not fit and connections stay blocked on write byte 1 access-handler behaviour bits 0-1 response kind: 0 small static buffer, 1 chunked callback (MHD_SIZE_UNKNOWN), 2 large (128 KiB) static buffer, 3 empty bit 2 answer 500 instead of 200 bit 3 suspend in the handler and leave it parked bit 4 suspend and resume immediately in the handler bit 5 call MHD_set_connection_option() from the handler bit 6 call MHD_get_connection_info() from the handler bit 7 drain the client side after every run byte 2 event-loop defaults bits 0-2 default MHD_get_fdset*() variant bits 3-4 default run entry point bit 5 honour the timeout MHD returns bit 6 query the timeouts after every run bit 7 MHD_quiesce_daemon() before stopping byte 3 schedule knobs bits 0-1 number of connections opened up front (1-4) bit 2 run the timeout oracle after every operation bit 3 allow a real-time wait for a connection timeout to expire (globally budgeted, see below) bit 4 queue one more connection at the very end and stop the daemon without running the loop again, so that MHD has to dispose of a connection it never started (see queue_unprocessed_conn()) bits 5-7 unused byte 4 artificial-clock step base byte 5. the operation program. Each operation is one byte, (opcode << 4) | argument; see enum op below. OP_SEND_RAW is the only one with an operand: a length byte followed by that many payload bytes.
An input shorter than five bytes is rejected: the configuration block is mandatory and an input that short carries no program either.
Beyond ASAN/UBSAN and the MHD_set_panic_func() tripwire (any MHD_PANIC() reached this way is a finding, including the "MHD_stop_daemon() called while we have suspended connections" one that answers the "the daemon must always be stoppable" requirement):
a) the four timeout accessors must agree. MHD_get_timeout(), MHD_get_timeout64(), MHD_get_timeout64s() and MHD_get_timeout_i() read the same state, so either all of them report a timeout or none of them does. Their values are read in sequence, so the clock may advance between two of them and the value may only decrease; connection_get_wait() has a documented 100 ms floor for the "exact match" case, hence the 100 ms slack.
b) a reported timeout must never exceed the largest connection timeout in effect. MHD only ever derives it from last_activity + connection_timeout_ms, so a larger value would mean the deadline is somewhere the application cannot reach.
c) MHD must never ask the application to wait forever while it has a live, not-suspended connection with a non-zero timeout: that is precisely the "timeout in the past" situation, i.e. a connection that can never be reaped. Live connections are tracked through MHD_OPTION_NOTIFY_CONNECTION, which brackets exactly the interval in which MHD owns the connection object.
Both inputs of (b) and (c) – whether a connection is suspended and what its timeout is – are read back from MHD rather than modelled, because both diverge from what the application asked for: MHD_set_connection_option() silently does nothing while a connection is suspended. A harness that models them ends up reporting findings against its own model.
d) MHD_get_fdset*() must not set a descriptor at or above the FD_SETSIZE limit it was given, *max_fd must be at least as large as every descriptor that was added, and *max_fd itself must be one of them.
e) after MHD_quiesce_daemon() the listening socket must be gone from the descriptor sets.
Two contract rules the harness has to respect (violating either makes MHD abort on a schedule that is perfectly legal, so the harness would only be finding its own bugs):
MHD_suspend_connection() is additionally only called when MHD does not already consider the connection suspended, unless a resume of it is still pending – that is the one case internal_suspend_connection_() handles itself (it cancels the resume), and the harness mirrors the resulting state. Calling it on an already-suspended connection would unlink it from a list it is not on.
One more trap: with MHD_USE_ITC – which MHD_ALLOW_SUSPEND_RESUME implies, so this harness always has it – MHD_add_connection() only queues the socket, and the struct MHD_Connection is created later, from inside a run. There is therefore no moment at which the application could pair its own socket up with the connection object, and the registry of live connections has to be built purely from MHD_OPTION_NOTIFY_CONNECTION. This is why the client sockets (csock) and the connections (lives) are two separate arrays.
Note on MHD_get_timeout_expiration(): no such function exists in the MHD 1.x API. The four accessors above are the complete family; the absolute-deadline form is a MHD 2.x addition.
Definition in file fuzz_eventloop.c.
| #define BIG_BODY_LEN 131072 |
Size of the "large response" body.
Definition at line 188 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and make_response().
| #define DRAIN_BUF 4096 |
Bytes read back from the daemon are counted, never inspected.
Definition at line 191 of file fuzz_eventloop.c.
Referenced by drain_conn().
| #define FUZZ_HARNESS_NAME "fuzz_eventloop" |
Definition at line 172 of file fuzz_eventloop.c.
Referenced by print_stats().
| #define MAX_CONNS 8 |
Largest number of connections a single iteration may have open.
Definition at line 182 of file fuzz_eventloop.c.
Referenced by close_conn(), drain_all(), drain_conn(), LLVMFuzzerTestOneInput(), new_connection(), and send_bytes().
| #define MAX_LIVE (MAX_CONNS + 4) |
A few more slots than connections, so the registry cannot overflow.
Definition at line 285 of file fuzz_eventloop.c.
Referenced by do_resume(), do_suspend(), LLVMFuzzerTestOneInput(), notify_conn_cb(), op_connopt(), op_info(), resume_all(), scan_live_timeouts(), and slot_of().
| #define MAX_OPS 400 |
Upper bound on the number of operations interpreted per iteration.
Definition at line 185 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().
| #define OPB | ( | o, | |
| a ) |
Definition at line 1909 of file fuzz_eventloop.c.
| enum op |
| Enumerator | |
|---|---|
| OP_SEND_FRAG | |
| OP_SEND_RAW | |
| OP_FDSET | |
| OP_RUN | |
| OP_TIMEOUT | |
| OP_CLOCK | |
| OP_SUSPEND | |
| OP_RESUME | |
| OP_NEWCONN | |
| OP_CLOSECONN | |
| OP_SWITCH | |
| OP_QUIESCE | |
| OP_DRAIN | |
| OP_CONNOPT | |
| OP_INFO | |
| OP_POLL | |
Definition at line 1274 of file fuzz_eventloop.c.
|
static |
Definition at line 655 of file fuzz_eventloop.c.
References cfg, MHD_ConnectionInfo::connect_fd, MHD_ConnectionInfo::connection_timeout, lives, make_response(), MHD_CONNECTION_INFO_CONNECTION_FD, MHD_CONNECTION_INFO_CONNECTION_TIMEOUT, MHD_CONNECTION_OPTION_TIMEOUT, MHD_destroy_response(), MHD_get_connection_info(), MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_OK, MHD_NO, MHD_queue_response(), MHD_resume_connection(), MHD_set_connection_option(), MHD_suspend_connection(), MHD_YES, NULL, slot_of(), stat_handler_calls, stat_resume, stat_suspend, and tearing_down.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Check the descriptor sets that the last MHD_get_fdset*() produced.
| setsize | the FD_SETSIZE limit that was passed to MHD |
| max_fd | the reported maximum, MHD_INVALID_SOCKET if none |
| had_max | whether a max_fd pointer was passed at all |
| with_es | whether an except set was passed |
Definition at line 844 of file fuzz_eventloop.c.
References fuzz_report_finding(), g_es, g_rs, g_ws, and MHD_INVALID_SOCKET.
Referenced by op_fdset().


|
static |
Query all four timeout accessors and cross-check them.
The values are read one after the other, so the monotonic clock may advance in between and a later reading may be smaller. It may never be larger, except for the 100 ms floor connection_get_wait() falls back to when the elapsed time exactly matches the timeout.
Definition at line 760 of file fuzz_eventloop.c.
References clk_ms, deadline_ms, deadline_valid, fuzz_report_finding(), MHD_get_timeout(), MHD_get_timeout64(), MHD_get_timeout64s(), MHD_get_timeout_i(), MHD_UNSIGNED_LONG_LONG, MHD_YES, scan_live_timeouts(), and stat_timeouts.
Referenced by LLVMFuzzerTestOneInput(), and op_run().


|
static |
Drop our end of connection i.
| graceful | non-zero to shut the write side down first (an orderly client close), zero to just close (an abrupt one, which MHD sees as a reset) |
Definition at line 1193 of file fuzz_eventloop.c.
References csock, and MAX_CONNS.
Referenced by LLVMFuzzerTestOneInput().

|
static |
Definition at line 590 of file fuzz_eventloop.c.
References MHD_CONTENT_READER_END_OF_STREAM.
Referenced by make_response().

|
static |
Definition at line 613 of file fuzz_eventloop.c.
Referenced by make_response().

|
static |
Definition at line 488 of file fuzz_eventloop.c.
References lives, MAX_LIVE, MHD_resume_connection(), NULL, and stat_resume.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Suspend slot i, if that is legal right now.
MHD_suspend_connection() unlinks the connection from the timeout and connection lists, so calling it on a connection MHD already has on the suspended list corrupts those lists. The one exception is a connection with a resume still pending: internal_suspend_connection_() detects that itself and merely cancels the resume, leaving the connection suspended – which is why susp is set in both branches.
Definition at line 471 of file fuzz_eventloop.c.
References lives, MAX_LIVE, MHD_suspend_connection(), mhd_thinks_suspended(), NULL, and stat_suspend.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Definition at line 1012 of file fuzz_eventloop.c.
References drain_conn(), and MAX_CONNS.
Referenced by LLVMFuzzerTestOneInput(), and op_run().


|
static |
Drain whatever the daemon has produced on slot i, so that a large response can make progress.
Definition at line 994 of file fuzz_eventloop.c.
References csock, DRAIN_BUF, and MAX_CONNS.
Referenced by drain_all(), and LLVMFuzzerTestOneInput().

|
static |
Definition at line 1775 of file fuzz_eventloop.c.
References fuzz_below(), fuzz_byte(), fuzz_chance(), gen_frag(), gen_loop_round(), OP_CLOCK, OP_CLOSECONN, OP_CONNOPT, OP_DRAIN, OP_INFO, OP_NEWCONN, OP_POLL, OP_QUIESCE, OP_RESUME, OP_RUN, OP_SEND_FRAG, OP_SEND_RAW, OP_SUSPEND, OP_SWITCH, OP_TIMEOUT, sb_byte(), and sb_op().

|
static |
Definition at line 2041 of file fuzz_eventloop.c.
References seeds.
|
static |
Definition at line 2048 of file fuzz_eventloop.c.
References seed_render_buf, and seeds.
|
static |
Definition at line 1739 of file fuzz_eventloop.c.
References fuzz_below(), fuzz_chance(), and gen_frag_bias.
Referenced by fuzz_generate().


|
static |
Emit "collect the descriptors, poll, run" – the shape a real external event loop has – with a randomly chosen variant of each step.
Definition at line 1753 of file fuzz_eventloop.c.
References fuzz_below(), fuzz_chance(), OP_FDSET, OP_POLL, OP_RUN, OP_TIMEOUT, and sb_op().
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 1398 of file fuzz_eventloop.c.
References ahc(), big_body, BIG_BODY_LEN, big_body_ready, cfg, check_timeouts(), clk_ms, close_conn(), csock, cur_conn, cur_daemon, data, deadline_ms, deadline_valid, do_resume(), do_suspend(), drain_all(), drain_conn(), expiry_budget, expiry_budget_read, frag_tbl, fuzz_ignore_sigpipe(), fuzz_verbose, g_have_sets, g_max_fd, g_setsize, lives, MAX_CONNS, MAX_LIVE, MAX_OPS, mem_limit_tbl, MHD_ALLOW_SUSPEND_RESUME, MHD_INVALID_SOCKET, MHD_OPTION_APP_FD_SETSIZE, MHD_OPTION_ARRAY, MHD_OPTION_CONNECTION_LIMIT, MHD_OPTION_CONNECTION_MEMORY_LIMIT, MHD_OPTION_CONNECTION_TIMEOUT, MHD_OPTION_END, MHD_OPTION_NOTIFY_CONNECTION, MHD_run(), MHD_set_panic_func(), MHD_start_daemon(), MHD_stop_daemon(), MHD_USE_ERROR_LOG, MHD_USE_NO_LISTEN_SOCKET, nconns, new_connection(), notify_conn_cb(), NULL, OP_CLOCK, OP_CLOSECONN, OP_CONNOPT, op_connopt(), OP_DRAIN, OP_FDSET, op_fdset(), OP_INFO, op_info(), OP_NEWCONN, op_poll(), OP_QUIESCE, op_quiesce(), OP_RESUME, OP_RUN, op_run(), OP_SEND_FRAG, OP_SEND_RAW, OP_SUSPEND, OP_SWITCH, OP_TIMEOUT, MHD_OptionItem::option, panic_cb(), print_stats(), MHD_OptionItem::ptr_value, queue_unprocessed_conn(), quiesced_fd, resume_all(), send_bytes(), stat_daemons, stats_registered, tearing_down, timeout_tbl, MHD_OptionItem::value, and wait_for_expiry().
|
static |
Definition at line 620 of file fuzz_eventloop.c.
References big_body, BIG_BODY_LEN, cfg, crc_cb(), crc_free(), MHD_create_response_empty(), MHD_create_response_from_buffer_static(), MHD_create_response_from_callback(), MHD_RF_NONE, MHD_SIZE_UNKNOWN, and NULL.
Referenced by ahc().


|
static |
Ask MHD whether it considers slot i suspended.
Definition at line 446 of file fuzz_eventloop.c.
References lives, MHD_CONNECTION_INFO_CONNECTION_SUSPENDED, MHD_get_connection_info(), MHD_YES, NULL, and MHD_ConnectionInfo::suspended.
Referenced by do_suspend().


|
static |
Definition at line 1099 of file fuzz_eventloop.c.
References cfg, csock, cur_conn, MAX_CONNS, MHD_add_connection(), MHD_YES, and nconns.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Definition at line 406 of file fuzz_eventloop.c.
References lives, MAX_LIVE, MHD_CONNECTION_NOTIFY_STARTED, NULL, and slot_of().
Referenced by LLVMFuzzerTestOneInput().


|
static |
Definition at line 1378 of file fuzz_eventloop.c.
References lives, MAX_LIVE, MHD_CONNECTION_OPTION_TIMEOUT, MHD_set_connection_option(), and NULL.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Collect the descriptor sets.
Variant 0 goes through the real v1 entry point. microhttpd.h also defines MHD_get_fdset as a macro forwarding to MHD_get_fdset2 with FD_SETSIZE, so the name has to be parenthesised or the v1 function is never reached at all. Same trick for MHD_run_from_select below.
Definition at line 911 of file fuzz_eventloop.c.
References cfg, check_fdsets(), fuzz_report_finding(), g_es, g_have_sets, g_max_fd, g_rs, g_setsize, g_ws, MHD_get_fdset, MHD_get_fdset2(), MHD_INVALID_SOCKET, NULL, quiesced_fd, setsize_tbl, stat_fdset_v1, and stat_fdset_v2.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Definition at line 1348 of file fuzz_eventloop.c.
References MHD_ConnectionInfo::daemon, MHD_DaemonInfo::flags, lives, MAX_LIVE, MHD_CONNECTION_INFO_CONNECTION_SUSPENDED, MHD_CONNECTION_INFO_DAEMON, MHD_DAEMON_INFO_CURRENT_CONNECTIONS, MHD_DAEMON_INFO_FLAGS, MHD_get_connection_info(), MHD_get_daemon_info(), NULL, MHD_DaemonInfo::num_connections, and MHD_ConnectionInfo::suspended.
Referenced by LLVMFuzzerTestOneInput().


|
static |
select() on the sets collected last, with a zero timeout.
The harness is single threaded and everything MHD could be waiting for has already been written into the socketpairs, so blocking would only burn wall clock; select() is called purely to fill in the readiness.
Definition at line 976 of file fuzz_eventloop.c.
References g_es, g_have_sets, g_max_fd, g_rs, g_ws, and MHD_INVALID_SOCKET.
Referenced by LLVMFuzzerTestOneInput().

|
static |
Definition at line 1326 of file fuzz_eventloop.c.
References fuzz_report_finding(), MHD_INVALID_SOCKET, MHD_quiesce_daemon(), quiesced_fd, and stat_quiesce.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Advance the daemon once.
| d | the daemon |
| var | which entry point to use |
| flavour | which descriptor sets to hand over: 0 the ones MHD asked for, 1 all-zero, 2 all-ones, 3 only the read set as collected |
Definition at line 1031 of file fuzz_eventloop.c.
References cfg, check_timeouts(), deadline_valid, drain_all(), g_es, g_rs, g_setsize, g_ws, MHD_run(), MHD_run_from_select, MHD_run_from_select2(), MHD_run_wait(), stat_rfs_v1, stat_rfs_v2, stat_run, and stat_run_wait.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Definition at line 371 of file fuzz_eventloop.c.
References fuzz_report_finding(), and NULL.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Definition at line 349 of file fuzz_eventloop.c.
References FUZZ_HARNESS_NAME, fuzz_verbose, stat_daemons, stat_expiry_waits, stat_fdset_v1, stat_fdset_v2, stat_handler_calls, stat_queued_at_stop, stat_quiesce, stat_resume, stat_rfs_v1, stat_rfs_v2, stat_run, stat_run_wait, stat_suspend, and stat_timeouts.
Referenced by LLVMFuzzerTestOneInput().

|
static |
Hand the daemon one more connection and do not run the loop again.
MHD_add_connection() on a thread-safe daemon does not build the struct MHD_Connection right away; it puts the socket on daemon->new_connections_head and leaves the rest to the next run. Stopping the daemon before that run is the only way to reach new_connection_close_() in daemon.c, which is where MHD disposes of a connection it accepted but never started. The ordinary teardown below always calls MHD_run() once more, which is why 1.6 billion executions left that function at zero coverage.
The socket pair is deliberately kept out of the harness's own connection table: nothing is ever sent on it, no notify callback fires for it, and by this point the teardown has already closed every tracked slot. Our end is returned so that the caller can close it after MHD_stop_daemon().
| d | the daemon, about to be stopped |
Definition at line 1160 of file fuzz_eventloop.c.
References MHD_add_connection(), MHD_YES, and stat_queued_at_stop.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Resume everything still parked.
Definition at line 509 of file fuzz_eventloop.c.
References lives, MAX_LIVE, MHD_resume_connection(), NULL, and stat_resume.
Referenced by LLVMFuzzerTestOneInput(), and wait_for_expiry().


|
static |
Definition at line 1711 of file fuzz_eventloop.c.
Referenced by fuzz_generate(), and sb_op().

|
static |
Definition at line 1720 of file fuzz_eventloop.c.
References sb_byte().
Referenced by fuzz_generate(), and gen_loop_round().


|
static |
Summarise the connections MHD currently owns.
Both properties are read back from MHD rather than modelled: a connection leaves the timeout lists exactly when MHD sets connection->suspended, and its timeout is exactly what MHD_set_connection_option() left there – which is not what the application passed if the connection happened to be suspended at the time. Modelling either of them means the oracle eventually fires on the model rather than on MHD.
| [out] | max_ms | largest timeout, in milliseconds, of the connections that are in a timeout list right now |
Definition at line 545 of file fuzz_eventloop.c.
References MHD_ConnectionInfo::connection_timeout, lives, MAX_LIVE, MHD_CONNECTION_INFO_CONNECTION_SUSPENDED, MHD_CONNECTION_INFO_CONNECTION_TIMEOUT, MHD_get_connection_info(), MHD_YES, NULL, and MHD_ConnectionInfo::suspended.
Referenced by check_timeouts().


|
static |
Definition at line 1207 of file fuzz_eventloop.c.
References csock, cur_daemon, MAX_CONNS, MHD_run(), and NULL.
Referenced by LLVMFuzzerTestOneInput().


|
static |
Find the registry slot of c, or -1.
Definition at line 393 of file fuzz_eventloop.c.
References lives, MAX_LIVE, and NULL.
Referenced by ahc(), and notify_conn_cb().

|
static |
Wait in real time until the connection timeout of the current daemon has certainly expired, so that the expiry path is actually reached.
MHD_OPTION_CONNECTION_TIMEOUT has a resolution of one second, so this costs about that much wall clock and is therefore globally budgeted.
Definition at line 1303 of file fuzz_eventloop.c.
References cfg, clk_ms, expiry_budget, MHD_run(), NULL, resume_all(), and stat_expiry_waits.
Referenced by LLVMFuzzerTestOneInput().


|
static |
The large response body, filled once.
Definition at line 316 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and make_response().
|
static |
Definition at line 317 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().
|
static |
Definition at line 228 of file fuzz_eventloop.c.
Referenced by ahc(), LLVMFuzzerTestOneInput(), make_response(), new_connection(), op_fdset(), op_run(), and wait_for_expiry().
|
static |
Artificial clock; only the harness's own scheduling depends on it.
Definition at line 303 of file fuzz_eventloop.c.
Referenced by check_timeouts(), LLVMFuzzerTestOneInput(), and wait_for_expiry().
|
static |
The client end of one socketpair. Deliberately not tied to a struct MHD_Connection: with MHD_USE_ITC (which MHD_ALLOW_SUSPEND_RESUME implies) MHD_add_connection() only queues the socket and the connection object is created later, from inside a run. There is therefore no moment at which the harness could pair the two up, and trying to would silently mistrack every connection.
Definition at line 265 of file fuzz_eventloop.c.
Referenced by close_conn(), drain_conn(), LLVMFuzzerTestOneInput(), new_connection(), and send_bytes().
|
static |
Definition at line 267 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and new_connection().
|
static |
Daemon of the current iteration.
Definition at line 290 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and send_bytes().
|
static |
Definition at line 304 of file fuzz_eventloop.c.
Referenced by check_timeouts(), and LLVMFuzzerTestOneInput().
|
static |
Definition at line 305 of file fuzz_eventloop.c.
Referenced by check_timeouts(), LLVMFuzzerTestOneInput(), and op_run().
|
static |
Budget for iterations that are allowed to wait in real time for a connection timeout to expire. MHD_OPTION_CONNECTION_TIMEOUT has a resolution of one second, so the expiry path cannot be reached without actually burning about that much wall clock; the budget keeps the whole run in the "couple of seconds" range while still exercising it. Override with MHD_FUZZ_EXPIRY_BUDGET.
Definition at line 327 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and wait_for_expiry().
|
static |
Definition at line 328 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().
|
static |
Request fragments. Whole requests, halves of requests and pipelines, so that a schedule can leave a connection in any parser state while it plays with the event loop.
Definition at line 1250 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().
|
static |
Definition at line 310 of file fuzz_eventloop.c.
Referenced by check_fdsets(), op_fdset(), op_poll(), and op_run().
|
static |
Definition at line 313 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), op_fdset(), and op_poll().
|
static |
Definition at line 311 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), op_fdset(), and op_poll().
|
static |
Descriptor sets collected by the last OP_FDSET.
Definition at line 308 of file fuzz_eventloop.c.
Referenced by check_fdsets(), op_fdset(), op_poll(), and op_run().
|
static |
Definition at line 312 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), op_fdset(), and op_run().
|
static |
Definition at line 309 of file fuzz_eventloop.c.
Referenced by check_fdsets(), op_fdset(), op_poll(), and op_run().
|
static |
Fragment indices, weighted towards the ones that complete a request: a schedule that never reaches the access handler exercises very little of the connection life cycle.
Definition at line 1733 of file fuzz_eventloop.c.
Referenced by gen_frag().
|
static |
Definition at line 287 of file fuzz_eventloop.c.
Referenced by ahc(), do_resume(), do_suspend(), LLVMFuzzerTestOneInput(), mhd_thinks_suspended(), notify_conn_cb(), op_connopt(), op_info(), resume_all(), scan_live_timeouts(), and slot_of().
|
static |
Connection memory limits selectable by byte 0.
Definition at line 231 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().
|
static |
Definition at line 266 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and new_connection().
|
static |
Listening socket returned by MHD_quiesce_daemon(), ours to close.
Definition at line 300 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), op_fdset(), and op_quiesce().
|
static |
Definition at line 2037 of file fuzz_eventloop.c.
Referenced by fuzz_seed_get().
|
static |
Definition at line 1911 of file fuzz_eventloop.c.
Referenced by fuzz_seed_count(), and fuzz_seed_get().
|
static |
FD_SETSIZE values handed to MHD_get_fdset2()/MHD_run_from_select2().
All of them are <= FD_SETSIZE on purpose. Passing a larger value than the fd_set objects actually hold would let MHD write past them, which is the application lying about its own buffers rather than anything MHD could defend against; the interesting direction is the smaller one, where MHD has to refuse descriptors that do not fit.
Definition at line 245 of file fuzz_eventloop.c.
Referenced by op_fdset().
|
static |
Statistics, printed at exit with –verbose.
Definition at line 331 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput(), and print_stats().
|
static |
Definition at line 343 of file fuzz_eventloop.c.
Referenced by print_stats(), and wait_for_expiry().
|
static |
Definition at line 333 of file fuzz_eventloop.c.
Referenced by op_fdset(), and print_stats().
|
static |
Definition at line 334 of file fuzz_eventloop.c.
Referenced by op_fdset(), and print_stats().
|
static |
Definition at line 332 of file fuzz_eventloop.c.
Referenced by ahc(), and print_stats().
|
static |
Definition at line 344 of file fuzz_eventloop.c.
Referenced by print_stats(), and queue_unprocessed_conn().
|
static |
Definition at line 340 of file fuzz_eventloop.c.
Referenced by op_quiesce(), and print_stats().
|
static |
Definition at line 342 of file fuzz_eventloop.c.
Referenced by ahc(), do_resume(), print_stats(), and resume_all().
|
static |
Definition at line 335 of file fuzz_eventloop.c.
Referenced by op_run(), and print_stats().
|
static |
Definition at line 336 of file fuzz_eventloop.c.
Referenced by op_run(), and print_stats().
|
static |
Definition at line 337 of file fuzz_eventloop.c.
Referenced by op_run(), and print_stats().
|
static |
Definition at line 338 of file fuzz_eventloop.c.
Referenced by op_run(), and print_stats().
|
static |
Definition at line 341 of file fuzz_eventloop.c.
Referenced by ahc(), do_suspend(), and print_stats().
|
static |
Definition at line 339 of file fuzz_eventloop.c.
Referenced by check_timeouts(), and print_stats().
|
static |
Definition at line 345 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().
|
static |
Set once the iteration only wants to drain the daemon. The handler then stops parking connections, which is what makes the flush loop in the teardown terminate.
Definition at line 297 of file fuzz_eventloop.c.
Referenced by ahc(), and LLVMFuzzerTestOneInput().
|
static |
Connection timeouts (seconds) selectable by byte 0.
Definition at line 234 of file fuzz_eventloop.c.
Referenced by LLVMFuzzerTestOneInput().