172#define FUZZ_HARNESS_NAME "fuzz_eventloop"
176#include <sys/socket.h>
177#include <netinet/in.h>
178#include <sys/select.h>
188#define BIG_BODY_LEN 131072
191#define DRAIN_BUF 4096
200 unsigned int timeout_s;
207 unsigned int resp_kind;
215 unsigned int fdset_var;
216 unsigned int run_var;
218 int timeout_every_run;
221 unsigned int nconn_up_front;
224 int stop_with_queued;
246 (
unsigned int) FD_SETSIZE,
247 (
unsigned int) FD_SETSIZE,
248 (
unsigned int) FD_SETSIZE / 2,
249 64, 16, 4, 1, (
unsigned int) FD_SETSIZE
285#define MAX_LIVE (MAX_CONNS + 4)
312static unsigned int g_setsize = (
unsigned int) FD_SETSIZE;
354 "%s: daemons=%lu handler=%lu get_fdset=%lu get_fdset2=%lu "
355 "run_from_select=%lu run_from_select2=%lu run=%lu run_wait=%lu "
356 "timeout queries=%lu quiesce=%lu suspend=%lu resume=%lu "
357 "expiry waits=%lu queued at stop=%lu\n",
379 (void) snprintf (msg,
sizeof (msg),
380 "MHD_PANIC() reached from an event-loop schedule "
382 (
NULL != file) ? file :
"?",
384 (
NULL != reason) ? reason :
"?");
408 void **socket_context,
415 (void) socket_context;
422 lives[i].mc = connection;
479 if (mhd_susp &&
lives[i].susp)
585 unsigned int pattern;
595 struct crc_state *st = (
struct crc_state *) cls;
599 if (pos >= st->total)
601 n = (size_t) (st->total - pos);
606 for (i = 0; i < n; i++)
607 buf[i] = (
char) (
'a' + (int) ((pos + i + st->pattern) % 26));
622 struct crc_state *st;
625 switch (
cfg.resp_kind)
628 st = (
struct crc_state *) calloc (1,
sizeof (
struct crc_state));
632 st->pattern =
cfg.clock_seed;
660 const char *upload_data,
661 size_t *upload_data_size,
673 if (
NULL == *req_cls)
675 *req_cls = (
void *) (intptr_t) 1;
679 if (0 != *upload_data_size)
681 *upload_data_size = 0;
690 unsigned int nt = (0 ==
cfg.timeout_s) ? 1u : (
cfg.timeout_s + 1u);
698 volatile size_t sink = 0;
736 else if (
cfg.susp_park &&
783 have[2] = (0 <= t64s);
785 val[0] = (uint64_t) tl;
787 val[2] = (uint64_t) (t64s < 0 ? 0 : t64s);
788 val[3] = (uint64_t) (ti < 0 ? 0 : ti);
790 for (k = 1; k < 4; k++)
791 if (have[k] != have[0])
793 "MHD_get_timeout*(): the four accessors disagree about whether "
794 "a timeout is in effect");
804 "MHD_get_timeout*() reported no timeout although the daemon has a "
805 "live, not suspended connection with a non-zero timeout");
810 for (k = 0; k < 4; k++)
812 if (val[k] <= max_ms)
814 (void) snprintf (msg,
sizeof (msg),
815 "MHD_get_timeout*() [accessor %u] returned %llu ms, "
816 "larger than the largest connection timeout in effect "
819 (
unsigned long long) val[k],
820 (
unsigned long long) max_ms);
823 for (k = 1; k < 4; k++)
824 if ( (val[k] > val[k - 1]) &&
827 "MHD_get_timeout*(): a later accessor reported a larger timeout "
828 "than an earlier one, although the deadline cannot have moved");
853 for (f = 0; f < (int) FD_SETSIZE; f++)
855 int in_set = FD_ISSET (f, &
g_rs) || FD_ISSET (f, &
g_ws);
857 if (with_es && FD_ISSET (f, &
g_es))
861 if ((
unsigned int) f >= setsize)
863 "MHD_get_fdset*() added a descriptor at or above the FD_SETSIZE "
864 "limit it was given");
869 (f == (
int) max_fd) )
878 "MHD_get_fdset*() set max_fd although it added no descriptor");
883 "MHD_get_fdset*() added descriptors but left max_fd unset");
884 if (hi > (
int) max_fd)
886 "MHD_get_fdset*() added a descriptor larger than the max_fd it "
888 if ((
unsigned int) max_fd >= setsize)
890 "MHD_get_fdset*() reported a max_fd at or above the FD_SETSIZE "
891 "limit it was given");
894 "MHD_get_fdset*() reported a max_fd that is not in any of the sets");
915 unsigned int setsize = (
unsigned int) FD_SETSIZE;
931 (
unsigned int) FD_SETSIZE);
945 (
unsigned int) FD_SETSIZE);
952 (
unsigned int) FD_SETSIZE);
960 ((
unsigned int)
quiesced_fd < (
unsigned int) FD_SETSIZE) &&
963 "MHD_get_fdset*() still watches the listening socket after "
964 "MHD_quiesce_daemon() handed it back to the application");
1003 ssize_t n = recv (
csock[i], tmp,
sizeof (tmp), MSG_DONTWAIT);
1033 unsigned int flavour)
1039 switch (flavour % 4)
1050 memset (&rs, 0xFF,
sizeof (rs));
1051 memset (&ws, 0xFF,
sizeof (ws));
1052 memset (&es, 0xFF,
sizeof (es));
1075 ? (
unsigned int) FD_SETSIZE :
g_setsize);
1089 if (
cfg.timeout_every_run)
1102 struct sockaddr_in sa;
1108 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
1110 if (
cfg.small_sockbuf)
1114 (void) setsockopt (sv[0], SOL_SOCKET, SO_RCVBUF, &bs,
sizeof (bs));
1115 (void) setsockopt (sv[1], SOL_SOCKET, SO_SNDBUF, &bs,
sizeof (bs));
1117 memset (&sa, 0,
sizeof (sa));
1118 sa.sin_family = AF_INET;
1119 sa.sin_port = htons (44444);
1120 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1124 (
const struct sockaddr *) &sa,
1125 (socklen_t)
sizeof (sa)))
1128 (void) close (sv[0]);
1163 struct sockaddr_in sa;
1165 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
1167 memset (&sa, 0,
sizeof (sa));
1168 sa.sin_family = AF_INET;
1169 sa.sin_port = htons (44444);
1170 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1173 (
const struct sockaddr *) &sa,
1174 (socklen_t)
sizeof (sa)))
1177 (void) close (sv[0]);
1200 (void) shutdown (
csock[i], SHUT_WR);
1201 (void) close (
csock[i]);
1211 const char *p = (
const char *) buf;
1213 unsigned int tries = 0;
1219 while ( (off < len) &&
1222 ssize_t s = send (
csock[i], p + off, len - off, MSG_DONTWAIT);
1237 (EAGAIN != errno) &&
1238 (EWOULDBLOCK != errno) &&
1251 "GET / HTTP/1.1\r\nHost: x\r\n\r\n",
1252 "GET /a HTTP/1.1\r\nHost: x\r\n",
1254 "POST /p HTTP/1.1\r\nHost: x\r\nContent-Length: 10\r\n\r\n",
1256 "POST /c HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\n\r\n",
1259 "GET / HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n",
1260 "GET / HTTP/1.0\r\n\r\n",
1261 "HEAD / HTTP/1.1\r\nHost: x\r\n\r\n",
1262 "GET / HTTP/1.1\r\nHost: x\r\n\r\nGET /2 HTTP/1.1\r\nHost: x\r\n\r\n",
1264 "ET / HTTP/1.1\r\n",
1307 if ( (!
cfg.allow_real_wait) ||
1308 (1 !=
cfg.timeout_s) ||
1340 "MHD_quiesce_daemon() handed out the listening socket twice");
1353 volatile size_t sink = 0;
1361 sink += (size_t) di->
flags;
1403 unsigned int nopt = 0;
1406 unsigned int nops = 0;
1424 big_body[i] = (
char) (
'a' + (i % 26));
1428 const char *e = getenv (
"MHD_FUZZ_EXPIRY_BUDGET");
1435 memset (&
cfg, 0,
sizeof (
cfg));
1453 cfg.listen_sock = (0 != (
data[0] & 0x04));
1454 cfg.app_fd_setsize = (0 != (
data[0] & 0x08));
1456 cfg.conn_limit = (0 != (
data[0] & 0x40));
1457 cfg.small_sockbuf = (0 != (
data[0] & 0x80));
1459 cfg.resp_kind = (
unsigned int) (
data[1] & 0x03);
1460 cfg.error_reply = (0 != (
data[1] & 0x04));
1461 cfg.susp_park = (0 != (
data[1] & 0x08));
1462 cfg.susp_now = (0 != (
data[1] & 0x10));
1463 cfg.hnd_connopt = (0 != (
data[1] & 0x20));
1464 cfg.hnd_info = (0 != (
data[1] & 0x40));
1465 cfg.auto_drain = (0 != (
data[1] & 0x80));
1467 cfg.fdset_var = (
unsigned int) (
data[2] & 0x07);
1468 cfg.run_var = (
unsigned int) ((
data[2] >> 3) & 0x03);
1469 cfg.honour_timeout = (0 != (
data[2] & 0x20));
1470 cfg.timeout_every_run = (0 != (
data[2] & 0x40));
1471 cfg.quiesce_end = (0 != (
data[2] & 0x80));
1473 cfg.nconn_up_front = 1u + (
unsigned int) (
data[3] & 0x03);
1474 cfg.check_always = (0 != (
data[3] & 0x04));
1475 cfg.allow_real_wait = (0 != (
data[3] & 0x08));
1476 cfg.stop_with_queued = (0 != (
data[3] & 0x10));
1479 if (0 !=
cfg.mem_limit)
1482 opts[nopt].
value = (intptr_t)
cfg.mem_limit;
1487 opts[nopt].
value = (intptr_t)
cfg.timeout_s;
1493 opts[nopt].
value = (intptr_t) 2;
1497 if (
cfg.app_fd_setsize)
1500 opts[nopt].
value = (intptr_t) FD_SETSIZE;
1505 opts[nopt].
value = 0;
1512 if (!
cfg.listen_sock)
1534 cfg.listen_sock = 0;
1554 for (i = 0; i <
cfg.nconn_up_front; i++)
1559 while ( (pos < size) &&
1562 const unsigned int b =
data[pos++];
1563 const unsigned int opc = b >> 4;
1564 const unsigned int arg = b & 0x0F;
1590 op_fdset (d, (0 != (arg & 0x08)) ?
cfg.fdset_var : arg);
1593 op_run (d, arg & 0x03, (arg >> 2) & 0x03);
1597 if ( (
cfg.honour_timeout) &&
1607 clk_ms += (uint64_t) (1u + arg) * (uint64_t) (1u +
cfg.clock_seed % 64u)
1609 if ( (
cfg.honour_timeout) &&
1626 (0 != (arg & 0x04)));
1636 if (0 != (arg & 0x08))
1651 if (
cfg.check_always)
1674 if (
cfg.quiesce_end)
1677 if (
cfg.stop_with_queued)
1683 (void) close (queued_fd);
1714 if (b->len < b->cap)
1724 sb_byte (b, (uint8_t) ((opc << 4) | (arg & 0x0F)));
1734 0, 0, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 1, 2, 12, 13, 14, 15
1780 unsigned int nrounds;
1796 for (i = 0; i < nrounds; i++)
1818 for (k = 0; k < n; k++)
1904 unsigned char cfg[5];
1905 unsigned char ops[24];
1909#define OPB(o,a) (unsigned char) (((o) << 4) | (a))
1914 {
"fdset-v1-run-from-select-v1", { 0x00, 0x80, 0x00, 0x00, 0x00 },
1920 {
"fdset2-run-from-select2", { 0x00, 0x80, 0x09, 0x00, 0x00 },
1926 {
"fdset2-small-setsize", { 0x00, 0x80, 0x02, 0x00, 0x04 },
1931 {
"fdset2-null-args", { 0x00, 0x80, 0x00, 0x00, 0x00 },
1936 {
"run-and-run-wait", { 0x00, 0x80, 0x10, 0x00, 0x00 },
1941 {
"run-from-select-bogus-sets", { 0x00, 0x80, 0x00, 0x00, 0x00 },
1947 {
"run-from-select-stale-sets", { 0x00, 0x80, 0x00, 0x00, 0x00 },
1952 {
"suspend-across-loop", { 0x00, 0x80, 0x00, 0x00, 0x00 },
1958 {
"handler-parks-two-connections", { 0x00, 0x88, 0x00, 0x00, 0x00 },
1964 {
"suspend-cancels-pending-resume", { 0x00, 0x80, 0x00, 0x00, 0x00 },
1971 {
"quiesce-listening-daemon", { 0x04, 0x80, 0x00, 0x00, 0x00 },
1978 {
"blocked-write-scheduling", { 0x80, 0x02, 0x00, 0x00, 0x00 },
1985 {
"connection-timeout-expiry", { 0x00, 0x80, 0x00, 0x08, 0x00 },
1991 {
"manual-timeout-list", { 0x00, 0x80, 0x00, 0x03, 0x00 },
1997 {
"pipelined-and-chunked", { 0x00, 0x81, 0x00, 0x00, 0x00 },
2003 {
"never-poll", { 0x00, 0x80, 0x00, 0x00, 0x00 },
2009 {
"abrupt-close-mid-request", { 0x00, 0x80, 0x00, 0x00, 0x00 },
2014 {
"connection-limit", { 0x40, 0x80, 0x00, 0x03, 0x00 },
2020 {
"no-timeout-configured", { 0x02, 0x80, 0x00, 0x04, 0x00 },
2028 {
"stop-with-queued-connection", { 0x00, 0x80, 0x00, 0x10, 0x00 },
2033 {
"stop-with-queued-after-quiesce", { 0x04, 0x80, 0x80, 0x10, 0x00 },
2047static const uint8_t *
2051 const struct seed_def *sd = &
seeds[idx];
2052 size_t n = sd->nops;
2054 if (n >
sizeof (sd->ops))
2055 n =
sizeof (sd->ops);
2060 *len =
sizeof (sd->cfg) + n;
Shared, header-only fuzzing driver for the MHD in-process fuzzers.
static FUZZ_UNUSED void fuzz_ignore_sigpipe(void)
static FUZZ_UNUSED int fuzz_verbose
static FUZZ_UNUSED uint32_t fuzz_below(struct fuzz_rng *r, uint32_t n)
static FUZZ_UNUSED uint8_t fuzz_byte(struct fuzz_rng *r)
static FUZZ_UNUSED void fuzz_report_finding(const char *what)
static FUZZ_UNUSED int fuzz_chance(struct fuzz_rng *r, uint32_t n)
static void drain_all(void)
static int csock[MAX_CONNS]
static void close_conn(unsigned int i, int graceful)
static size_t fuzz_seed_count(void)
static const struct seed_def seeds[]
static void op_info(struct MHD_Daemon *d, unsigned int arg)
static void op_fdset(struct MHD_Daemon *d, unsigned int var)
static int stats_registered
static void notify_conn_cb(void *cls, struct MHD_Connection *connection, void **socket_context, enum MHD_ConnectionNotificationCode toe)
static unsigned long stat_daemons
static int resume_all(void)
static const unsigned int timeout_tbl[]
static const unsigned int setsize_tbl[]
static void check_timeouts(struct MHD_Daemon *d)
static unsigned long stat_quiesce
static const unsigned char gen_frag_bias[]
static void sb_byte(struct sbuf *b, uint8_t v)
static unsigned long stat_suspend
static unsigned long stat_fdset_v2
static int new_connection(struct MHD_Daemon *d)
static MHD_socket g_max_fd
static unsigned long stat_expiry_waits
#define FUZZ_HARNESS_NAME
static unsigned long stat_run
static void check_fdsets(unsigned int setsize, MHD_socket max_fd, int had_max, int with_es)
static void drain_conn(unsigned int i)
static const uint8_t * fuzz_seed_get(size_t idx, size_t *len)
static unsigned long stat_fdset_v1
static void wait_for_expiry(struct MHD_Daemon *d)
static unsigned long stat_rfs_v2
static struct MHD_Response * make_response(void)
static void do_resume(unsigned int i)
static void sb_op(struct sbuf *b, unsigned int opc, unsigned int arg)
static void op_poll(void)
static unsigned int gen_frag(struct fuzz_rng *rng)
static unsigned long stat_run_wait
static MHD_socket quiesced_fd
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
static void op_quiesce(struct MHD_Daemon *d)
static unsigned int cur_conn
static int slot_of(const struct MHD_Connection *c)
static unsigned long stat_rfs_v1
static unsigned long stat_timeouts
static char big_body[BIG_BODY_LEN]
static void send_bytes(unsigned int i, const void *buf, size_t len)
static int expiry_budget_read
static struct MHD_Daemon * cur_daemon
static size_t fuzz_generate(struct fuzz_rng *rng, uint8_t *buf, size_t cap)
static void print_stats(void)
static uint64_t deadline_ms
static void panic_cb(void *cls, const char *file, unsigned int line, const char *reason)
static const char *const frag_tbl[16]
static int deadline_valid
static struct live_conn lives[MAX_LIVE]
static void op_run(struct MHD_Daemon *d, unsigned int var, unsigned int flavour)
static uint8_t seed_render_buf[64]
static unsigned long stat_resume
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 unsigned long stat_handler_calls
static int queue_unprocessed_conn(struct MHD_Daemon *d)
static int scan_live_timeouts(uint64_t *max_ms)
static unsigned long stat_queued_at_stop
static void op_connopt(unsigned int i, unsigned int val)
static void crc_free(void *cls)
static unsigned int nconns
static int mhd_thinks_suspended(unsigned int i)
static const size_t mem_limit_tbl[]
static int big_body_ready
static unsigned int g_setsize
static ssize_t crc_cb(void *cls, uint64_t pos, char *buf, size_t max)
static void gen_loop_round(struct fuzz_rng *rng, struct sbuf *b)
static void do_suspend(unsigned int i)
_MHD_EXTERN int MHD_get_timeout_i(struct MHD_Daemon *daemon)
_MHD_EXTERN int64_t MHD_get_timeout64s(struct MHD_Daemon *daemon)
#define MHD_run_from_select(d, r, w, e)
_MHD_EXTERN void MHD_stop_daemon(struct MHD_Daemon *daemon)
_MHD_EXTERN enum MHD_Result MHD_run(struct MHD_Daemon *daemon)
_MHD_EXTERN enum MHD_Result MHD_get_fdset2(struct MHD_Daemon *daemon, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, MHD_socket *max_fd, unsigned int fd_setsize)
#define MHD_get_fdset(daemon, read_fd_set, write_fd_set, except_fd_set, max_fd)
_MHD_EXTERN enum MHD_Result MHD_get_timeout(struct MHD_Daemon *daemon, MHD_UNSIGNED_LONG_LONG *timeout)
_MHD_EXTERN enum MHD_Result MHD_get_timeout64(struct MHD_Daemon *daemon, uint64_t *timeout)
_MHD_EXTERN enum MHD_Result MHD_run_from_select2(struct MHD_Daemon *daemon, const fd_set *read_fd_set, const fd_set *write_fd_set, const fd_set *except_fd_set, unsigned int fd_setsize)
_MHD_EXTERN struct MHD_Daemon * MHD_start_daemon(unsigned int flags, uint16_t port, MHD_AcceptPolicyCallback apc, void *apc_cls, MHD_AccessHandlerCallback dh, void *dh_cls,...)
_MHD_EXTERN enum MHD_Result MHD_run_wait(struct MHD_Daemon *daemon, int32_t millisec)
#define MHD_HTTP_INTERNAL_SERVER_ERROR
_MHD_EXTERN void MHD_set_panic_func(MHD_PanicCallback cb, void *cls)
MHD_ConnectionNotificationCode
@ MHD_CONNECTION_NOTIFY_STARTED
@ MHD_CONNECTION_INFO_CONNECTION_TIMEOUT
@ MHD_CONNECTION_INFO_CONNECTION_SUSPENDED
@ MHD_CONNECTION_INFO_DAEMON
@ MHD_CONNECTION_INFO_CONNECTION_FD
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
_MHD_EXTERN struct MHD_Response * MHD_create_response_empty(enum MHD_ResponseFlags flags)
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_static(size_t size, const void *buffer)
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_callback(uint64_t size, size_t block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback crfc)
_MHD_EXTERN enum MHD_Result MHD_add_connection(struct MHD_Daemon *daemon, MHD_socket client_socket, const struct sockaddr *addr, socklen_t addrlen)
_MHD_EXTERN enum MHD_Result MHD_set_connection_option(struct MHD_Connection *connection, enum MHD_CONNECTION_OPTION option,...)
_MHD_EXTERN MHD_socket MHD_quiesce_daemon(struct MHD_Daemon *daemon)
_MHD_EXTERN const union MHD_DaemonInfo * MHD_get_daemon_info(struct MHD_Daemon *daemon, enum MHD_DaemonInfoType info_type,...)
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
public interface to libmicrohttpd
@ MHD_OPTION_APP_FD_SETSIZE
@ MHD_OPTION_NOTIFY_CONNECTION
@ MHD_OPTION_CONNECTION_LIMIT
@ MHD_OPTION_CONNECTION_MEMORY_LIMIT
@ MHD_OPTION_CONNECTION_TIMEOUT
#define MHD_CONTENT_READER_END_OF_STREAM
#define MHD_UNSIGNED_LONG_LONG
_MHD_EXTERN void MHD_resume_connection(struct MHD_Connection *connection)
#define MHD_INVALID_SOCKET
@ MHD_DAEMON_INFO_CURRENT_CONNECTIONS
@ MHD_ALLOW_SUSPEND_RESUME
@ MHD_USE_NO_LISTEN_SOCKET
_MHD_EXTERN void MHD_suspend_connection(struct MHD_Connection *connection)
@ MHD_CONNECTION_OPTION_TIMEOUT
unsigned int connection_timeout
struct MHD_Daemon * daemon
unsigned int num_connections