fuzz_options.c (76421B)
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_options.c 22 * @brief In-process fuzzer for MHD's daemon option handling and for the 23 * daemon start-up / shutdown paths. 24 * @author Christian Grothoff 25 * 26 * fuzz_request.c fuzzes what MHD does with the *bytes on the wire*, but 27 * it always starts the daemon in one single shape: external polling, no 28 * listen socket, five fixed options. Everything in daemon.c that is 29 * reached through any other configuration -- the flag validation in 30 * MHD_start_daemon(), parse_options_va(), the internal polling thread, 31 * the thread pool, epoll/poll/select, the listen socket, the per-IP and 32 * per-daemon connection limits, quiesce -- is therefore dead code as far 33 * as the fuzzing suite is concerned. This harness closes that gap: the 34 * input bytes pick a *combination* of MHD_FLAG bits and an MHD_OPTION 35 * array, the daemon is started with them, one short HTTP request is 36 * driven through it over a socketpair, and the daemon is stopped again. 37 * 38 * The request-driving machinery is the one from fuzz_request.c: 39 * MHD_USE_NO_LISTEN_SOCKET plus MHD_add_connection() on an AF_UNIX 40 * socketpair(), with a fake 127.0.0.1 peer address so that the per-IP 41 * accounting sees something sane, and MHD_set_panic_func() installed as 42 * a tripwire. What is new here is that the *daemon* is a variable. 43 * 44 * Two shapes of daemon exist, and the harness drives them differently: 45 * 46 * - "external polling" (no MHD_USE_INTERNAL_POLLING_THREAD and no 47 * MHD_USE_THREAD_PER_CONNECTION). Single threaded and fully 48 * deterministic: the segments are fed in one at a time and the 49 * daemon is pumped with MHD_run() / MHD_get_fdset2() + select() + 50 * MHD_run_from_select2() / MHD_run_wait() between them. This is the 51 * majority of the iterations and the only shape in which the harness 52 * suspends a connection. 53 * 54 * - "internal thread" (an internal polling thread, a thread pool, or 55 * thread-per-connection). MHD_add_connection() is explicitly 56 * supported in these modes -- it is how an application with its own 57 * accept() loop hands sockets over -- but the harness must not also 58 * poll the daemon, and it cannot know when the worker is done. So 59 * the whole request is written at once, the write side is shut down 60 * (which makes MHD finish the request immediately rather than 61 * waiting for more data), and the answer is awaited with a short 62 * bounded poll() before the daemon is stopped. MHD_USE_ITC is 63 * forced on in this shape so that the worker picks the new 64 * connection up at once instead of waiting for its poll timeout. 65 * No connection is ever suspended here. 66 * 67 * Input format (see README section 2.2 for the fuzz_request one, which 68 * the segment stream below is deliberately identical to): 69 * 70 * byte 0 daemon shape: index into mode_tbl[] (event loop and 71 * threading; the entries are the combinations MHD documents 72 * as valid, so that most iterations get a live daemon) 73 * byte 1 MHD_FLAG bits, group A (see flags_from_input()) 74 * byte 2 MHD_FLAG bits, group B; 0xC0 in the top two bits switches 75 * on the "raw" escape, which feeds bytes 1, 2 and 15 76 * straight into the flags word. That is what fuzzes 77 * MHD_start_daemon()'s own combination checks; MHD answering 78 * NULL is a normal outcome and simply ends the iteration. 79 * byte 3 option presence mask A (sizes and limits) 80 * byte 4 option presence mask B (discipline, insanity, fd_setsize) 81 * byte 5 option presence mask C (the callbacks and the pointers) 82 * byte 6 value selector: connection memory limit / increment 83 * byte 7 value selector: connection limit / per-IP limit 84 * byte 8 value selector: connection timeout / pool size / stack 85 * byte 9 value selector: nonce-nc size / digest random / bind type 86 * byte 10 value selector: discipline / strict / insanity / bzero URI 87 * byte 11 value selector: backlog / fd_setsize / reuse / fastopen 88 * byte 12 driver behaviour: event loop variant, quiesce, 89 * introspection, suspend mode, number of connections 90 * byte 13 handler behaviour (which response, MHD_NO, per-connection 91 * option) and the accept path: whether an accept policy 92 * callback is installed, what it answers, and whether the 93 * iteration additionally connect()s to the daemon's real 94 * listening socket 95 * byte 14 option presence mask D (the digest and TLS-adjacent 96 * options, MHD_OPTION_LISTEN_SOCKET, and the deliberately 97 * invalid option number) 98 * byte 15 spare entropy; also supplies flag bits 14+ in raw mode 99 * byte 16. a sequence of send segments, each introduced by a little 100 * endian 16 bit header (op << 14) | length 101 * op 0 send the payload on the current connection 102 * op 1 send the payload, then pump extra rounds 103 * op 2 send the payload, then pump extra rounds 104 * op 3 close the current connection, open a fresh one on 105 * the same daemon, then send 106 * 107 * The sixteen configuration bytes are mandatory; a shorter input is 108 * rejected. An input of exactly sixteen bytes is meaningful and is not 109 * a degenerate case: it starts and stops a daemon with one connection 110 * and no traffic at all, which is precisely the start-up/shutdown path 111 * this harness is about. 112 * 113 * Two rules the harness obeys, both of them application contract rather 114 * than anything worth fuzzing: 115 * 116 * - every daemon that starts is stopped, and no connection is left 117 * suspended when that happens, because MHD_stop_daemon() answers a 118 * suspended connection with MHD_PANIC(). Suspended connections are 119 * tracked in pending_resume[] and flushed during teardown, exactly 120 * as in fuzz_request.c; 121 * - the socket that MHD_quiesce_daemon() returns belongs to the 122 * caller. It is closed after MHD_stop_daemon() (not before: with 123 * internal threads a worker may still be using it), otherwise the 124 * harness runs out of file descriptors within a few thousand 125 * iterations. 126 * 127 * Environment: 128 * 129 * MHD_FUZZ_QUIESCE_EPOLL_RACE=1 let the harness call 130 * MHD_quiesce_daemon() on an epoll daemon that runs its own 131 * thread(s). Off by default because that combination reaches an 132 * open MHD defect; see quiesce_epoll_race_allowed() below. 133 */ 134 135 #define FUZZ_HARNESS_NAME "fuzz_options" 136 #include "fuzz_common.h" 137 138 #include <microhttpd.h> 139 #include <sys/socket.h> 140 #include <netinet/in.h> 141 #include <sys/select.h> 142 #include <poll.h> 143 #include <limits.h> 144 145 /* MHD_OPTION_STRICT_FOR_CLIENT is superseded by 146 MHD_OPTION_CLIENT_DISCIPLINE_LVL but is still shipped API, and its 147 mapping onto the discipline level is exactly the kind of thing this 148 harness is for. */ 149 #if defined(__GNUC__) || defined(__clang__) 150 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 151 #endif 152 153 /** Number of mandatory configuration bytes at the start of the input. */ 154 #define CFG_BYTES 16 155 156 #define MAX_SEGMENTS 48 157 #define MAX_CONNECTIONS 6 158 #define MAX_OPTS 40 159 #define RESP_DRAIN_BUF 4096 160 #define GEN_BUF_SIZE 4096 161 162 /** 163 * Milliseconds the internal-thread shape waits for the daemon to answer. 164 * The write side of the socketpair is shut down before the wait, so the 165 * daemon never sits on an incomplete request: either it answers (the 166 * common case, tens of microseconds) or it closes the connection, and 167 * both wake poll() up immediately. The timeout is therefore only paid 168 * by inputs that make MHD drop the connection without a reply. 169 */ 170 #define THREAD_WAIT_MS 2 171 172 /** Rounds of MHD_run() after each segment in the external shape. */ 173 #define PUMP_ROUNDS 3 174 /** Rounds of MHD_run() after a segment sent with op 1 or 2. */ 175 #define PUMP_ROUNDS_LONG 10 176 177 178 /* ------------------------------------------------------------------ */ 179 /* Per-iteration configuration */ 180 /* ------------------------------------------------------------------ */ 181 182 struct fuzz_cfg 183 { 184 /** Daemon runs its own thread(s); the harness must not call MHD_run(). */ 185 int uses_threads; 186 /** A real listening socket was requested (no MHD_USE_NO_LISTEN_SOCKET). */ 187 int listen_sock; 188 /** MHD_USE_ERROR_LOG was requested, so an external logger is mandatory. */ 189 int err_log; 190 /** 0 none, 1 suspend+resume in the handler, 2 resume from the pump. */ 191 int suspend_mode; 192 /** 0 MHD_run(), 1 MHD_get_fdset2()+select()+MHD_run_from_select2(), 193 2 MHD_run_wait(0), 3 the v1 MHD_get_fdset()/MHD_run_from_select(). */ 194 unsigned int loop_mode; 195 /** Call MHD_quiesce_daemon() before stopping. */ 196 int quiesce; 197 /** Query MHD_get_daemon_info() / MHD_get_timeout*() while pumping. */ 198 int daemon_info; 199 /** Call MHD_set_connection_option() from the handler. */ 200 int conn_option; 201 /** Which response constructor the handler uses. */ 202 unsigned int resp_kind; 203 /** Handler answers MHD_NO instead of queueing a response. */ 204 int handler_no; 205 /** Upper bound on the number of connections the iteration opens. */ 206 unsigned int nconn_max; 207 /** Really connect() to the daemon's listening socket. */ 208 int real_connect; 209 /** Install an accept policy callback, and what it should answer. */ 210 int accept_policy; 211 int accept_policy_deny; 212 }; 213 214 static struct fuzz_cfg cfg; 215 216 /** 217 * Connections suspended by suspend mode 2, which the pump loop still has 218 * to resume. Cleared by completed_cb() so that a connection MHD has 219 * finished with is never resumed afterwards. A connection that is still 220 * suspended when MHD_stop_daemon() runs makes MHD answer with 221 * MHD_PANIC ("MHD_stop_daemon() called while we have suspended 222 * connections"), which would look exactly like an MHD bug. 223 */ 224 static struct MHD_Connection *pending_resume[MAX_CONNECTIONS]; 225 226 /** 227 * Set once the iteration only wants to drain the daemon. The handler 228 * then stops parking new connections, which is what makes the flush loop 229 * in the teardown provably terminate. 230 */ 231 static int tearing_down; 232 233 /** Statistics, printed at exit with --verbose. */ 234 static unsigned long stat_daemons; 235 static unsigned long stat_daemons_failed; 236 static unsigned long stat_threaded; 237 static unsigned long stat_handler_calls; 238 static unsigned long stat_conns_added; 239 static unsigned long stat_conns_refused; 240 static unsigned long stat_real_conns; 241 static int stats_registered; 242 243 244 static void 245 print_stats (void) 246 { 247 if (! fuzz_verbose) 248 return; 249 fprintf (stderr, 250 "%s: daemons=%lu (failed to start=%lu, threaded=%lu) " 251 "connections=%lu (refused=%lu, accepted from a real socket=%lu) " 252 "handler calls=%lu\n", 253 FUZZ_HARNESS_NAME, 254 stat_daemons, stat_daemons_failed, stat_threaded, 255 stat_conns_added, stat_conns_refused, stat_real_conns, 256 stat_handler_calls); 257 } 258 259 260 /* ------------------------------------------------------------------ */ 261 /* Flags */ 262 /* ------------------------------------------------------------------ */ 263 264 /** 265 * The event-loop / threading core of the flags word. Every entry is a 266 * combination MHD documents as valid, so that the ordinary path through 267 * this harness gets a live daemon and actually exercises the option 268 * handling; the deliberately invalid combinations are reached through 269 * the raw escape of byte 2 instead. 270 * 271 * The distribution is on purpose: entries 0..17 are the external polling 272 * modes, 18..23 the ones with internal threads. An iteration with 273 * internal threads costs a thread creation, a join and a short wait for 274 * the answer, i.e. roughly an order of magnitude more than an external 275 * one, so they are a quarter of the iterations rather than a half. 276 */ 277 static const unsigned int mode_tbl[] = { 278 0, 0, 0, 0, 0, 0, /* external, select() */ 279 0, 0, 0, 0, 0, 0, 280 MHD_USE_EPOLL, MHD_USE_EPOLL, /* external, epoll */ 281 MHD_USE_EPOLL, MHD_USE_EPOLL, 282 MHD_USE_AUTO, MHD_USE_AUTO, /* external, MHD picks */ 283 MHD_USE_INTERNAL_POLLING_THREAD, 284 MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_POLL, 285 MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_EPOLL, 286 MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD, 287 MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD 288 | MHD_USE_POLL, 289 MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD 290 }; 291 292 #define MODE_COUNT (sizeof (mode_tbl) / sizeof (mode_tbl[0])) 293 294 /** 295 * Flag bits the raw escape is allowed to set. MHD_USE_TLS is masked 296 * out: without a certificate the daemon merely fails to start, so it 297 * would only waste iterations, and fuzzing GnuTLS is not what this 298 * harness is for. Everything else, including the bits above 299 * MHD_USE_NO_THREAD_SAFETY that no MHD_FLAG uses, is fair game. 300 */ 301 #define RAW_FLAG_MASK (~((unsigned int) MHD_USE_TLS)) 302 303 /** 304 * The bit that MHD_suspend_connection() actually tests. 305 * 306 * MHD_ALLOW_SUSPEND_RESUME is a *compound* value (8192 | MHD_USE_ITC), 307 * so "0 != (flags & MHD_ALLOW_SUSPEND_RESUME)" is already true for a 308 * daemon that merely asked for MHD_USE_ITC -- and suspending such a 309 * connection is answered with 310 * MHD_PANIC ("Cannot suspend connections without enabling 311 * MHD_ALLOW_SUSPEND_RESUME"), which is the harness violating the API 312 * rather than a finding. internal.h calls the single bit 313 * MHD_TEST_ALLOW_SUSPEND_RESUME; this is the same value, expressed 314 * without reaching into a private header. 315 */ 316 #define SUSPEND_BIT \ 317 (((unsigned int) MHD_ALLOW_SUSPEND_RESUME) \ 318 & ~((unsigned int) MHD_USE_ITC)) 319 320 321 /** 322 * Build the flags word from bytes 0, 1, 2 and 15 of the input. 323 * 324 * @param data the input 325 * @return the flags to pass to MHD_start_daemon() 326 */ 327 static unsigned int 328 flags_from_input (const uint8_t *data) 329 { 330 unsigned int flags; 331 332 if (0xC0 == (data[2] & 0xC0)) 333 { 334 /* Raw escape: the flags word comes straight off the input. This is 335 what exercises MHD_start_daemon()'s combination checks (POLL with 336 EPOLL, EPOLL with thread-per-connection, AUTO with either, ...), 337 every one of which answers NULL. */ 338 flags = ((unsigned int) data[1]) 339 | (((unsigned int) (data[2] & 0x3F)) << 8) 340 | (((unsigned int) data[15]) << 14); 341 flags &= RAW_FLAG_MASK; 342 cfg.listen_sock = (0 == (flags & MHD_USE_NO_LISTEN_SOCKET)); 343 cfg.err_log = (0 != (flags & MHD_USE_ERROR_LOG)); 344 return flags; 345 } 346 347 flags = mode_tbl[data[0] % MODE_COUNT]; 348 349 if (0 != (data[1] & 0x01)) 350 flags |= MHD_USE_PEDANTIC_CHECKS; 351 if (0 != (data[1] & 0x02)) 352 flags |= MHD_USE_SUPPRESS_DATE_NO_CLOCK; 353 if (0 != (data[1] & 0x04)) 354 flags |= MHD_ALLOW_SUSPEND_RESUME; 355 if ( (0 != (data[1] & 0x08)) && 356 (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_UPGRADE)) ) 357 flags |= MHD_ALLOW_UPGRADE; 358 if (0 != (data[1] & 0x10)) 359 flags |= MHD_USE_TURBO; 360 if (0 != (data[1] & 0x20)) 361 flags |= MHD_USE_ITC; 362 if (0 != (data[1] & 0x40)) 363 cfg.err_log = 1; 364 if (0 != (data[1] & 0x80)) 365 flags |= MHD_USE_POST_HANDSHAKE_AUTH_SUPPORT; /* ignored without TLS */ 366 367 if (0 != (data[2] & 0x01)) 368 cfg.listen_sock = 1; 369 if (0 != (data[2] & 0x02)) 370 flags |= MHD_USE_IPv6; 371 if (0 != (data[2] & 0x04)) 372 flags |= MHD_USE_DUAL_STACK; 373 if (0 != (data[2] & 0x08)) 374 flags |= MHD_USE_TCP_FASTOPEN; 375 if (0 != (data[2] & 0x10)) 376 flags |= MHD_USE_NO_THREAD_SAFETY; 377 if (0 != (data[2] & 0x20)) 378 flags |= MHD_USE_INSECURE_TLS_EARLY_DATA; /* ignored without TLS */ 379 380 /* MHD_USE_NO_THREAD_SAFETY together with any internal thread is 381 documented as unsupported and answered with NULL. Drop it here 382 rather than burning the iteration; the raw escape above still 383 reaches that check. */ 384 if (0 != (flags & (MHD_USE_INTERNAL_POLLING_THREAD 385 | MHD_USE_THREAD_PER_CONNECTION))) 386 flags &= ~((unsigned int) MHD_USE_NO_THREAD_SAFETY); 387 return flags; 388 } 389 390 391 /** 392 * @return non-zero if @a flags make MHD use epoll 393 * 394 * MHD_USE_AUTO resolves to epoll for everything except 395 * thread-per-connection, which it resolves to poll. 396 */ 397 static int 398 uses_epoll (unsigned int flags) 399 { 400 if (0 != (flags & MHD_USE_EPOLL)) 401 return 1; 402 return (0 != (flags & MHD_USE_AUTO)) && 403 (0 == (flags & MHD_USE_THREAD_PER_CONNECTION)); 404 } 405 406 407 /** 408 * Is the harness allowed to call MHD_quiesce_daemon() on an epoll 409 * daemon that runs its own thread(s)? 410 * 411 * It is not, by default, because that combination reaches an *open* MHD 412 * defect and would make "make check" fail at random: 413 * 414 * MHD_quiesce_daemon() sets daemon->was_quiesced and then removes the 415 * listen FD from the epoll set itself (daemon.c:6208), tolerating 416 * ENOENT with the comment "can happen due to race with MHD_epoll()". 417 * MHD_epoll() removes the very same FD in two places. The first 418 * (daemon.c:5556) mirrors that and tolerates ENOENT. The second 419 * (daemon.c:5593), the "at the connection limit, disable listen 420 * socket" branch, also fires when daemon->was_quiesced is set -- and 421 * it does not tolerate anything: 422 * 423 * if (0 != epoll_ctl (daemon->epoll_fd, EPOLL_CTL_DEL, ls, NULL)) 424 * MHD_PANIC (_ ("Failed to remove listen FD from epoll set.")); 425 * 426 * The worker can read daemon->was_quiesced as already true and 427 * daemon->listen_socket_in_epoll as still true -- neither is atomic 428 * and neither is under a lock -- and then lose the race for the 429 * removal, so epoll_ctl() answers ENOENT and MHD aborts the process. 430 * Confirmed with errno == ENOENT, was_quiesced == 1, connections == 0. 431 * The same unguarded MHD_PANIC() sits in the worker-pool loop of 432 * MHD_quiesce_daemon() itself (daemon.c:6189). 433 * 434 * Set MHD_FUZZ_QUIESCE_EPOLL_RACE=1 to reach it. Quiescing is left 435 * enabled everywhere else, so the poll()/select() side of 436 * MHD_quiesce_daemon(), including its worker-pool loop, keeps being 437 * exercised. 438 */ 439 static int 440 quiesce_epoll_race_allowed (void) 441 { 442 static int val = -1; 443 444 if (0 > val) 445 { 446 const char *e = getenv ("MHD_FUZZ_QUIESCE_EPOLL_RACE"); 447 448 val = ((NULL != e) && (0 != atoi (e))) ? 1 : 0; 449 } 450 return val; 451 } 452 453 454 /* ------------------------------------------------------------------ */ 455 /* Option values */ 456 /* ------------------------------------------------------------------ */ 457 458 static const size_t mem_limit_tbl[] = { 459 0 /* MHD default */, 128, 192, 256, 384, 512, 1024, 1400, 460 1500, 2048, 4096, 8192, 32768, 64, 0, 0 461 }; 462 463 static const size_t mem_increment_tbl[] = { 464 0 /* MHD default */, 1, 16, 64, 128, 256, 1024, 4096, 465 1500, 32768, 0, 0, 0, 0, 0, 0 466 }; 467 468 static const unsigned int conn_limit_tbl[] = { 469 0, 1, 2, 3, 8, 64, 1024, 100000 470 }; 471 472 static const unsigned int per_ip_limit_tbl[] = { 473 0, 1, 2, 3, 4, 8, 64, 1000 474 }; 475 476 static const unsigned int timeout_tbl[] = { 477 0, 1, 2, 5, 60, 3600, 86400, UINT_MAX 478 }; 479 480 static const unsigned int pool_size_tbl[] = { 2, 3, 4, 2 }; 481 482 /* Small stacks make pthread_create() fail outright under ASAN, which 483 only produces a NULL daemon; keep the values plausible. */ 484 static const size_t stack_size_tbl[] = { 485 0, 1024u * 1024u, 2048u * 1024u, 8192u * 1024u 486 }; 487 488 /* Bounded on purpose: the nonce-nc array is nonce_nc_size * 489 sizeof(struct MHD_NonceNc) (about 130 bytes per slot) and is 490 allocated and freed once per iteration. */ 491 static const unsigned int nonce_nc_tbl[] = { 0, 1, 4, 32 }; 492 493 static const int discipline_tbl[] = { -3, -2, -1, 0, 1, 2, 3, -4 }; 494 495 static const int strict_tbl[] = { -1, 0, 1, 2 }; 496 497 static const unsigned int backlog_tbl[] = { 0, 1, 5, 511 }; 498 499 static const unsigned int fastopen_tbl[] = { 0, 1, 5, 10 }; 500 501 /* Anything but the platform's own FD_SETSIZE is rejected unless MHD was 502 built with HAS_FD_SETSIZE_OVERRIDABLE, so the odd values are a small 503 minority: they cost a whole iteration each. */ 504 static const int fd_setsize_tbl[] = { 505 (int) FD_SETSIZE, (int) FD_SETSIZE, (int) FD_SETSIZE, (int) FD_SETSIZE, 506 (int) FD_SETSIZE, (int) FD_SETSIZE, 64, 0 507 }; 508 509 /** Fixed entropy, so that a digest nonce is reproducible across runs. */ 510 static const char digest_rnd[32] = 511 "\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef" 512 "\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10"; 513 514 /* Bind addresses for MHD_OPTION_SOCK_ADDR / MHD_OPTION_SOCK_ADDR_LEN. 515 Filled in by prepare_sock_addrs() because htons()/htonl() are not 516 constant expressions. */ 517 static struct sockaddr_in bind4; 518 #ifdef AF_INET6 519 static struct sockaddr_in6 bind6; 520 #endif 521 static int bind_addrs_ready; 522 523 524 static void 525 prepare_sock_addrs (void) 526 { 527 if (bind_addrs_ready) 528 return; 529 bind_addrs_ready = 1; 530 memset (&bind4, 0, sizeof (bind4)); 531 bind4.sin_family = AF_INET; 532 bind4.sin_port = htons (0); /* ephemeral */ 533 bind4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 534 #ifdef AF_INET6 535 memset (&bind6, 0, sizeof (bind6)); 536 bind6.sin6_family = AF_INET6; 537 bind6.sin6_port = htons (0); 538 bind6.sin6_addr = in6addr_loopback; 539 #endif 540 } 541 542 543 /* ------------------------------------------------------------------ */ 544 /* The daemon callbacks */ 545 /* ------------------------------------------------------------------ */ 546 547 /** 548 * MHD_OPTION_EXTERNAL_LOGGER. Swallows the message unless --verbose is 549 * in effect. This is what makes MHD_USE_ERROR_LOG affordable: with the 550 * flag set, MHD executes several hundred MHD_DLOG() call sites in 551 * daemon.c that are otherwise dead, and without a logger of our own all 552 * of that would land on stderr. 553 */ 554 static void 555 logger_cb (void *cls, 556 const char *fmt, 557 va_list ap) 558 { 559 (void) cls; 560 if (! fuzz_verbose) 561 return; 562 (void) vfprintf (stderr, fmt, ap); 563 } 564 565 566 /** 567 * MHD_OPTION_URI_LOG_CALLBACK. The return value becomes the initial 568 * `*req_cls` of the request, so it has to stay NULL: the access handler 569 * uses "req_cls is still NULL" to recognise its first invocation, and a 570 * non-NULL value here would also have to be freed somewhere, which is 571 * not possible when MHD_OPTION_NOTIFY_COMPLETED is not set. 572 */ 573 static void * 574 uri_log_cb (void *cls, 575 const char *uri, 576 struct MHD_Connection *con) 577 { 578 volatile size_t sink; 579 580 (void) cls; 581 (void) con; 582 sink = (NULL != uri) ? strlen (uri) : 0; 583 (void) sink; 584 return NULL; 585 } 586 587 588 /** 589 * MHD_OPTION_UNESCAPE_CALLBACK. Replaces MHD's own unescaping, so it 590 * must honour the contract: unescape @a s in place and return the new 591 * length. Leaving the string alone is a legal implementation and keeps 592 * the harness out of the business of re-testing mhd_str.c, which 593 * fuzz_str does. 594 */ 595 static size_t 596 unescape_cb (void *cls, 597 struct MHD_Connection *conn, 598 char *s) 599 { 600 (void) cls; 601 (void) conn; 602 return strlen (s); 603 } 604 605 606 static void 607 completed_cb (void *cls, 608 struct MHD_Connection *connection, 609 void **req_cls, 610 enum MHD_RequestTerminationCode toe) 611 { 612 (void) cls; 613 (void) toe; 614 /* MHD is done with this connection, so the deferred resume of suspend 615 mode 2 must not fire for it any more. */ 616 if (! cfg.uses_threads) 617 { 618 unsigned int i; 619 620 for (i = 0; i < MAX_CONNECTIONS; i++) 621 if (pending_resume[i] == connection) 622 pending_resume[i] = NULL; 623 } 624 *req_cls = NULL; 625 } 626 627 628 static void 629 notify_connection_cb (void *cls, 630 struct MHD_Connection *connection, 631 void **socket_context, 632 enum MHD_ConnectionNotificationCode toe) 633 { 634 (void) cls; 635 (void) connection; 636 if (MHD_CONNECTION_NOTIFY_STARTED == toe) 637 *socket_context = NULL; 638 } 639 640 641 static void 642 panic_cb (void *cls, 643 const char *file, 644 unsigned int line, 645 const char *reason) 646 { 647 char msg[512]; 648 649 (void) cls; 650 (void) snprintf (msg, sizeof (msg), 651 "MHD_PANIC() reached at %s:%u: %s", 652 (NULL != file) ? file : "?", 653 line, 654 (NULL != reason) ? reason : "?"); 655 fuzz_report_finding (msg); 656 } 657 658 659 /* ------------------------------------------------------------------ */ 660 /* Suspend bookkeeping */ 661 /* ------------------------------------------------------------------ */ 662 663 static void 664 pending_resume_add (struct MHD_Connection *c) 665 { 666 unsigned int i; 667 668 for (i = 0; i < MAX_CONNECTIONS; i++) 669 { 670 if (NULL == pending_resume[i]) 671 { 672 pending_resume[i] = c; 673 return; 674 } 675 } 676 } 677 678 679 /** 680 * Resume everything still parked. 681 * 682 * @return non-zero if at least one connection was resumed, so that the 683 * caller knows the daemon needs another round to act on it 684 */ 685 static int 686 pending_resume_flush (void) 687 { 688 unsigned int i; 689 int any = 0; 690 691 for (i = 0; i < MAX_CONNECTIONS; i++) 692 { 693 struct MHD_Connection *c = pending_resume[i]; 694 695 if (NULL == c) 696 continue; 697 /* Clear first: MHD_resume_connection() can make MHD run the handler, 698 which may suspend the very same connection again. */ 699 pending_resume[i] = NULL; 700 MHD_resume_connection (c); 701 any = 1; 702 } 703 return any; 704 } 705 706 707 /** 708 * Suspend the connection if the input asks for it. Only ever called in 709 * the external-polling shape: resuming from the harness thread while an 710 * internal worker owns the connection is legal but untimed, and this 711 * harness has no way to tell whether the resume happened before or after 712 * the worker looked at the connection. 713 */ 714 static void 715 suspend_maybe (struct MHD_Connection *connection) 716 { 717 if ( (0 == cfg.suspend_mode) || 718 cfg.uses_threads || 719 tearing_down) 720 return; 721 MHD_suspend_connection (connection); 722 if (1 == cfg.suspend_mode) 723 { 724 MHD_resume_connection (connection); 725 return; 726 } 727 pending_resume_add (connection); 728 } 729 730 731 /* ------------------------------------------------------------------ */ 732 /* The access handler */ 733 /* ------------------------------------------------------------------ */ 734 735 static const char resp_body[] = "hello"; 736 737 static enum MHD_Result 738 ahc (void *cls, 739 struct MHD_Connection *connection, 740 const char *url, 741 const char *method, 742 const char *version, 743 const char *upload_data, 744 size_t *upload_data_size, 745 void **req_cls) 746 { 747 /* The address of this object is the "request already started" marker. 748 Nothing is allocated per request on purpose: this harness runs 749 millions of iterations in one process and the daemon shapes with 750 internal threads cannot guarantee that MHD_OPTION_NOTIFY_COMPLETED 751 is even set, so anything malloc()ed here could leak. */ 752 static int req_marker; 753 struct MHD_Response *resp; 754 enum MHD_Result ret; 755 unsigned int code; 756 volatile size_t sink = 0; 757 758 (void) cls; 759 (void) upload_data; 760 761 if (&req_marker != *req_cls) 762 { 763 *req_cls = &req_marker; 764 return MHD_YES; 765 } 766 stat_handler_calls++; 767 768 /* Touch the parsed request line the way a real application would. */ 769 if (NULL != url) 770 sink += strlen (url); 771 if (NULL != method) 772 sink += strlen (method); 773 if (NULL != version) 774 sink += strlen (version); 775 (void) sink; 776 777 if (0 != *upload_data_size) 778 { 779 *upload_data_size = 0; 780 return MHD_YES; 781 } 782 783 if (cfg.conn_option) 784 (void) MHD_set_connection_option (connection, 785 MHD_CONNECTION_OPTION_TIMEOUT, 786 (unsigned int) 30); 787 if (cfg.handler_no) 788 return MHD_NO; /* never suspend on this path: MHD_NO terminates the 789 connection and terminating a suspended one trips 790 mhd_assert (! connection->suspended) */ 791 792 code = MHD_HTTP_OK; 793 switch (cfg.resp_kind) 794 { 795 case 1: 796 resp = MHD_create_response_empty (MHD_RF_NONE); 797 code = MHD_HTTP_NO_CONTENT; 798 break; 799 case 2: 800 resp = MHD_create_response_from_buffer (sizeof (resp_body) - 1, 801 (void *) (intptr_t) resp_body, 802 MHD_RESPMEM_MUST_COPY); 803 code = MHD_HTTP_FORBIDDEN; 804 break; 805 case 3: 806 resp = MHD_create_response_from_buffer_static (0, ""); 807 code = MHD_HTTP_INTERNAL_SERVER_ERROR; 808 break; 809 default: 810 resp = MHD_create_response_from_buffer_static (sizeof (resp_body) - 1, 811 resp_body); 812 break; 813 } 814 if (NULL == resp) 815 return MHD_NO; 816 ret = MHD_queue_response (connection, code, resp); 817 MHD_destroy_response (resp); 818 if (MHD_YES == ret) 819 suspend_maybe (connection); 820 return ret; 821 } 822 823 824 /* ------------------------------------------------------------------ */ 825 /* Driving the daemon */ 826 /* ------------------------------------------------------------------ */ 827 828 /** 829 * Read and discard whatever the daemon has produced so far. The harness 830 * has no response oracle -- fuzz_request owns that job -- but the data 831 * has to be taken off the socket so that MHD's writes keep succeeding. 832 */ 833 static void 834 drain (int sock) 835 { 836 char tmp[RESP_DRAIN_BUF]; 837 838 if (0 > sock) 839 return; 840 while (0 < recv (sock, tmp, sizeof (tmp), MSG_DONTWAIT)) 841 /* nothing */; 842 } 843 844 845 /** 846 * Advance an externally polled daemon by one cycle, through whichever of 847 * the four event-loop entry points byte 12 selected. 848 * 849 * The select() timeout is always zero: the harness is single threaded 850 * and everything the daemon could be waiting for has already been 851 * written into the socketpair, so blocking would only burn wall clock. 852 */ 853 static void 854 run_once (struct MHD_Daemon *d) 855 { 856 fd_set rs; 857 fd_set ws; 858 fd_set es; 859 MHD_socket max_fd = MHD_INVALID_SOCKET; 860 struct timeval tv; 861 862 if (cfg.daemon_info) 863 { 864 MHD_UNSIGNED_LONG_LONG tl = 0; 865 volatile int64_t sink; 866 867 (void) MHD_get_timeout (d, &tl); 868 sink = MHD_get_timeout64s (d); 869 sink += (int64_t) MHD_get_timeout_i (d); 870 (void) sink; 871 } 872 switch (cfg.loop_mode) 873 { 874 case 1: 875 case 3: 876 FD_ZERO (&rs); 877 FD_ZERO (&ws); 878 FD_ZERO (&es); 879 /* MHD_get_fdset and MHD_run_from_select are also macros forwarding 880 to the *2 variants, so the names have to be parenthesised for the 881 v1 entry points to be reached at all. */ 882 if (1 == cfg.loop_mode) 883 { 884 if (MHD_YES != MHD_get_fdset2 (d, &rs, &ws, &es, &max_fd, 885 (unsigned int) FD_SETSIZE)) 886 { 887 (void) MHD_run (d); 888 return; 889 } 890 } 891 else 892 { 893 if (MHD_YES != (MHD_get_fdset) (d, &rs, &ws, &es, &max_fd)) 894 { 895 (void) MHD_run (d); 896 return; 897 } 898 } 899 tv.tv_sec = 0; 900 tv.tv_usec = 0; 901 if (MHD_INVALID_SOCKET != max_fd) 902 (void) select ((int) max_fd + 1, &rs, &ws, &es, &tv); 903 if (1 == cfg.loop_mode) 904 (void) MHD_run_from_select2 (d, &rs, &ws, &es, (unsigned int) FD_SETSIZE); 905 else 906 (void) (MHD_run_from_select) (d, &rs, &ws, &es); 907 break; 908 case 2: 909 (void) MHD_run_wait (d, 0); 910 break; 911 default: 912 (void) MHD_run (d); 913 break; 914 } 915 } 916 917 918 static void 919 pump (struct MHD_Daemon *d, 920 int sock, 921 unsigned int rounds) 922 { 923 unsigned int i; 924 925 if (cfg.uses_threads) 926 return; 927 for (i = 0; i < rounds; i++) 928 { 929 /* Deferred resume of suspend mode 2. Each slot is cleared before 930 its connection is resumed, which stays correct even when the 931 resume makes MHD complete (and forget) the connection. */ 932 (void) pending_resume_flush (); 933 run_once (d); 934 drain (sock); 935 } 936 } 937 938 939 /** 940 * Wait, briefly and with a hard bound, for a daemon with internal 941 * threads to answer. The caller has already shut the write side down, 942 * so MHD sees end-of-stream and either answers or closes; both wake 943 * poll() immediately. An input that makes MHD do neither pays the full 944 * timeout, which is why it is only a couple of milliseconds. 945 */ 946 static void 947 wait_threaded (int sock) 948 { 949 unsigned int round; 950 951 if (0 > sock) 952 return; 953 for (round = 0; round < 4; round++) 954 { 955 struct pollfd p; 956 char tmp[RESP_DRAIN_BUF]; 957 ssize_t n; 958 959 p.fd = sock; 960 p.events = POLLIN; 961 p.revents = 0; 962 if (0 >= poll (&p, 1, THREAD_WAIT_MS)) 963 return; 964 if (0 == (p.revents & POLLIN)) 965 return; /* POLLHUP/POLLERR only: peer is gone */ 966 n = recv (sock, tmp, sizeof (tmp), MSG_DONTWAIT); 967 if (0 >= n) 968 return; 969 } 970 } 971 972 973 static void 974 send_all (struct MHD_Daemon *d, 975 int sock, 976 const uint8_t *data, 977 size_t len) 978 { 979 size_t off = 0; 980 unsigned int stall = 0; 981 982 if (0 > sock) 983 return; 984 while ( (off < len) && 985 (stall < 64) ) 986 { 987 ssize_t s = send (sock, data + off, len - off, MSG_DONTWAIT); 988 989 if (0 < s) 990 { 991 off += (size_t) s; 992 stall = 0; 993 continue; 994 } 995 stall++; 996 if (cfg.uses_threads) 997 { 998 struct pollfd p; 999 1000 p.fd = sock; 1001 p.events = POLLOUT; 1002 p.revents = 0; 1003 if (0 >= poll (&p, 1, THREAD_WAIT_MS)) 1004 break; 1005 } 1006 else 1007 { 1008 pump (d, sock, 2); 1009 } 1010 if ( (0 > s) && 1011 (EAGAIN != errno) && 1012 (EWOULDBLOCK != errno) && 1013 (EINTR != errno) ) 1014 break; 1015 } 1016 } 1017 1018 1019 /** 1020 * Hand a fresh socketpair to the daemon. 1021 * 1022 * @param d the daemon 1023 * @param[out] sock set to the harness side of the pair 1024 * @return 0 on success, -1 if MHD refused the connection (which is a 1025 * perfectly ordinary outcome: MHD_OPTION_CONNECTION_LIMIT and 1026 * MHD_OPTION_PER_IP_CONNECTION_LIMIT are part of what is fuzzed) 1027 */ 1028 static int 1029 new_connection (struct MHD_Daemon *d, 1030 int *sock) 1031 { 1032 int sv[2]; 1033 struct sockaddr_in sa; 1034 1035 *sock = -1; 1036 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv)) 1037 return -1; 1038 memset (&sa, 0, sizeof (sa)); 1039 sa.sin_family = AF_INET; 1040 sa.sin_port = htons (44444); 1041 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 1042 if (MHD_YES != MHD_add_connection (d, 1043 (MHD_socket) sv[1], 1044 (const struct sockaddr *) &sa, 1045 (socklen_t) sizeof (sa))) 1046 { 1047 /* MHD has already closed sv[1] in that case */ 1048 (void) close (sv[0]); 1049 stat_conns_refused++; 1050 return -1; 1051 } 1052 stat_conns_added++; 1053 *sock = sv[0]; 1054 return 0; 1055 } 1056 1057 1058 static void 1059 close_connection (struct MHD_Daemon *d, 1060 int *sock) 1061 { 1062 if (0 > *sock) 1063 return; 1064 (void) shutdown (*sock, SHUT_WR); 1065 if (cfg.uses_threads) 1066 wait_threaded (*sock); 1067 else 1068 pump (d, *sock, 4); 1069 (void) close (*sock); 1070 *sock = -1; 1071 } 1072 1073 1074 /* ------------------------------------------------------------------ */ 1075 /* Building the option array */ 1076 /* ------------------------------------------------------------------ */ 1077 1078 #define PICK(tbl, idx) ((tbl)[(idx) % (sizeof (tbl) / sizeof ((tbl)[0]))]) 1079 1080 static void 1081 add_opt (struct MHD_OptionItem *opts, 1082 unsigned int *nopt, 1083 enum MHD_OPTION option, 1084 intptr_t value, 1085 void *ptr_value) 1086 { 1087 if (*nopt + 1 >= MAX_OPTS) 1088 return; 1089 opts[*nopt].option = option; 1090 opts[*nopt].value = value; 1091 opts[*nopt].ptr_value = ptr_value; 1092 (*nopt)++; 1093 } 1094 1095 1096 /** 1097 * Translate the presence masks (bytes 3, 4, 14) and the value selectors 1098 * (bytes 6..11, 15) into an MHD_OptionItem array. 1099 * 1100 * Only the options that can be expressed through MHD_OPTION_ARRAY are 1101 * built here. The five callback options take two pointers, and putting 1102 * a function pointer into the array's `intptr_t value` member is not 1103 * strictly conforming C, so those go through the varargs of 1104 * MHD_start_daemon() instead (see start_daemon_variant()). 1105 */ 1106 static unsigned int 1107 build_options (const uint8_t *data, 1108 struct MHD_OptionItem *opts, 1109 unsigned int flags) 1110 { 1111 unsigned int nopt = 0; 1112 const uint8_t mask_a = data[3]; 1113 const uint8_t mask_b = data[4]; 1114 const uint8_t mask_d = data[14]; 1115 /* A thread pool needs an internal polling thread and is incompatible 1116 with thread-per-connection. */ 1117 const int pool_ok = 1118 (0 != (flags & MHD_USE_INTERNAL_POLLING_THREAD)) && 1119 (0 == (flags & MHD_USE_THREAD_PER_CONNECTION)); 1120 /* Offer options in configurations where MHD rejects them. One input 1121 in eight: the rejection branches are worth reaching, but each one 1122 costs the whole rest of the iteration, because the daemon does not 1123 start at all. */ 1124 const int misfit = (0xE0 == (data[15] & 0xE0)); 1125 1126 if (0 != (mask_a & 0x01)) 1127 add_opt (opts, &nopt, MHD_OPTION_CONNECTION_MEMORY_LIMIT, 1128 (intptr_t) PICK (mem_limit_tbl, data[6] & 0x0F), NULL); 1129 if (0 != (mask_a & 0x02)) 1130 add_opt (opts, &nopt, MHD_OPTION_CONNECTION_MEMORY_INCREMENT, 1131 (intptr_t) PICK (mem_increment_tbl, (data[6] >> 4) & 0x0F), NULL); 1132 if (0 != (mask_a & 0x04)) 1133 add_opt (opts, &nopt, MHD_OPTION_CONNECTION_LIMIT, 1134 (intptr_t) PICK (conn_limit_tbl, data[7] & 0x07), NULL); 1135 if (0 != (mask_a & 0x08)) 1136 add_opt (opts, &nopt, MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1137 (intptr_t) PICK (per_ip_limit_tbl, (data[7] >> 4) & 0x07), NULL); 1138 if (0 != (mask_a & 0x10)) 1139 add_opt (opts, &nopt, MHD_OPTION_CONNECTION_TIMEOUT, 1140 (intptr_t) PICK (timeout_tbl, data[8] & 0x07), NULL); 1141 /* MHD_OPTION_THREAD_POOL_SIZE is rejected outright without an 1142 internal polling thread, and again when combined with 1143 MHD_USE_THREAD_PER_CONNECTION. Both branches are worth reaching, 1144 but a daemon that fails to start exercises nothing else, so the 1145 mismatched combinations are gated behind an extra bit instead of 1146 being half of all the inputs that name the option. */ 1147 if ( (0 != (mask_a & 0x20)) && 1148 (pool_ok || misfit) ) 1149 add_opt (opts, &nopt, MHD_OPTION_THREAD_POOL_SIZE, 1150 (intptr_t) PICK (pool_size_tbl, (data[8] >> 3) & 0x03), NULL); 1151 if (0 != (mask_a & 0x40)) 1152 add_opt (opts, &nopt, MHD_OPTION_THREAD_STACK_SIZE, 1153 (intptr_t) PICK (stack_size_tbl, (data[8] >> 5) & 0x03), NULL); 1154 if (0 != (mask_a & 0x80)) 1155 add_opt (opts, &nopt, MHD_OPTION_LISTENING_ADDRESS_REUSE, 1156 (intptr_t) (unsigned int) (data[11] & 0x01), NULL); 1157 1158 if (0 != (mask_b & 0x01)) 1159 add_opt (opts, &nopt, MHD_OPTION_LISTEN_BACKLOG_SIZE, 1160 (intptr_t) PICK (backlog_tbl, (data[11] >> 1) & 0x03), NULL); 1161 if (0 != (mask_b & 0x02)) 1162 add_opt (opts, &nopt, MHD_OPTION_NONCE_NC_SIZE, 1163 (intptr_t) PICK (nonce_nc_tbl, data[9] & 0x03), NULL); 1164 if (0 != (mask_b & 0x04)) 1165 add_opt (opts, &nopt, MHD_OPTION_SERVER_INSANITY, 1166 (intptr_t) (unsigned int) ((data[10] >> 6) & 0x03), NULL); 1167 if (0 != (mask_b & 0x08)) 1168 add_opt (opts, &nopt, MHD_OPTION_STRICT_FOR_CLIENT, 1169 (intptr_t) PICK (strict_tbl, (data[10] >> 4) & 0x03), NULL); 1170 if (0 != (mask_b & 0x10)) 1171 add_opt (opts, &nopt, MHD_OPTION_CLIENT_DISCIPLINE_LVL, 1172 (intptr_t) PICK (discipline_tbl, data[10] & 0x07), NULL); 1173 if (0 != (mask_b & 0x20)) 1174 add_opt (opts, &nopt, MHD_OPTION_SIGPIPE_HANDLED_BY_APP, 1175 /* Truthful: LLVMFuzzerTestOneInput() ignores SIGPIPE 1176 process-wide before anything else happens. */ 1177 (intptr_t) 1, NULL); 1178 if (0 != (mask_b & 0x40)) 1179 add_opt (opts, &nopt, MHD_OPTION_APP_FD_SETSIZE, 1180 (intptr_t) PICK (fd_setsize_tbl, (data[11] >> 3) & 0x07), NULL); 1181 if (0 != (mask_b & 0x80)) 1182 add_opt (opts, &nopt, MHD_OPTION_ALLOW_BIN_ZERO_IN_URI_PATH, 1183 (intptr_t) (int) ((data[11] >> 5) & 0x03), NULL); 1184 1185 if (0 != (mask_d & 0x01)) 1186 add_opt (opts, &nopt, MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE, 1187 (intptr_t) (unsigned int) ((data[9] >> 2) & 0x0F), NULL); 1188 if (0 != (mask_d & 0x02)) 1189 add_opt (opts, &nopt, MHD_OPTION_DIGEST_AUTH_DEFAULT_NONCE_TIMEOUT, 1190 (intptr_t) (unsigned int) (data[15] & 0x7F), NULL); 1191 if (0 != (mask_d & 0x04)) 1192 add_opt (opts, &nopt, MHD_OPTION_DIGEST_AUTH_DEFAULT_MAX_NC, 1193 (intptr_t) (uint32_t) data[15], NULL); 1194 if (0 != (mask_d & 0x08)) 1195 add_opt (opts, &nopt, MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE, 1196 (intptr_t) PICK (fastopen_tbl, (data[11] >> 6) & 0x03), NULL); 1197 if (0 != (mask_d & 0x10)) 1198 add_opt (opts, &nopt, MHD_OPTION_TLS_NO_ALPN, 1199 (intptr_t) (int) (data[15] & 0x01), NULL); 1200 if (0 != (mask_d & 0x20)) 1201 /* MHD_INVALID_SOCKET means "use the socket MHD creates itself"; a 1202 real descriptor is deliberately not offered, because MHD takes 1203 ownership of it and the harness would have to track that. */ 1204 add_opt (opts, &nopt, MHD_OPTION_LISTEN_SOCKET, 1205 (intptr_t) MHD_INVALID_SOCKET, NULL); 1206 1207 /* MHD_OPTION_DIGEST_AUTH_RANDOM keeps the caller's buffer, the _COPY 1208 variant makes MHD malloc() a copy that MHD_stop_daemon() has to free 1209 again -- a leak this harness would notice immediately. */ 1210 if (0 != (data[5] & 0x20)) 1211 add_opt (opts, &nopt, 1212 (0 != (data[5] & 0x40)) 1213 ? MHD_OPTION_DIGEST_AUTH_RANDOM_COPY 1214 : MHD_OPTION_DIGEST_AUTH_RANDOM, 1215 (intptr_t) sizeof (digest_rnd), 1216 (void *) (intptr_t) digest_rnd); 1217 1218 /* A bind address is rejected together with MHD_USE_NO_LISTEN_SOCKET; 1219 same reasoning as for the thread pool above. */ 1220 if ( (0 != (data[5] & 0x80)) && 1221 (cfg.listen_sock || misfit) ) 1222 { 1223 prepare_sock_addrs (); 1224 /* The address family has to match MHD_USE_IPv6, otherwise MHD 1225 rejects the daemon; that check is reached through the raw flag 1226 escape rather than by feeding a mismatched address on purpose. */ 1227 #ifdef AF_INET6 1228 if (0 != (flags & MHD_USE_IPv6)) 1229 { 1230 if (0 != (data[15] & 0x02)) 1231 add_opt (opts, &nopt, MHD_OPTION_SOCK_ADDR_LEN, 1232 (intptr_t) (socklen_t) sizeof (bind6), &bind6); 1233 else 1234 add_opt (opts, &nopt, MHD_OPTION_SOCK_ADDR, 0, &bind6); 1235 } 1236 else 1237 #endif 1238 if (0 != (data[15] & 0x02)) 1239 add_opt (opts, &nopt, MHD_OPTION_SOCK_ADDR_LEN, 1240 (intptr_t) (socklen_t) sizeof (bind4), &bind4); 1241 else 1242 add_opt (opts, &nopt, MHD_OPTION_SOCK_ADDR, 0, &bind4); 1243 } 1244 1245 /* An option number MHD does not know at all. parse_options_va() 1246 answers MHD_NO for it and MHD_start_daemon() returns NULL, which is 1247 the branch this reaches; keep it last so that everything above has 1248 already been parsed. */ 1249 if (0 != (mask_d & 0x40)) 1250 add_opt (opts, &nopt, (enum MHD_OPTION) (200 + (data[15] & 0x0F)), 1251 0, NULL); 1252 1253 opts[nopt].option = MHD_OPTION_END; 1254 opts[nopt].value = 0; 1255 opts[nopt].ptr_value = NULL; 1256 return nopt; 1257 } 1258 1259 1260 /* The three callback options whose "not set" state is representable as a 1261 NULL function pointer; MHD checks all three for NULL before calling 1262 them, so passing NULL is exactly equivalent to omitting the option. */ 1263 typedef void *(*fuzz_uri_log_cb)(void *, const char *, 1264 struct MHD_Connection *); 1265 1266 #define VARARG_CALLBACKS \ 1267 MHD_OPTION_NOTIFY_COMPLETED, cb_completed, NULL, \ 1268 MHD_OPTION_NOTIFY_CONNECTION, cb_notify, NULL, \ 1269 MHD_OPTION_URI_LOG_CALLBACK, cb_uri_log, NULL 1270 1271 /* The accept policy callback, defined with the accept path further 1272 down. */ 1273 static enum MHD_Result 1274 apc_cb (void *cls, 1275 const struct sockaddr *addr, 1276 socklen_t addrlen); 1277 1278 1279 /** 1280 * Start the daemon. 1281 * 1282 * MHD_OPTION_EXTERNAL_LOGGER and MHD_OPTION_UNESCAPE_CALLBACK cannot be 1283 * "passed as NULL": MHD calls both unconditionally, so their absence has 1284 * to be expressed by leaving the option out of the varargs, which is why 1285 * there are four spellings of the same call. The logger comes first on 1286 * purpose -- MHD_OPTION_EXTERNAL_LOGGER only catches the messages 1287 * emitted after it has been parsed, and parsing the option array emits 1288 * several. 1289 */ 1290 static struct MHD_Daemon * 1291 start_daemon_variant (unsigned int flags, 1292 struct MHD_OptionItem *opts, 1293 unsigned int cbsel) 1294 { 1295 MHD_AcceptPolicyCallback apc = cfg.accept_policy ? &apc_cb : NULL; 1296 MHD_RequestCompletedCallback cb_completed = 1297 (0 != (cbsel & 0x01)) ? &completed_cb : NULL; 1298 MHD_NotifyConnectionCallback cb_notify = 1299 (0 != (cbsel & 0x02)) ? ¬ify_connection_cb : NULL; 1300 fuzz_uri_log_cb cb_uri_log = 1301 (0 != (cbsel & 0x04)) ? &uri_log_cb : NULL; 1302 1303 switch ((cbsel >> 3) & 0x03) 1304 { 1305 case 1: 1306 return MHD_start_daemon (flags, 0, apc, NULL, &ahc, NULL, 1307 MHD_OPTION_ARRAY, opts, 1308 VARARG_CALLBACKS, 1309 MHD_OPTION_UNESCAPE_CALLBACK, &unescape_cb, NULL, 1310 MHD_OPTION_END); 1311 case 2: 1312 return MHD_start_daemon (flags, 0, apc, NULL, &ahc, NULL, 1313 MHD_OPTION_EXTERNAL_LOGGER, &logger_cb, NULL, 1314 MHD_OPTION_ARRAY, opts, 1315 VARARG_CALLBACKS, 1316 MHD_OPTION_END); 1317 case 3: 1318 return MHD_start_daemon (flags, 0, apc, NULL, &ahc, NULL, 1319 MHD_OPTION_EXTERNAL_LOGGER, &logger_cb, NULL, 1320 MHD_OPTION_ARRAY, opts, 1321 VARARG_CALLBACKS, 1322 MHD_OPTION_UNESCAPE_CALLBACK, &unescape_cb, NULL, 1323 MHD_OPTION_END); 1324 default: 1325 return MHD_start_daemon (flags, 0, apc, NULL, &ahc, NULL, 1326 MHD_OPTION_ARRAY, opts, 1327 VARARG_CALLBACKS, 1328 MHD_OPTION_END); 1329 } 1330 } 1331 1332 1333 /** 1334 * The accept policy callback. MHD_accept_connection() calls it with the 1335 * peer address of every socket it accepts and closes the connection 1336 * again when it answers MHD_NO, which is a code path (and a whole 1337 * function, new_connection_close_()) that nothing else here reaches. 1338 */ 1339 static enum MHD_Result 1340 apc_cb (void *cls, 1341 const struct sockaddr *addr, 1342 socklen_t addrlen) 1343 { 1344 volatile size_t sink; 1345 1346 (void) cls; 1347 sink = (size_t) addrlen + ((NULL != addr) ? (size_t) addr->sa_family : 0u); 1348 (void) sink; 1349 return cfg.accept_policy_deny ? MHD_NO : MHD_YES; 1350 } 1351 1352 1353 /** 1354 * Really connect to the daemon's listening socket. 1355 * 1356 * MHD_add_connection() bypasses accept(), so without this the whole 1357 * accept path -- MHD_accept_connection(), the accept policy callback, 1358 * the listen-socket branches of the three event loops -- is unreachable. 1359 * The client end is given SO_LINGER {1, 0} so that close() sends a RST 1360 * and neither side ends up in TIME_WAIT: at fuzzing rates the ephemeral 1361 * port range would otherwise be exhausted within a couple of minutes. 1362 * 1363 * @param d the daemon, which must have a listening socket 1364 * @param flags the flags it was started with, to pick the address family 1365 * @return the connected socket, or -1 1366 */ 1367 static int 1368 connect_real (struct MHD_Daemon *d, 1369 unsigned int flags) 1370 { 1371 const union MHD_DaemonInfo *di; 1372 struct linger lg; 1373 int s; 1374 uint16_t port; 1375 1376 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 1377 if ( (NULL == di) || 1378 (0 == di->port) ) 1379 return -1; 1380 port = (uint16_t) di->port; 1381 prepare_sock_addrs (); 1382 #ifdef AF_INET6 1383 if (0 != (flags & MHD_USE_IPv6)) 1384 { 1385 struct sockaddr_in6 to = bind6; 1386 1387 to.sin6_port = htons (port); 1388 s = socket (AF_INET6, SOCK_STREAM, 0); 1389 if (0 > s) 1390 return -1; 1391 if (0 != connect (s, (const struct sockaddr *) &to, sizeof (to))) 1392 { 1393 (void) close (s); 1394 return -1; 1395 } 1396 } 1397 else 1398 #endif 1399 { 1400 struct sockaddr_in to = bind4; 1401 1402 to.sin_port = htons (port); 1403 s = socket (AF_INET, SOCK_STREAM, 0); 1404 if (0 > s) 1405 return -1; 1406 if (0 != connect (s, (const struct sockaddr *) &to, sizeof (to))) 1407 { 1408 (void) close (s); 1409 return -1; 1410 } 1411 } 1412 lg.l_onoff = 1; 1413 lg.l_linger = 0; 1414 (void) setsockopt (s, SOL_SOCKET, SO_LINGER, &lg, sizeof (lg)); 1415 stat_real_conns++; 1416 return s; 1417 } 1418 1419 1420 /** 1421 * Ask MHD_is_feature_supported() about one feature. The function is a 1422 * large switch in daemon.c that no other harness touches; the index 1423 * comes off the input so that invalid values reach its default branch 1424 * as well. 1425 */ 1426 static void 1427 query_feature (uint8_t sel) 1428 { 1429 volatile int sink; 1430 1431 sink = (int) MHD_is_feature_supported ((enum MHD_FEATURE) (sel % 40u)); 1432 (void) sink; 1433 } 1434 1435 1436 /** 1437 * Read everything MHD_get_daemon_info() offers. All of it lives in 1438 * daemon.c and none of it is reachable from the other harnesses. 1439 */ 1440 static void 1441 query_daemon_info (struct MHD_Daemon *d) 1442 { 1443 volatile unsigned int sink = 0; 1444 const union MHD_DaemonInfo *di; 1445 1446 sink += (unsigned int) (NULL != MHD_get_version ()); 1447 sink += MHD_get_version_bin (); 1448 1449 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); 1450 if (NULL != di) 1451 sink += di->num_connections; 1452 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS); 1453 if (NULL != di) 1454 sink += (unsigned int) di->flags; 1455 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 1456 if (NULL != di) 1457 sink += di->port; 1458 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); 1459 if (NULL != di) 1460 sink += (unsigned int) (di->listen_fd + 1); 1461 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_EPOLL_FD); 1462 if (NULL != di) 1463 sink += (unsigned int) (di->listen_fd + 1); 1464 (void) sink; 1465 } 1466 1467 1468 /* ------------------------------------------------------------------ */ 1469 /* The fuzz target */ 1470 /* ------------------------------------------------------------------ */ 1471 1472 int 1473 LLVMFuzzerTestOneInput (const uint8_t *data, 1474 size_t size) 1475 { 1476 struct MHD_Daemon *d; 1477 struct MHD_OptionItem opts[MAX_OPTS]; 1478 unsigned int flags; 1479 int sock = -1; 1480 int rsock = -1; 1481 size_t pos; 1482 unsigned int nseg = 0; 1483 unsigned int nconn = 1; 1484 unsigned int cbsel; 1485 MHD_socket quiesced = MHD_INVALID_SOCKET; 1486 1487 /* Must happen before the first write() into the socketpair, and must 1488 not be left to the built-in driver: fuzz_install_handlers() is 1489 compiled out under -DFUZZ_NO_MAIN, which is exactly the build every 1490 external fuzzing engine uses. The call is idempotent. See 1491 fuzz_ignore_sigpipe() in fuzz_common.h for what happens without it. */ 1492 fuzz_ignore_sigpipe (); 1493 1494 /* The sixteen configuration bytes are mandatory. An input of exactly 1495 that length is fine and starts a daemon with no traffic. */ 1496 if (size < CFG_BYTES) 1497 return 0; 1498 1499 memset (&cfg, 0, sizeof (cfg)); 1500 memset (pending_resume, 0, sizeof (pending_resume)); 1501 tearing_down = 0; 1502 1503 flags = flags_from_input (data); 1504 if (cfg.listen_sock) 1505 flags &= ~((unsigned int) MHD_USE_NO_LISTEN_SOCKET); 1506 else 1507 flags |= MHD_USE_NO_LISTEN_SOCKET; 1508 if (cfg.err_log) 1509 flags |= MHD_USE_ERROR_LOG; 1510 else 1511 flags &= ~((unsigned int) MHD_USE_ERROR_LOG); 1512 1513 cfg.uses_threads = (0 != (flags & (MHD_USE_INTERNAL_POLLING_THREAD 1514 | MHD_USE_THREAD_PER_CONNECTION))); 1515 if (cfg.uses_threads && 1516 (0 == (flags & MHD_USE_NO_THREAD_SAFETY))) 1517 { 1518 /* Without the inter-thread communication channel a worker only 1519 notices a connection handed to it by MHD_add_connection() when its 1520 own poll times out, so every threaded iteration would pay the full 1521 wait. MHD forces ITC on anyway whenever there is no listen 1522 socket; this extends that to the daemons that have one. */ 1523 flags |= MHD_USE_ITC; 1524 } 1525 1526 cfg.loop_mode = (unsigned int) (data[12] & 0x03); 1527 cfg.quiesce = (0 != (data[12] & 0x04)); 1528 if (cfg.quiesce && 1529 cfg.uses_threads && 1530 uses_epoll (flags) && 1531 (! quiesce_epoll_race_allowed ())) 1532 cfg.quiesce = 0; 1533 cfg.daemon_info = (0 != (data[12] & 0x08)); 1534 cfg.suspend_mode = (0 != (flags & SUSPEND_BIT)) 1535 ? (int) ((data[12] >> 4) & 0x03) 1536 : 0; 1537 if (3 == cfg.suspend_mode) 1538 cfg.suspend_mode = 1; 1539 cfg.nconn_max = 1u + (unsigned int) ((data[12] >> 6) & 0x03); 1540 if (cfg.nconn_max > MAX_CONNECTIONS) 1541 cfg.nconn_max = MAX_CONNECTIONS; 1542 1543 cfg.resp_kind = (unsigned int) (data[13] & 0x03); 1544 cfg.handler_no = (0 != (data[13] & 0x04)); 1545 cfg.conn_option = (0 != (data[13] & 0x08)); 1546 cfg.accept_policy = (0 != (data[13] & 0x10)); 1547 cfg.accept_policy_deny = (0 != (data[13] & 0x20)); 1548 /* One iteration in four of those that have a listening socket at all; 1549 a real connect()/accept() pair is much more expensive than 1550 MHD_add_connection() on a socketpair. */ 1551 cfg.real_connect = cfg.listen_sock && (0xC0 == (data[13] & 0xC0)); 1552 1553 (void) build_options (data, opts, flags); 1554 1555 cbsel = (unsigned int) data[5]; 1556 /* MHD_USE_ERROR_LOG without MHD_OPTION_EXTERNAL_LOGGER sends every 1557 message MHD produces to stderr through MHD_default_logger_, which 1558 at fuzzing rates is tens of megabytes of noise. The flag is far too 1559 valuable to drop -- with it set, several hundred MHD_DLOG() call 1560 sites in daemon.c become live -- so the logger is forced on instead 1561 (bit 4 of the callback selector). */ 1562 if (cfg.err_log) 1563 cbsel |= 0x10u; 1564 1565 MHD_set_panic_func (&panic_cb, NULL); 1566 d = start_daemon_variant (flags, opts, cbsel); 1567 if (NULL == d) 1568 { 1569 /* Entirely normal: an unsupported flag combination, an option MHD 1570 rejects, a bind() failure, ... */ 1571 stat_daemons_failed++; 1572 return 0; 1573 } 1574 stat_daemons++; 1575 if (cfg.uses_threads) 1576 stat_threaded++; 1577 if (! stats_registered) 1578 { 1579 stats_registered = 1; 1580 (void) atexit (&print_stats); 1581 } 1582 1583 if (cfg.daemon_info) 1584 query_daemon_info (d); 1585 query_feature (data[15]); 1586 1587 if (cfg.real_connect) 1588 { 1589 rsock = connect_real (d, flags); 1590 if (0 <= rsock) 1591 { 1592 static const char req[] = "GET / HTTP/1.1\r\nHost: x\r\n\r\n"; 1593 1594 (void) send (rsock, req, sizeof (req) - 1, MSG_DONTWAIT); 1595 if (cfg.uses_threads) 1596 wait_threaded (rsock); 1597 else 1598 pump (d, rsock, PUMP_ROUNDS_LONG); 1599 } 1600 } 1601 1602 (void) new_connection (d, &sock); 1603 1604 pos = CFG_BYTES; 1605 while ( (pos + 2 <= size) && 1606 (nseg < MAX_SEGMENTS) ) 1607 { 1608 unsigned int hdr = (unsigned int) data[pos] 1609 | ((unsigned int) data[pos + 1] << 8); 1610 unsigned int op = hdr >> 14; 1611 size_t slen = (size_t) (hdr & 0x3FFF); 1612 1613 pos += 2; 1614 nseg++; 1615 if (slen > size - pos) 1616 slen = size - pos; 1617 1618 if ( (3 == op) && 1619 (nconn < cfg.nconn_max) ) 1620 { 1621 close_connection (d, &sock); 1622 (void) new_connection (d, &sock); 1623 nconn++; 1624 } 1625 if (0 != slen) 1626 send_all (d, sock, data + pos, slen); 1627 pos += slen; 1628 if (cfg.uses_threads) 1629 continue; /* the threaded shape drains at close */ 1630 pump (d, sock, (0 == op) ? PUMP_ROUNDS : PUMP_ROUNDS_LONG); 1631 } 1632 1633 close_connection (d, &sock); 1634 pump (d, sock, 4); 1635 if (0 <= rsock) 1636 { 1637 (void) shutdown (rsock, SHUT_WR); 1638 if (cfg.uses_threads) 1639 wait_threaded (rsock); 1640 else 1641 pump (d, rsock, 4); 1642 (void) close (rsock); 1643 rsock = -1; 1644 } 1645 1646 /* A connection left suspended makes MHD_stop_daemon() MHD_PANIC(), and 1647 MHD_resume_connection() alone is not enough: it only raises a flag, 1648 and the connection is taken off the daemon's suspended list by 1649 MHD_run(). So flush and run until nothing is parked any more. 1650 tearing_down keeps the handler from parking anything new, which is 1651 what bounds this loop; the cap is only a backstop. */ 1652 tearing_down = 1; 1653 if (! cfg.uses_threads) 1654 { 1655 unsigned int i; 1656 1657 for (i = 0; i < MAX_CONNECTIONS + 2u; i++) 1658 { 1659 if (! pending_resume_flush ()) 1660 break; 1661 (void) MHD_run (d); 1662 } 1663 } 1664 1665 if (cfg.quiesce) 1666 { 1667 /* The returned socket belongs to the caller from here on, and with 1668 internal threads it must not be closed before MHD_stop_daemon() 1669 has joined them. */ 1670 quiesced = MHD_quiesce_daemon (d); 1671 } 1672 MHD_stop_daemon (d); 1673 if (MHD_INVALID_SOCKET != quiesced) 1674 (void) close ((int) quiesced); 1675 return 0; 1676 } 1677 1678 1679 /* ------------------------------------------------------------------ */ 1680 /* Structure-aware generator */ 1681 /* ------------------------------------------------------------------ */ 1682 1683 /* Defined unconditionally, exactly like the rest of the harness API: 1684 only main() may live behind #ifndef FUZZ_NO_MAIN, and fuzz_common.h 1685 already declares these three with FUZZ_UNUSED so that the libFuzzer 1686 and AFL++ builds, which never call them, compile without a warning. */ 1687 1688 struct sbuf 1689 { 1690 uint8_t *p; 1691 size_t len; 1692 size_t cap; 1693 }; 1694 1695 1696 static void 1697 sb_raw (struct sbuf *b, 1698 const void *s, 1699 size_t n) 1700 { 1701 if (b->len + n > b->cap) 1702 n = b->cap - b->len; 1703 memcpy (b->p + b->len, s, n); 1704 b->len += n; 1705 } 1706 1707 1708 static void 1709 sb_str (struct sbuf *b, 1710 const char *s) 1711 { 1712 sb_raw (b, s, strlen (s)); 1713 } 1714 1715 1716 static void 1717 sb_u64 (struct sbuf *b, 1718 uint64_t v, 1719 int hex) 1720 { 1721 char tmp[32]; 1722 1723 (void) snprintf (tmp, sizeof (tmp), 1724 hex ? "%llx" : "%llu", 1725 (unsigned long long) v); 1726 sb_str (b, tmp); 1727 } 1728 1729 1730 static const char *const gen_methods[] = { 1731 "GET", "POST", "HEAD", "PUT", "OPTIONS", "DELETE", "TRACE", "CONNECT", 1732 "PATCH", "get", "BREW", "" 1733 }; 1734 1735 static const char *const gen_targets[] = { 1736 "/", "/a", "/a/b/c", "*", "http://x/a", "/%41%42", "/a?b=c&d", 1737 "/very/long/path/that/does/not/fit/into/a/small/connection/memory/pool", 1738 "/a?novalue", "//", "/.%2e/", "/\x01" 1739 }; 1740 1741 static const char *const gen_versions[] = { 1742 "HTTP/1.1", "HTTP/1.0", "HTTP/1.2", "HTTP/0.9", "HTTP/1", "" 1743 }; 1744 1745 static const char *const gen_hdr_names[] = { 1746 "Host", "Connection", "Accept", "User-Agent", "Cookie", "Expect", 1747 "Content-Type", "X-Fuzz", "Upgrade", "Accept-Encoding", "Range", 1748 "If-Modified-Since" 1749 }; 1750 1751 static const char *const gen_hdr_values[] = { 1752 "x", "keep-alive", "close", "*/*", "a=b; c=d", "100-continue", 1753 "text/plain", "1", "fuzz-protocol", "gzip", "bytes=0-1", "chunked" 1754 }; 1755 1756 1757 /** 1758 * Emit one HTTP request into @a b. 1759 * 1760 * The shapes are deliberately unambitious -- the request parser is 1761 * fuzz_request's subject, not this harness's. What matters here is that 1762 * the bytes form something MHD will actually take through its state 1763 * machine under whatever daemon configuration the configuration bytes 1764 * describe, so that the option handling is exercised against a live 1765 * connection rather than against a connection MHD drops on the first 1766 * byte. 1767 */ 1768 static void 1769 gen_request (struct fuzz_rng *rng, 1770 struct sbuf *b, 1771 unsigned int shape) 1772 { 1773 unsigned int nhdr; 1774 unsigned int i; 1775 1776 switch (shape % 10) 1777 { 1778 case 9: 1779 /* Not HTTP at all: MHD has to reject it, which is its own path. */ 1780 for (i = 0; i < 24; i++) 1781 { 1782 uint8_t c = fuzz_byte (rng); 1783 1784 sb_raw (b, &c, 1); 1785 } 1786 return; 1787 case 6: 1788 /* Two pipelined requests on one connection. */ 1789 sb_str (b, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n"); 1790 sb_str (b, "GET /b HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n"); 1791 return; 1792 default: 1793 break; 1794 } 1795 1796 sb_str (b, gen_methods[fuzz_below (rng, (uint32_t) (sizeof (gen_methods) 1797 / sizeof (gen_methods[0] 1798 )))]); 1799 sb_str (b, " "); 1800 sb_str (b, gen_targets[fuzz_below (rng, (uint32_t) (sizeof (gen_targets) 1801 / sizeof (gen_targets[0] 1802 )))]); 1803 sb_str (b, " "); 1804 sb_str (b, gen_versions[fuzz_below (rng, 1805 (uint32_t) (sizeof (gen_versions) 1806 / sizeof (gen_versions[0]))) 1807 ]); 1808 sb_str (b, "\r\n"); 1809 1810 nhdr = (5 == (shape % 10)) ? (8 + fuzz_below (rng, 24)) : fuzz_below (rng, 5); 1811 for (i = 0; i < nhdr; i++) 1812 { 1813 sb_str (b, gen_hdr_names[fuzz_below (rng, 1814 (uint32_t) (sizeof (gen_hdr_names) 1815 / sizeof (gen_hdr_names[0] 1816 )))]); 1817 sb_str (b, ": "); 1818 sb_str (b, gen_hdr_values[fuzz_below (rng, 1819 (uint32_t) (sizeof (gen_hdr_values) 1820 / sizeof (gen_hdr_values[ 1821 0])))]); 1822 sb_str (b, "\r\n"); 1823 } 1824 1825 switch (shape % 10) 1826 { 1827 case 2: /* Content-Length body */ 1828 { 1829 uint32_t n = fuzz_below (rng, 64); 1830 1831 sb_str (b, "Content-Length: "); 1832 sb_u64 (b, n, 0); 1833 sb_str (b, "\r\n\r\n"); 1834 for (i = 0; i < n; i++) 1835 sb_str (b, "A"); 1836 break; 1837 } 1838 case 3: /* chunked body */ 1839 { 1840 unsigned int nch = 1 + fuzz_below (rng, 3); 1841 1842 sb_str (b, "Transfer-Encoding: chunked\r\n\r\n"); 1843 for (i = 0; i < nch; i++) 1844 { 1845 uint32_t n = 1 + fuzz_below (rng, 16); 1846 uint32_t k; 1847 1848 sb_u64 (b, n, 1); 1849 sb_str (b, "\r\n"); 1850 for (k = 0; k < n; k++) 1851 sb_str (b, "B"); 1852 sb_str (b, "\r\n"); 1853 } 1854 sb_str (b, "0\r\n\r\n"); 1855 break; 1856 } 1857 case 4: /* expect 100-continue */ 1858 sb_str (b, "Expect: 100-continue\r\nContent-Length: 4\r\n\r\nabcd"); 1859 break; 1860 case 7: /* upgrade request */ 1861 sb_str (b, "Connection: Upgrade\r\nUpgrade: fuzz-protocol\r\n\r\n"); 1862 break; 1863 case 8: /* truncated: MHD keeps waiting for more */ 1864 sb_str (b, "X-Trunc: "); 1865 break; 1866 default: 1867 sb_str (b, "\r\n"); 1868 break; 1869 } 1870 } 1871 1872 1873 /** 1874 * Serialise @a body into the segment stream understood by 1875 * LLVMFuzzerTestOneInput(). 1876 */ 1877 static void 1878 emit_segments (struct fuzz_rng *rng, 1879 struct sbuf *out, 1880 const uint8_t *body, 1881 size_t body_len, 1882 int new_conn_first) 1883 { 1884 size_t off = 0; 1885 int first = 1; 1886 1887 while (off < body_len) 1888 { 1889 size_t chunk; 1890 unsigned int op; 1891 uint8_t hdr[2]; 1892 unsigned int hv; 1893 1894 switch (fuzz_below (rng, 5)) 1895 { 1896 case 0: 1897 chunk = 1; 1898 break; 1899 case 1: 1900 chunk = 2 + fuzz_below (rng, 8); 1901 break; 1902 default: 1903 chunk = body_len - off; 1904 break; 1905 } 1906 if (chunk > body_len - off) 1907 chunk = body_len - off; 1908 if (chunk > 0x3FFF) 1909 chunk = 0x3FFF; 1910 op = (first && new_conn_first) ? 3u : (fuzz_chance (rng, 5) ? 2u : 0u); 1911 hv = (op << 14) | (unsigned int) chunk; 1912 hdr[0] = (uint8_t) (hv & 0xFF); 1913 hdr[1] = (uint8_t) (hv >> 8); 1914 if (out->len + 2 + chunk > out->cap) 1915 return; 1916 sb_raw (out, hdr, 2); 1917 sb_raw (out, body + off, chunk); 1918 off += chunk; 1919 first = 0; 1920 } 1921 } 1922 1923 1924 /** 1925 * The generator. 1926 * 1927 * Purely random configuration bytes are already useful for this harness 1928 * -- unlike an HTTP request, an option array has no grammar to get wrong 1929 * -- but two things still need help. Byte 0 is biased into the range of 1930 * mode_tbl[] so that most iterations get a daemon that actually starts, 1931 * and the tail of the input has to look like HTTP, or MHD closes every 1932 * connection before any of the configured behaviour has a chance to 1933 * matter. 1934 */ 1935 static size_t 1936 fuzz_generate (struct fuzz_rng *rng, 1937 uint8_t *buf, 1938 size_t cap) 1939 { 1940 struct sbuf out; 1941 uint8_t cfg_bytes[CFG_BYTES]; 1942 uint8_t req[GEN_BUF_SIZE]; 1943 struct sbuf rb; 1944 unsigned int nreq; 1945 unsigned int i; 1946 1947 out.p = buf; 1948 out.len = 0; 1949 out.cap = cap; 1950 1951 for (i = 0; i < CFG_BYTES; i++) 1952 cfg_bytes[i] = fuzz_byte (rng); 1953 1954 /* Byte 0 selects the daemon shape; keep it inside the table so that 1955 the value is not folded by the modulo in an uneven way. */ 1956 cfg_bytes[0] = (uint8_t) fuzz_below (rng, (uint32_t) MODE_COUNT); 1957 /* The raw flag escape is 1 in 4 of the byte-2 values, which is far too 1958 often: those daemons mostly fail to start and never reach the option 1959 handling. Clear the escape unless it is explicitly rolled. */ 1960 if (! fuzz_chance (rng, 10)) 1961 cfg_bytes[2] &= (uint8_t) ~0xC0u; 1962 else 1963 cfg_bytes[2] |= (uint8_t) 0xC0u; 1964 /* Likewise the deliberately invalid option number: useful, but every 1965 input carrying it ends in MHD_start_daemon() == NULL. */ 1966 if (! fuzz_chance (rng, 20)) 1967 cfg_bytes[14] &= (uint8_t) ~0x40u; 1968 1969 sb_raw (&out, cfg_bytes, CFG_BYTES); 1970 1971 nreq = 1u + (fuzz_chance (rng, 4) ? 1u : 0u); 1972 for (i = 0; i < nreq; i++) 1973 { 1974 rb.p = req; 1975 rb.len = 0; 1976 rb.cap = sizeof (req); 1977 gen_request (rng, &rb, fuzz_below (rng, 10)); 1978 emit_segments (rng, &out, req, rb.len, 1979 (0 != i) || fuzz_chance (rng, 6)); 1980 } 1981 return out.len; 1982 } 1983 1984 1985 /* ------------------------------------------------------------------ */ 1986 /* Built-in seed corpus */ 1987 /* ------------------------------------------------------------------ */ 1988 1989 /** 1990 * A seed is sixteen configuration bytes plus one request, rendered into 1991 * the wire format at run time so that segment lengths never have to be 1992 * spelled out by hand. 1993 * 1994 * Every seed turns on exactly one area, so that a corpus minimiser keeps 1995 * them distinguishable, and the configuration bytes of a seed that does 1996 * not care about an area are zero -- which is the plainest setting: 1997 * external polling with select(), no listen socket, no options at all, 1998 * one connection, MHD_run() as the event loop. 1999 */ 2000 struct seed_def 2001 { 2002 const char *name; 2003 unsigned char cfg[CFG_BYTES]; 2004 const char *req; 2005 }; 2006 2007 /* Byte positions inside seed_def::cfg, for readability. */ 2008 #define C_MODE 0 2009 #define C_FLAGA 1 2010 #define C_FLAGB 2 2011 #define C_OPTA 3 2012 #define C_OPTB 4 2013 #define C_OPTC 5 2014 #define C_VAL_MEM 6 2015 #define C_VAL_CONN 7 2016 #define C_VAL_THR 8 2017 #define C_VAL_DAUTH 9 2018 #define C_VAL_DISC 10 2019 #define C_VAL_SOCK 11 2020 #define C_DRIVE 12 2021 #define C_HANDLER 13 2022 #define C_OPTD 14 2023 #define C_SPARE 15 2024 2025 #define REQ_PLAIN "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" 2026 #define REQ_CLOSE "GET /a HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n" 2027 #define REQ_POST \ 2028 "POST /a HTTP/1.1\r\nHost: x\r\nContent-Length: 4\r\n\r\nabcd" 2029 #define REQ_CHUNKED \ 2030 "POST /a HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\n" \ 2031 "\r\n3\r\nabc\r\n0\r\n\r\n" 2032 2033 static const struct seed_def seeds[] = { 2034 /* ---- the event loops, all external ---- */ 2035 { "plain-external-run", 2036 { 0 }, REQ_PLAIN }, 2037 { "external-fdset2", 2038 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 | 0x08, 0, 0, 0 }, 2039 REQ_PLAIN }, 2040 { "external-run-wait", 2041 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0 }, 2042 REQ_PLAIN }, 2043 { "external-fdset-v1", 2044 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0, 0, 0 }, 2045 REQ_PLAIN }, 2046 { "external-epoll", 2047 { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2048 REQ_PLAIN }, 2049 { "external-auto", 2050 { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2051 REQ_PLAIN }, 2052 2053 /* ---- the daemon shapes that run their own threads ---- */ 2054 { "internal-thread-select", 2055 { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2056 REQ_CLOSE }, 2057 { "internal-thread-poll", 2058 { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2059 REQ_CLOSE }, 2060 { "internal-thread-epoll", 2061 { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2062 REQ_CLOSE }, 2063 { "thread-per-connection", 2064 { 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2065 REQ_CLOSE }, 2066 { "thread-per-connection-poll", 2067 { 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2068 REQ_CLOSE }, 2069 /* A thread pool needs MHD_OPTION_THREAD_POOL_SIZE (option mask A bit 2070 5) on top of an internal polling thread, and is rejected outright 2071 with thread-per-connection. */ 2072 { "thread-pool", 2073 { 18, 0, 0, 0x20, 0, 0, 0, 0, 0x00, 0, 0, 0, 0, 0, 0, 0 }, 2074 REQ_CLOSE }, 2075 { "thread-pool-epoll-stack", 2076 { 20, 0, 0, 0x20 | 0x40, 0, 0, 0, 0, 0x10 | 0x20, 0, 0, 0, 0, 0, 0, 0 }, 2077 REQ_CLOSE }, 2078 2079 /* ---- a real listening socket ---- */ 2080 { "listen-socket", 2081 { 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2082 REQ_PLAIN }, 2083 { "listen-socket-reuse-backlog", 2084 { 0, 0, 0x01, 0x80, 0x01, 0, 0, 0, 0, 0, 0, 0x01 | 0x06, 0, 0, 0, 0 }, 2085 REQ_PLAIN }, 2086 { "listen-socket-sockaddr", 2087 { 0, 0, 0x01, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2088 REQ_PLAIN }, 2089 { "listen-socket-ipv6-dual", 2090 { 0, 0, 0x01 | 0x02 | 0x04, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2091 REQ_PLAIN }, 2092 { "listen-socket-quiesce", 2093 { 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04 | 0x08, 0, 0, 0 }, 2094 REQ_PLAIN }, 2095 { "listen-socket-internal-thread", 2096 { 18, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04, 0, 0, 0 }, 2097 REQ_CLOSE }, 2098 2099 /* ---- the accept() path: a real client on the listening socket ---- 2100 Byte 13 bit 0x40|0x80 asks for the connect(), bit 0x10 installs the 2101 accept policy callback and bit 0x20 makes it say no. Without these 2102 MHD_accept_connection() and the listen-socket branches of the three 2103 event loops are never entered at all: MHD_add_connection() bypasses 2104 accept() completely. */ 2105 { "real-connect", 2106 { 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC0, 0, 0 }, 2107 REQ_PLAIN }, 2108 { "real-connect-accept-policy", 2109 { 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC0 | 0x10, 0, 0 }, 2110 REQ_PLAIN }, 2111 { "real-connect-accept-denied", 2112 { 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC0 | 0x10 | 0x20, 0, 0 }, 2113 REQ_PLAIN }, 2114 { "real-connect-internal-thread", 2115 { 18, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC0, 0, 0 }, 2116 REQ_CLOSE }, 2117 { "real-connect-external-epoll", 2118 { 12, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC0, 0, 0 }, 2119 REQ_PLAIN }, 2120 2121 /* ---- the memory options ---- */ 2122 { "tiny-pool", 2123 { 0, 0, 0, 0x01 | 0x02, 0, 0, 0x01 | 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2124 REQ_PLAIN }, 2125 { "big-pool-big-increment", 2126 { 0, 0, 0, 0x01 | 0x02, 0, 0, 0x0C | 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2127 REQ_POST }, 2128 2129 /* ---- the connection limits ---- */ 2130 { "connection-limit-one", 2131 { 0, 0, 0, 0x04, 0, 0, 0, 0x01, 0, 0, 0, 0, 0xC0, 0, 0, 0 }, 2132 REQ_PLAIN }, 2133 { "per-ip-limit-one", 2134 { 0, 0, 0, 0x08, 0, 0, 0, 0x10, 0, 0, 0, 0, 0xC0, 0, 0, 0 }, 2135 REQ_PLAIN }, 2136 { "connection-limit-zero", 2137 { 0, 0, 0, 0x04, 0, 0, 0, 0x00, 0, 0, 0, 0, 0, 0, 0, 0 }, 2138 REQ_PLAIN }, 2139 { "connection-timeout", 2140 { 0, 0, 0, 0x10, 0, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0 }, 2141 REQ_PLAIN }, 2142 2143 /* ---- parsing discipline and insanity ---- */ 2144 { "discipline-lowest", 2145 { 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0x00, 0, 0, 0, 0, 0 }, 2146 "GET /a HTTP/1.1\r\n Host: x\r\n\r\n" }, 2147 { "discipline-highest-pedantic", 2148 { 0, 0x01, 0, 0, 0x10, 0, 0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0 }, 2149 REQ_PLAIN }, 2150 { "strict-for-client", 2151 { 0, 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0x00, 0, 0, 0, 0, 0 }, 2152 REQ_PLAIN }, 2153 { "server-insanity", 2154 { 0, 0, 0, 0, 0x04, 0, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0 }, 2155 REQ_PLAIN }, 2156 { "bin-zero-in-uri-path", 2157 { 0, 0, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0, 0 }, 2158 "GET /a%00b HTTP/1.1\r\nHost: x\r\n\r\n" }, 2159 { "app-fd-setsize", 2160 { 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0x00, 0x01, 0, 0, 0 }, 2161 REQ_PLAIN }, 2162 2163 /* ---- the callbacks ---- */ 2164 { "notify-completed", 2165 { 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2166 REQ_PLAIN }, 2167 { "notify-connection", 2168 { 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2169 REQ_PLAIN }, 2170 { "uri-log-callback", 2171 { 0, 0, 0, 0, 0, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2172 "GET /a?q=%41 HTTP/1.1\r\nHost: x\r\n\r\n" }, 2173 { "external-logger", 2174 { 0, 0x40, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2175 REQ_PLAIN }, 2176 { "unescape-callback", 2177 { 0, 0, 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2178 "GET /%41%42?a=%43 HTTP/1.1\r\nHost: x\r\n\r\n" }, 2179 { "all-callbacks-error-log", 2180 { 0, 0x40, 0, 0, 0, 0x01 | 0x02 | 0x04 | 0x08 | 0x10, 2181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2182 REQ_PLAIN }, 2183 2184 /* ---- digest-auth related options ---- */ 2185 { "digest-random", 2186 { 0, 0, 0, 0, 0x02, 0x20, 0, 0, 0, 0x02, 0, 0, 0, 0, 0, 0 }, 2187 REQ_PLAIN }, 2188 { "digest-random-copy", 2189 { 0, 0, 0, 0, 0x02, 0x20 | 0x40, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0 }, 2190 REQ_PLAIN }, 2191 { "digest-nonce-bind-and-defaults", 2192 { 0, 0, 0, 0, 0, 0x20, 0, 0, 0, 0x3C, 0, 0, 0, 0, 2193 0x01 | 0x02 | 0x04, 0x11 }, 2194 REQ_PLAIN }, 2195 2196 /* ---- suspend / resume ---- */ 2197 { "suspend-immediate", 2198 { 0, 0x04, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, 2199 REQ_PLAIN }, 2200 { "suspend-deferred", 2201 { 0, 0x04, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0 }, 2202 REQ_PLAIN }, 2203 { "suspend-deferred-two-connections", 2204 { 0, 0x04, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0x20 | 0x40, 0, 0, 0 }, 2205 REQ_PLAIN }, 2206 2207 /* ---- the remaining flag bits ---- */ 2208 { "turbo-itc-suppress-date", 2209 { 0, 0x02 | 0x10 | 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2210 REQ_PLAIN }, 2211 { "allow-upgrade", 2212 { 0, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2213 "GET / HTTP/1.1\r\nHost: x\r\nConnection: Upgrade\r\n" 2214 "Upgrade: fuzz-protocol\r\n\r\n" }, 2215 { "no-thread-safety", 2216 { 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2217 REQ_PLAIN }, 2218 { "tcp-fastopen-listen", 2219 { 0, 0, 0x01 | 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0x08, 0 }, 2220 REQ_PLAIN }, 2221 { "sigpipe-handled-by-app", 2222 { 0, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2223 REQ_PLAIN }, 2224 { "listen-socket-option-invalid-fd", 2225 { 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0 }, 2226 REQ_PLAIN }, 2227 2228 /* ---- inputs whose daemon must not start ---- */ 2229 /* Raw flag escape: MHD_USE_POLL together with MHD_USE_EPOLL. */ 2230 { "raw-flags-poll-and-epoll", 2231 { 0, 0x40, 0xC0 | 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2232 REQ_PLAIN }, 2233 /* Raw flag escape: MHD_USE_EPOLL with MHD_USE_THREAD_PER_CONNECTION. */ 2234 { "raw-flags-epoll-thread-per-conn", 2235 { 0, 0x04 | 0x08, 0xC0 | 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2236 REQ_PLAIN }, 2237 /* An option number MHD does not know. */ 2238 { "invalid-option-number", 2239 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0 }, 2240 REQ_PLAIN }, 2241 /* MHD_OPTION_THREAD_POOL_SIZE without an internal polling thread. */ 2242 { "thread-pool-without-threads", 2243 { 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 2244 REQ_PLAIN }, 2245 2246 /* ---- the handler behaviours ---- */ 2247 { "handler-returns-no", 2248 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04, 0, 0 }, 2249 REQ_PLAIN }, 2250 { "empty-and-copied-responses", 2251 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 | 0x08, 0, 0 }, 2252 REQ_CHUNKED }, 2253 { "error-response", 2254 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0, 0 }, 2255 REQ_POST }, 2256 2257 /* ---- everything at once ---- */ 2258 { "kitchen-sink-external", 2259 { 0, 0x02 | 0x04 | 0x10 | 0x20 | 0x40, 0x01, 2260 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x80, 2261 0x02 | 0x10 | 0x20 | 0x40 | 0x80, 2262 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20, 2263 0x63, 0x45, 0x21, 0x13, 0x02, 0x0A, 2264 0x01 | 0x04 | 0x08 | 0x20, 0x08, 0x01 | 0x02 | 0x04 | 0x10, 0x33 }, 2265 REQ_POST }, 2266 { "kitchen-sink-thread-pool", 2267 { 18, 0x02 | 0x10 | 0x20 | 0x40, 0x01, 2268 0x01 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, 2269 0x01 | 0x02 | 0x80, 2270 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20, 2271 0x03, 0x46, 0x39, 0x02, 0x00, 0x0A, 2272 0x04 | 0x08, 0x00, 0x01 | 0x08, 0x22 }, 2273 REQ_CLOSE } 2274 }; 2275 2276 static uint8_t seed_render_buf[1024]; 2277 2278 2279 static size_t 2280 fuzz_seed_count (void) 2281 { 2282 return sizeof (seeds) / sizeof (seeds[0]); 2283 } 2284 2285 2286 static const uint8_t * 2287 fuzz_seed_get (size_t idx, 2288 size_t *len) 2289 { 2290 const struct seed_def *sd = &seeds[idx]; 2291 struct sbuf b; 2292 2293 b.p = seed_render_buf; 2294 b.len = 0; 2295 b.cap = sizeof (seed_render_buf); 2296 sb_raw (&b, sd->cfg, CFG_BYTES); 2297 if (NULL != sd->req) 2298 { 2299 size_t n = strlen (sd->req); 2300 unsigned int hv; 2301 uint8_t hdr[2]; 2302 2303 if (n > 0x3FFF) 2304 n = 0x3FFF; 2305 hv = (0u << 14) | (unsigned int) n; 2306 hdr[0] = (uint8_t) (hv & 0xFF); 2307 hdr[1] = (uint8_t) (hv >> 8); 2308 sb_raw (&b, hdr, 2); 2309 sb_raw (&b, sd->req, n); 2310 } 2311 *len = b.len; 2312 return seed_render_buf; 2313 }