fuzz_eventloop.c (61619B)
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_eventloop.c 22 * @brief In-process fuzzer for MHD's external event loop and for the 23 * scheduling of the connection life cycle. 24 * @author Christian Grothoff 25 * 26 * fuzz_request.c already touches these entry points, but only as a side 27 * channel: it picks one event-loop mode per iteration and then always 28 * pumps in the same rhythm. The bugs this harness is after are in the 29 * *scheduling* -- what MHD does when the application polls at adversarial 30 * times, ignores the timeout it was given, calls MHD_run_from_select() 31 * with descriptor sets that do not match what MHD asked for, or 32 * suspends/resumes connections across those calls. 33 * 34 * The input is therefore not an HTTP request but a *schedule*: a short 35 * configuration block followed by a program of one-byte opcodes that is 36 * interpreted against a live `struct MHD_Daemon` with up to 37 * #MAX_CONNS socketpair connections. Request bytes enter the program 38 * through two of those opcodes (a fragment table and a raw literal), so 39 * the parser is still driven, just not fuzzed. 40 * 41 * Input format 42 * ------------ 43 * 44 * byte 0 daemon configuration 45 * bits 0-1 MHD_OPTION_CONNECTION_TIMEOUT selector, 46 * index into {1, 2, 0, 1} seconds 47 * bit 2 give the daemon a real listening socket (port 0) 48 * instead of MHD_USE_NO_LISTEN_SOCKET, so that 49 * MHD_quiesce_daemon() has something to do and the 50 * listen FD shows up in the descriptor sets 51 * bit 3 pass MHD_OPTION_APP_FD_SETSIZE 52 * bits 4-5 MHD_OPTION_CONNECTION_MEMORY_LIMIT selector, 53 * index into {default, 256, 1024, 4096} 54 * bit 6 MHD_OPTION_CONNECTION_LIMIT = 2, so that 55 * MHD_add_connection() starts failing 56 * bit 7 shrink SO_SNDBUF/SO_RCVBUF of the socketpair, so 57 * that responses do not fit and connections stay 58 * blocked on write 59 * byte 1 access-handler behaviour 60 * bits 0-1 response kind: 0 small static buffer, 61 * 1 chunked callback (MHD_SIZE_UNKNOWN), 62 * 2 large (128 KiB) static buffer, 3 empty 63 * bit 2 answer 500 instead of 200 64 * bit 3 suspend in the handler and leave it parked 65 * bit 4 suspend and resume immediately in the handler 66 * bit 5 call MHD_set_connection_option() from the handler 67 * bit 6 call MHD_get_connection_info() from the handler 68 * bit 7 drain the client side after every run 69 * byte 2 event-loop defaults 70 * bits 0-2 default MHD_get_fdset*() variant 71 * bits 3-4 default run entry point 72 * bit 5 honour the timeout MHD returns 73 * bit 6 query the timeouts after every run 74 * bit 7 MHD_quiesce_daemon() before stopping 75 * byte 3 schedule knobs 76 * bits 0-1 number of connections opened up front (1-4) 77 * bit 2 run the timeout oracle after every operation 78 * bit 3 allow a real-time wait for a connection timeout 79 * to expire (globally budgeted, see below) 80 * bits 4-7 unused 81 * byte 4 artificial-clock step base 82 * byte 5. the operation program. Each operation is one byte, 83 * `(opcode << 4) | argument`; see enum op below. OP_SEND_RAW 84 * is the only one with an operand: a length byte followed by 85 * that many payload bytes. 86 * 87 * An input shorter than five bytes is rejected: the configuration block 88 * is mandatory and an input that short carries no program either. 89 * 90 * Oracles 91 * ------- 92 * 93 * Beyond ASAN/UBSAN and the MHD_set_panic_func() tripwire (any 94 * MHD_PANIC() reached this way is a finding, including the 95 * "MHD_stop_daemon() called while we have suspended connections" one 96 * that answers the "the daemon must always be stoppable" requirement): 97 * 98 * a) the four timeout accessors must agree. MHD_get_timeout(), 99 * MHD_get_timeout64(), MHD_get_timeout64s() and MHD_get_timeout_i() 100 * read the same state, so either all of them report a timeout or 101 * none of them does. Their values are read in sequence, so the 102 * clock may advance between two of them and the value may only 103 * *decrease*; connection_get_wait() has a documented 100 ms floor 104 * for the "exact match" case, hence the 100 ms slack. 105 * 106 * b) a reported timeout must never exceed the largest connection 107 * timeout in effect. MHD only ever derives it from 108 * `last_activity + connection_timeout_ms`, so a larger value would 109 * mean the deadline is somewhere the application cannot reach. 110 * 111 * c) MHD must never ask the application to wait forever while it has a 112 * live, not-suspended connection with a non-zero timeout: that is 113 * precisely the "timeout in the past" situation, i.e. a connection 114 * that can never be reaped. Live connections are tracked through 115 * MHD_OPTION_NOTIFY_CONNECTION, which brackets exactly the interval 116 * in which MHD owns the connection object. 117 * 118 * Both inputs of (b) and (c) -- whether a connection is suspended and 119 * what its timeout is -- are read back from MHD rather than modelled, 120 * because both diverge from what the application asked for: 121 * MHD_set_connection_option() silently does nothing while a 122 * connection is suspended. A harness that models them ends up 123 * reporting findings against its own model. 124 * 125 * d) MHD_get_fdset*() must not set a descriptor at or above the 126 * FD_SETSIZE limit it was given, `*max_fd` must be at least as large 127 * as every descriptor that was added, and `*max_fd` itself must be 128 * one of them. 129 * 130 * e) after MHD_quiesce_daemon() the listening socket must be gone from 131 * the descriptor sets. 132 * 133 * Two contract rules the harness has to respect (violating either makes 134 * MHD abort on a schedule that is perfectly legal, so the harness would 135 * only be finding its own bugs): 136 * 137 * * a connection is only suspended when the access handler is about to 138 * return MHD_YES. MHD_NO asks MHD to terminate the connection, and 139 * terminating one that the same callback just suspended trips 140 * mhd_assert (! connection->suspended) in MHD_connection_close_(); 141 * 142 * * every suspended connection is resumed before MHD_stop_daemon(). 143 * Several connections can be parked at once, so this is a set 144 * (@e lives[i].susp), not a single slot, and @e tearing_down stops 145 * the handler from parking anything new while the set is drained. 146 * 147 * MHD_suspend_connection() is additionally only called when MHD does not 148 * already consider the connection suspended, *unless* a resume of it is 149 * still pending -- that is the one case internal_suspend_connection_() 150 * handles itself (it cancels the resume), and the harness mirrors the 151 * resulting state. Calling it on an already-suspended connection would 152 * unlink it from a list it is not on. 153 * 154 * One more trap: with MHD_USE_ITC -- which MHD_ALLOW_SUSPEND_RESUME 155 * implies, so this harness always has it -- MHD_add_connection() only 156 * *queues* the socket, and the `struct MHD_Connection` is created later, 157 * from inside a run. There is therefore no moment at which the 158 * application could pair its own socket up with the connection object, 159 * and the registry of live connections has to be built purely from 160 * MHD_OPTION_NOTIFY_CONNECTION. This is why the client sockets 161 * (@e csock) and the connections (@e lives) are two separate arrays. 162 * 163 * Note on MHD_get_timeout_expiration(): no such function exists in the 164 * MHD 1.x API. The four accessors above are the complete family; the 165 * absolute-deadline form is a MHD 2.x addition. 166 */ 167 168 #define FUZZ_HARNESS_NAME "fuzz_eventloop" 169 #include "fuzz_common.h" 170 171 #include <microhttpd.h> 172 #include <sys/socket.h> 173 #include <netinet/in.h> 174 #include <sys/select.h> 175 #include <limits.h> 176 177 /** Largest number of connections a single iteration may have open. */ 178 #define MAX_CONNS 8 179 180 /** Upper bound on the number of operations interpreted per iteration. */ 181 #define MAX_OPS 400 182 183 /** Size of the "large response" body. */ 184 #define BIG_BODY_LEN 131072 185 186 /** Bytes read back from the daemon are counted, never inspected. */ 187 #define DRAIN_BUF 4096 188 189 190 /* ------------------------------------------------------------------ */ 191 /* Per-iteration configuration */ 192 /* ------------------------------------------------------------------ */ 193 194 struct el_cfg 195 { 196 unsigned int timeout_s; /**< MHD_OPTION_CONNECTION_TIMEOUT */ 197 int listen_sock; /**< real listening socket wanted */ 198 int app_fd_setsize; /**< pass MHD_OPTION_APP_FD_SETSIZE */ 199 size_t mem_limit; /**< MHD_OPTION_CONNECTION_MEMORY_LIMIT */ 200 int conn_limit; /**< MHD_OPTION_CONNECTION_LIMIT = 2 */ 201 int small_sockbuf; /**< shrink the socketpair buffers */ 202 203 unsigned int resp_kind; /**< which response the handler queues */ 204 int error_reply; /**< answer 500 instead of 200 */ 205 int susp_park; /**< handler suspends and leaves it parked */ 206 int susp_now; /**< handler suspends and resumes at once */ 207 int hnd_connopt; /**< handler calls set_connection_option */ 208 int hnd_info; /**< handler calls get_connection_info */ 209 int auto_drain; /**< drain the client sockets after a run */ 210 211 unsigned int fdset_var; /**< default MHD_get_fdset*() variant */ 212 unsigned int run_var; /**< default run entry point */ 213 int honour_timeout; /**< act on the timeout MHD returns */ 214 int timeout_every_run; /**< query the timeouts after every run */ 215 int quiesce_end; /**< quiesce before stopping */ 216 217 unsigned int nconn_up_front; /**< connections opened before the program */ 218 int check_always; /**< run the timeout oracle after every op */ 219 int allow_real_wait; /**< may burn real time on a timeout expiry */ 220 uint8_t clock_seed; /**< artificial-clock step base */ 221 }; 222 223 static struct el_cfg cfg; 224 225 /** Connection memory limits selectable by byte 0. */ 226 static const size_t mem_limit_tbl[] = { 0, 256, 1024, 4096 }; 227 228 /** Connection timeouts (seconds) selectable by byte 0. */ 229 static const unsigned int timeout_tbl[] = { 1, 2, 0, 1 }; 230 231 /** 232 * FD_SETSIZE values handed to MHD_get_fdset2()/MHD_run_from_select2(). 233 * 234 * All of them are <= FD_SETSIZE on purpose. Passing a *larger* value 235 * than the `fd_set` objects actually hold would let MHD write past them, 236 * which is the application lying about its own buffers rather than 237 * anything MHD could defend against; the interesting direction is the 238 * smaller one, where MHD has to refuse descriptors that do not fit. 239 */ 240 static const unsigned int setsize_tbl[] = { 241 (unsigned int) FD_SETSIZE, 242 (unsigned int) FD_SETSIZE, 243 (unsigned int) FD_SETSIZE / 2, 244 64, 16, 4, 1, (unsigned int) FD_SETSIZE 245 }; 246 247 248 /* ------------------------------------------------------------------ */ 249 /* Per-iteration state */ 250 /* ------------------------------------------------------------------ */ 251 252 /** 253 * The client end of one socketpair. Deliberately *not* tied to a 254 * `struct MHD_Connection`: with MHD_USE_ITC (which 255 * MHD_ALLOW_SUSPEND_RESUME implies) MHD_add_connection() only queues the 256 * socket and the connection object is created later, from inside a run. 257 * There is therefore no moment at which the harness could pair the two 258 * up, and trying to would silently mistrack every connection. 259 */ 260 static int csock[MAX_CONNS]; 261 static unsigned int nconns; 262 static unsigned int cur_conn; 263 264 /** 265 * A connection MHD currently owns. 266 * 267 * The registry is maintained purely from MHD_OPTION_NOTIFY_CONNECTION, 268 * which brackets exactly the interval in which the object exists: after 269 * MHD_CONNECTION_NOTIFY_CLOSED nothing may reference it any more, in 270 * particular not a deferred resume and not the "is there a live 271 * connection" oracle. 272 */ 273 struct live_conn 274 { 275 struct MHD_Connection *mc; /**< NULL if the slot is free */ 276 int susp; /**< suspended by us, not resumed yet */ 277 }; 278 279 /** A few more slots than connections, so the registry cannot overflow. */ 280 #define MAX_LIVE (MAX_CONNS + 4) 281 282 static struct live_conn lives[MAX_LIVE]; 283 284 /** Daemon of the current iteration. */ 285 static struct MHD_Daemon *cur_daemon; 286 287 /** 288 * Set once the iteration only wants to drain the daemon. The handler 289 * then stops parking connections, which is what makes the flush loop in 290 * the teardown terminate. 291 */ 292 static int tearing_down; 293 294 /** Listening socket returned by MHD_quiesce_daemon(), ours to close. */ 295 static MHD_socket quiesced_fd = MHD_INVALID_SOCKET; 296 297 /** Artificial clock; only the harness's own scheduling depends on it. */ 298 static uint64_t clk_ms; 299 static uint64_t deadline_ms; 300 static int deadline_valid; 301 302 /** Descriptor sets collected by the last OP_FDSET. */ 303 static fd_set g_rs; 304 static fd_set g_ws; 305 static fd_set g_es; 306 static MHD_socket g_max_fd = MHD_INVALID_SOCKET; 307 static unsigned int g_setsize = (unsigned int) FD_SETSIZE; 308 static int g_have_sets; 309 310 /** The large response body, filled once. */ 311 static char big_body[BIG_BODY_LEN]; 312 static int big_body_ready; 313 314 /** 315 * Budget for iterations that are allowed to wait in real time for a 316 * connection timeout to expire. MHD_OPTION_CONNECTION_TIMEOUT has a 317 * resolution of one second, so the expiry path cannot be reached without 318 * actually burning about that much wall clock; the budget keeps the 319 * whole run in the "couple of seconds" range while still exercising it. 320 * Override with MHD_FUZZ_EXPIRY_BUDGET. 321 */ 322 static int expiry_budget = 2; 323 static int expiry_budget_read; 324 325 /** Statistics, printed at exit with --verbose. */ 326 static unsigned long stat_daemons; 327 static unsigned long stat_handler_calls; 328 static unsigned long stat_fdset_v1; 329 static unsigned long stat_fdset_v2; 330 static unsigned long stat_rfs_v1; 331 static unsigned long stat_rfs_v2; 332 static unsigned long stat_run; 333 static unsigned long stat_run_wait; 334 static unsigned long stat_timeouts; 335 static unsigned long stat_quiesce; 336 static unsigned long stat_suspend; 337 static unsigned long stat_resume; 338 static unsigned long stat_expiry_waits; 339 static int stats_registered; 340 341 342 static void 343 print_stats (void) 344 { 345 if (! fuzz_verbose) 346 return; 347 fprintf (stderr, 348 "%s: daemons=%lu handler=%lu get_fdset=%lu get_fdset2=%lu " 349 "run_from_select=%lu run_from_select2=%lu run=%lu run_wait=%lu " 350 "timeout queries=%lu quiesce=%lu suspend=%lu resume=%lu " 351 "expiry waits=%lu\n", 352 FUZZ_HARNESS_NAME, 353 stat_daemons, stat_handler_calls, stat_fdset_v1, stat_fdset_v2, 354 stat_rfs_v1, stat_rfs_v2, stat_run, stat_run_wait, 355 stat_timeouts, stat_quiesce, stat_suspend, stat_resume, 356 stat_expiry_waits); 357 } 358 359 360 /* ------------------------------------------------------------------ */ 361 /* Callbacks */ 362 /* ------------------------------------------------------------------ */ 363 364 static void 365 panic_cb (void *cls, 366 const char *file, 367 unsigned int line, 368 const char *reason) 369 { 370 char msg[512]; 371 372 (void) cls; 373 (void) snprintf (msg, sizeof (msg), 374 "MHD_PANIC() reached from an event-loop schedule " 375 "at %s:%u: %s", 376 (NULL != file) ? file : "?", 377 line, 378 (NULL != reason) ? reason : "?"); 379 fuzz_report_finding (msg); 380 } 381 382 383 /** 384 * Find the registry slot of @a c, or -1. 385 */ 386 static int 387 slot_of (const struct MHD_Connection *c) 388 { 389 unsigned int i; 390 391 for (i = 0; i < MAX_LIVE; i++) 392 if ( (NULL != lives[i].mc) && 393 (lives[i].mc == c) ) 394 return (int) i; 395 return -1; 396 } 397 398 399 static void 400 notify_conn_cb (void *cls, 401 struct MHD_Connection *connection, 402 void **socket_context, 403 enum MHD_ConnectionNotificationCode toe) 404 { 405 unsigned int i; 406 int idx; 407 408 (void) cls; 409 (void) socket_context; 410 if (MHD_CONNECTION_NOTIFY_STARTED == toe) 411 { 412 for (i = 0; i < MAX_LIVE; i++) 413 { 414 if (NULL != lives[i].mc) 415 continue; 416 lives[i].mc = connection; 417 lives[i].susp = 0; 418 return; 419 } 420 return; 421 } 422 /* MHD_CONNECTION_NOTIFY_CLOSED: the object is about to be freed. */ 423 idx = slot_of (connection); 424 if (0 <= idx) 425 { 426 lives[idx].mc = NULL; 427 lives[idx].susp = 0; 428 } 429 } 430 431 432 /* ------------------------------------------------------------------ */ 433 /* Suspend / resume bookkeeping */ 434 /* ------------------------------------------------------------------ */ 435 436 /** 437 * Ask MHD whether it considers slot @a i suspended. 438 */ 439 static int 440 mhd_thinks_suspended (unsigned int i) 441 { 442 const union MHD_ConnectionInfo *ci; 443 444 if (NULL == lives[i].mc) 445 return 0; 446 ci = MHD_get_connection_info (lives[i].mc, 447 MHD_CONNECTION_INFO_CONNECTION_SUSPENDED); 448 if (NULL == ci) 449 return 0; 450 return (MHD_YES == ci->suspended); 451 } 452 453 454 /** 455 * Suspend slot @a i, if that is legal right now. 456 * 457 * MHD_suspend_connection() unlinks the connection from the timeout and 458 * connection lists, so calling it on a connection MHD already has on the 459 * suspended list corrupts those lists. The one exception is a 460 * connection with a resume still pending: internal_suspend_connection_() 461 * detects that itself and merely cancels the resume, leaving the 462 * connection suspended -- which is why @e susp is set in both branches. 463 */ 464 static void 465 do_suspend (unsigned int i) 466 { 467 int mhd_susp; 468 469 if ( (i >= MAX_LIVE) || 470 (NULL == lives[i].mc) ) 471 return; 472 mhd_susp = mhd_thinks_suspended (i); 473 if (mhd_susp && lives[i].susp) 474 return; /* really suspended already */ 475 MHD_suspend_connection (lives[i].mc); 476 lives[i].susp = 1; 477 stat_suspend++; 478 } 479 480 481 static void 482 do_resume (unsigned int i) 483 { 484 if ( (i >= MAX_LIVE) || 485 (NULL == lives[i].mc) || 486 (! lives[i].susp) ) 487 return; 488 /* Clear first: MHD_resume_connection() may end up running the handler 489 later, which is allowed to suspend the very same connection again. */ 490 lives[i].susp = 0; 491 MHD_resume_connection (lives[i].mc); 492 stat_resume++; 493 } 494 495 496 /** 497 * Resume everything still parked. 498 * 499 * @return non-zero if at least one connection was resumed, so that the 500 * caller knows the daemon needs another round to act on it 501 */ 502 static int 503 resume_all (void) 504 { 505 unsigned int i; 506 int any = 0; 507 508 for (i = 0; i < MAX_LIVE; i++) 509 { 510 if ( (NULL == lives[i].mc) || 511 (! lives[i].susp) ) 512 continue; 513 lives[i].susp = 0; 514 MHD_resume_connection (lives[i].mc); 515 stat_resume++; 516 any = 1; 517 } 518 return any; 519 } 520 521 522 /** 523 * Summarise the connections MHD currently owns. 524 * 525 * Both properties are read back from MHD rather than modelled: a 526 * connection leaves the timeout lists exactly when MHD sets 527 * `connection->suspended`, and its timeout is exactly what 528 * MHD_set_connection_option() left there -- which is *not* what the 529 * application passed if the connection happened to be suspended at the 530 * time. Modelling either of them means the oracle eventually fires on 531 * the model rather than on MHD. 532 * 533 * @param[out] max_ms largest timeout, in milliseconds, of the 534 * connections that are in a timeout list right now 535 * @return non-zero if at least one such connection exists, i.e. if MHD 536 * must report a timeout 537 */ 538 static int 539 scan_live_timeouts (uint64_t *max_ms) 540 { 541 unsigned int i; 542 int any = 0; 543 544 *max_ms = 0; 545 for (i = 0; i < MAX_LIVE; i++) 546 { 547 const union MHD_ConnectionInfo *ci; 548 uint64_t ms; 549 550 if (NULL == lives[i].mc) 551 continue; 552 ci = MHD_get_connection_info (lives[i].mc, 553 MHD_CONNECTION_INFO_CONNECTION_SUSPENDED); 554 if ( (NULL != ci) && 555 (MHD_YES == ci->suspended) ) 556 continue; /* not in any timeout list */ 557 ci = MHD_get_connection_info (lives[i].mc, 558 MHD_CONNECTION_INFO_CONNECTION_TIMEOUT); 559 if (NULL == ci) 560 continue; 561 ms = ((uint64_t) ci->connection_timeout) * 1000; 562 if (0 == ms) 563 continue; /* in a list, but exempt from timeouts */ 564 any = 1; 565 if (ms > *max_ms) 566 *max_ms = ms; 567 } 568 return any; 569 } 570 571 572 /* ------------------------------------------------------------------ */ 573 /* The access handler */ 574 /* ------------------------------------------------------------------ */ 575 576 struct crc_state 577 { 578 uint64_t total; 579 unsigned int pattern; 580 }; 581 582 583 static ssize_t 584 crc_cb (void *cls, 585 uint64_t pos, 586 char *buf, 587 size_t max) 588 { 589 struct crc_state *st = (struct crc_state *) cls; 590 size_t n; 591 size_t i; 592 593 if (pos >= st->total) 594 return MHD_CONTENT_READER_END_OF_STREAM; 595 n = (size_t) (st->total - pos); 596 if (n > max) 597 n = max; 598 if (0 == n) 599 return MHD_CONTENT_READER_END_OF_STREAM; 600 for (i = 0; i < n; i++) 601 buf[i] = (char) ('a' + (int) ((pos + i + st->pattern) % 26)); 602 return (ssize_t) n; 603 } 604 605 606 static void 607 crc_free (void *cls) 608 { 609 free (cls); 610 } 611 612 613 static struct MHD_Response * 614 make_response (void) 615 { 616 struct crc_state *st; 617 struct MHD_Response *r; 618 619 switch (cfg.resp_kind) 620 { 621 case 1: 622 st = (struct crc_state *) calloc (1, sizeof (struct crc_state)); 623 if (NULL == st) 624 return NULL; 625 st->total = 700; 626 st->pattern = cfg.clock_seed; 627 r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 628 128, 629 &crc_cb, 630 st, 631 &crc_free); 632 if (NULL == r) 633 free (st); 634 return r; 635 case 2: 636 /* Large enough not to fit into the socket buffers, so that the 637 connection stays blocked on write and MHD has to schedule it 638 through the write descriptor set over several rounds. */ 639 return MHD_create_response_from_buffer_static (BIG_BODY_LEN, big_body); 640 case 3: 641 return MHD_create_response_empty (MHD_RF_NONE); 642 default: 643 return MHD_create_response_from_buffer_static (2, "ok"); 644 } 645 } 646 647 648 static enum MHD_Result 649 ahc (void *cls, 650 struct MHD_Connection *connection, 651 const char *url, 652 const char *method, 653 const char *version, 654 const char *upload_data, 655 size_t *upload_data_size, 656 void **req_cls) 657 { 658 struct MHD_Response *resp; 659 enum MHD_Result ret; 660 int idx; 661 662 (void) cls; 663 (void) url; 664 (void) method; 665 (void) version; 666 (void) upload_data; 667 if (NULL == *req_cls) 668 { 669 *req_cls = (void *) (intptr_t) 1; 670 return MHD_YES; 671 } 672 stat_handler_calls++; 673 if (0 != *upload_data_size) 674 { 675 *upload_data_size = 0; 676 return MHD_YES; 677 } 678 679 idx = slot_of (connection); 680 if (cfg.hnd_connopt) 681 { 682 /* Moves the connection between the "normal" and the "manual" timeout 683 list, i.e. changes which connection MHD_get_timeout*() reports. */ 684 unsigned int nt = (0 == cfg.timeout_s) ? 1u : (cfg.timeout_s + 1u); 685 686 (void) MHD_set_connection_option (connection, 687 MHD_CONNECTION_OPTION_TIMEOUT, 688 nt); 689 } 690 if (cfg.hnd_info) 691 { 692 volatile size_t sink = 0; 693 const union MHD_ConnectionInfo *ci; 694 695 ci = MHD_get_connection_info (connection, 696 MHD_CONNECTION_INFO_CONNECTION_FD); 697 if (NULL != ci) 698 sink += (size_t) (ci->connect_fd + 1); 699 ci = MHD_get_connection_info (connection, 700 MHD_CONNECTION_INFO_CONNECTION_TIMEOUT); 701 if (NULL != ci) 702 sink += (size_t) ci->connection_timeout; 703 (void) sink; 704 } 705 706 resp = make_response (); 707 if (NULL == resp) 708 return MHD_NO; 709 ret = MHD_queue_response (connection, 710 cfg.error_reply 711 ? MHD_HTTP_INTERNAL_SERVER_ERROR : MHD_HTTP_OK, 712 resp); 713 MHD_destroy_response (resp); 714 if (MHD_YES != ret) 715 return ret; 716 /* Only once the response was accepted: returning MHD_NO tells MHD to 717 terminate the connection, and terminating one that this very callback 718 suspended trips mhd_assert (! connection->suspended) in 719 MHD_connection_close_(). */ 720 if (tearing_down || 721 (0 > idx)) 722 return ret; 723 if (cfg.susp_now) 724 { 725 MHD_suspend_connection (connection); 726 MHD_resume_connection (connection); 727 stat_suspend++; 728 stat_resume++; 729 } 730 else if (cfg.susp_park && 731 (! lives[idx].susp)) 732 { 733 MHD_suspend_connection (connection); 734 lives[idx].susp = 1; 735 stat_suspend++; 736 } 737 return ret; 738 } 739 740 741 /* ------------------------------------------------------------------ */ 742 /* Oracles */ 743 /* ------------------------------------------------------------------ */ 744 745 /** 746 * Query all four timeout accessors and cross-check them. 747 * 748 * The values are read one after the other, so the monotonic clock may 749 * advance in between and a later reading may be *smaller*. It may never 750 * be larger, except for the 100 ms floor connection_get_wait() falls back 751 * to when the elapsed time exactly matches the timeout. 752 */ 753 static void 754 check_timeouts (struct MHD_Daemon *d) 755 { 756 MHD_UNSIGNED_LONG_LONG tl = 0; 757 uint64_t t64 = 0; 758 int64_t t64s; 759 int ti; 760 enum MHD_Result r1; 761 enum MHD_Result r2; 762 int have[4]; 763 uint64_t val[4]; 764 unsigned int k; 765 uint64_t max_ms; 766 int any_timed; 767 char msg[256]; 768 769 stat_timeouts++; 770 r1 = MHD_get_timeout (d, &tl); 771 r2 = MHD_get_timeout64 (d, &t64); 772 t64s = MHD_get_timeout64s (d); 773 ti = MHD_get_timeout_i (d); 774 775 have[0] = (MHD_YES == r1); 776 have[1] = (MHD_YES == r2); 777 have[2] = (0 <= t64s); 778 have[3] = (0 <= ti); 779 val[0] = (uint64_t) tl; 780 val[1] = t64; 781 val[2] = (uint64_t) (t64s < 0 ? 0 : t64s); 782 val[3] = (uint64_t) (ti < 0 ? 0 : ti); 783 784 for (k = 1; k < 4; k++) 785 if (have[k] != have[0]) 786 fuzz_report_finding ( 787 "MHD_get_timeout*(): the four accessors disagree about whether " 788 "a timeout is in effect"); 789 790 any_timed = scan_live_timeouts (&max_ms); 791 if (! have[0]) 792 { 793 /* An indefinite wait while a live, not-suspended connection has a 794 non-zero timeout means that connection can never be reaped: its 795 deadline is already unreachable for the application. */ 796 if (any_timed) 797 fuzz_report_finding ( 798 "MHD_get_timeout*() reported no timeout although the daemon has a " 799 "live, not suspended connection with a non-zero timeout"); 800 deadline_valid = 0; 801 return; 802 } 803 804 for (k = 0; k < 4; k++) 805 { 806 if (val[k] <= max_ms) 807 continue; 808 (void) snprintf (msg, sizeof (msg), 809 "MHD_get_timeout*() [accessor %u] returned %llu ms, " 810 "larger than the largest connection timeout in effect " 811 "(%llu ms)", 812 k, 813 (unsigned long long) val[k], 814 (unsigned long long) max_ms); 815 fuzz_report_finding (msg); 816 } 817 for (k = 1; k < 4; k++) 818 if ( (val[k] > val[k - 1]) && 819 (val[k] > 100) ) 820 fuzz_report_finding ( 821 "MHD_get_timeout*(): a later accessor reported a larger timeout " 822 "than an earlier one, although the deadline cannot have moved"); 823 824 deadline_ms = clk_ms + val[1]; 825 deadline_valid = 1; 826 } 827 828 829 /** 830 * Check the descriptor sets that the last MHD_get_fdset*() produced. 831 * 832 * @param setsize the FD_SETSIZE limit that was passed to MHD 833 * @param max_fd the reported maximum, #MHD_INVALID_SOCKET if none 834 * @param had_max whether a @a max_fd pointer was passed at all 835 * @param with_es whether an except set was passed 836 */ 837 static void 838 check_fdsets (unsigned int setsize, 839 MHD_socket max_fd, 840 int had_max, 841 int with_es) 842 { 843 int f; 844 int hi = -1; 845 int max_seen = 0; 846 847 for (f = 0; f < (int) FD_SETSIZE; f++) 848 { 849 int in_set = FD_ISSET (f, &g_rs) || FD_ISSET (f, &g_ws); 850 851 if (with_es && FD_ISSET (f, &g_es)) 852 in_set = 1; 853 if (! in_set) 854 continue; 855 if ((unsigned int) f >= setsize) 856 fuzz_report_finding ( 857 "MHD_get_fdset*() added a descriptor at or above the FD_SETSIZE " 858 "limit it was given"); 859 if (f > hi) 860 hi = f; 861 if ( (had_max) && 862 (MHD_INVALID_SOCKET != max_fd) && 863 (f == (int) max_fd) ) 864 max_seen = 1; 865 } 866 if (! had_max) 867 return; 868 if (0 > hi) 869 { 870 if (MHD_INVALID_SOCKET != max_fd) 871 fuzz_report_finding ( 872 "MHD_get_fdset*() set max_fd although it added no descriptor"); 873 return; 874 } 875 if (MHD_INVALID_SOCKET == max_fd) 876 fuzz_report_finding ( 877 "MHD_get_fdset*() added descriptors but left max_fd unset"); 878 if (hi > (int) max_fd) 879 fuzz_report_finding ( 880 "MHD_get_fdset*() added a descriptor larger than the max_fd it " 881 "reported"); 882 if ((unsigned int) max_fd >= setsize) 883 fuzz_report_finding ( 884 "MHD_get_fdset*() reported a max_fd at or above the FD_SETSIZE " 885 "limit it was given"); 886 if (! max_seen) 887 fuzz_report_finding ( 888 "MHD_get_fdset*() reported a max_fd that is not in any of the sets"); 889 } 890 891 892 /* ------------------------------------------------------------------ */ 893 /* Event-loop primitives */ 894 /* ------------------------------------------------------------------ */ 895 896 /** 897 * Collect the descriptor sets. 898 * 899 * Variant 0 goes through the *real* v1 entry point. microhttpd.h also 900 * defines MHD_get_fdset as a macro forwarding to MHD_get_fdset2 with 901 * FD_SETSIZE, so the name has to be parenthesised or the v1 function is 902 * never reached at all. Same trick for MHD_run_from_select below. 903 */ 904 static void 905 op_fdset (struct MHD_Daemon *d, 906 unsigned int var) 907 { 908 MHD_socket max_fd = MHD_INVALID_SOCKET; 909 unsigned int setsize = (unsigned int) FD_SETSIZE; 910 int had_max = 1; 911 int with_es = 1; 912 913 FD_ZERO (&g_rs); 914 FD_ZERO (&g_ws); 915 FD_ZERO (&g_es); 916 switch (var % 5) 917 { 918 case 0: 919 stat_fdset_v1++; 920 (void) (MHD_get_fdset) (d, &g_rs, &g_ws, &g_es, &max_fd); 921 break; 922 case 1: 923 stat_fdset_v2++; 924 (void) MHD_get_fdset2 (d, &g_rs, &g_ws, &g_es, &max_fd, 925 (unsigned int) FD_SETSIZE); 926 break; 927 case 2: 928 stat_fdset_v2++; 929 setsize = setsize_tbl[(var + cfg.clock_seed) 930 % (sizeof (setsize_tbl) 931 / sizeof (setsize_tbl[0]))]; 932 (void) MHD_get_fdset2 (d, &g_rs, &g_ws, &g_es, &max_fd, setsize); 933 break; 934 case 3: 935 /* max_fd is documented as optional */ 936 stat_fdset_v2++; 937 had_max = 0; 938 (void) MHD_get_fdset2 (d, &g_rs, &g_ws, &g_es, NULL, 939 (unsigned int) FD_SETSIZE); 940 break; 941 default: 942 /* no except set: deprecated, but shipped API */ 943 stat_fdset_v2++; 944 with_es = 0; 945 (void) MHD_get_fdset2 (d, &g_rs, &g_ws, NULL, &max_fd, 946 (unsigned int) FD_SETSIZE); 947 break; 948 } 949 check_fdsets (setsize, max_fd, had_max, with_es); 950 g_max_fd = max_fd; 951 g_setsize = setsize; 952 g_have_sets = 1; 953 if ( (MHD_INVALID_SOCKET != quiesced_fd) && 954 ((unsigned int) quiesced_fd < (unsigned int) FD_SETSIZE) && 955 FD_ISSET (quiesced_fd, &g_rs) ) 956 fuzz_report_finding ( 957 "MHD_get_fdset*() still watches the listening socket after " 958 "MHD_quiesce_daemon() handed it back to the application"); 959 } 960 961 962 /** 963 * select() on the sets collected last, with a zero timeout. 964 * 965 * The harness is single threaded and everything MHD could be waiting for 966 * has already been written into the socketpairs, so blocking would only 967 * burn wall clock; select() is called purely to fill in the readiness. 968 */ 969 static void 970 op_poll (void) 971 { 972 struct timeval tv; 973 974 if ( (! g_have_sets) || 975 (MHD_INVALID_SOCKET == g_max_fd) ) 976 return; 977 tv.tv_sec = 0; 978 tv.tv_usec = 0; 979 (void) select ((int) g_max_fd + 1, &g_rs, &g_ws, &g_es, &tv); 980 } 981 982 983 /** 984 * Drain whatever the daemon has produced on slot @a i, so that a large 985 * response can make progress. 986 */ 987 static void 988 drain_conn (unsigned int i) 989 { 990 char tmp[DRAIN_BUF]; 991 992 if ( (i >= MAX_CONNS) || 993 (0 > csock[i]) ) 994 return; 995 for (;;) 996 { 997 ssize_t n = recv (csock[i], tmp, sizeof (tmp), MSG_DONTWAIT); 998 999 if (0 >= n) 1000 break; 1001 } 1002 } 1003 1004 1005 static void 1006 drain_all (void) 1007 { 1008 unsigned int i; 1009 1010 for (i = 0; i < MAX_CONNS; i++) 1011 drain_conn (i); 1012 } 1013 1014 1015 /** 1016 * Advance the daemon once. 1017 * 1018 * @param d the daemon 1019 * @param var which entry point to use 1020 * @param flavour which descriptor sets to hand over: 1021 * 0 the ones MHD asked for, 1 all-zero, 2 all-ones, 1022 * 3 only the read set as collected 1023 */ 1024 static void 1025 op_run (struct MHD_Daemon *d, 1026 unsigned int var, 1027 unsigned int flavour) 1028 { 1029 fd_set rs; 1030 fd_set ws; 1031 fd_set es; 1032 1033 switch (flavour % 4) 1034 { 1035 case 1: 1036 FD_ZERO (&rs); 1037 FD_ZERO (&ws); 1038 FD_ZERO (&es); 1039 break; 1040 case 2: 1041 /* Every descriptor number reported ready. MHD only tests the bits of 1042 the sockets it owns, so this is an application that lies about 1043 readiness, not an invalid descriptor. */ 1044 memset (&rs, 0xFF, sizeof (rs)); 1045 memset (&ws, 0xFF, sizeof (ws)); 1046 memset (&es, 0xFF, sizeof (es)); 1047 break; 1048 case 3: 1049 rs = g_rs; 1050 FD_ZERO (&ws); 1051 FD_ZERO (&es); 1052 break; 1053 default: 1054 rs = g_rs; 1055 ws = g_ws; 1056 es = g_es; 1057 break; 1058 } 1059 switch (var % 4) 1060 { 1061 case 0: 1062 stat_rfs_v1++; 1063 (void) (MHD_run_from_select) (d, &rs, &ws, &es); 1064 break; 1065 case 1: 1066 stat_rfs_v2++; 1067 (void) MHD_run_from_select2 (d, &rs, &ws, &es, 1068 (g_setsize > (unsigned int) FD_SETSIZE) 1069 ? (unsigned int) FD_SETSIZE : g_setsize); 1070 break; 1071 case 2: 1072 stat_run++; 1073 (void) MHD_run (d); 1074 break; 1075 default: 1076 stat_run_wait++; 1077 (void) MHD_run_wait (d, 0); 1078 break; 1079 } 1080 deadline_valid = 0; 1081 if (cfg.auto_drain) 1082 drain_all (); 1083 if (cfg.timeout_every_run) 1084 check_timeouts (d); 1085 } 1086 1087 1088 /* ------------------------------------------------------------------ */ 1089 /* Connections */ 1090 /* ------------------------------------------------------------------ */ 1091 1092 static int 1093 new_connection (struct MHD_Daemon *d) 1094 { 1095 int sv[2]; 1096 struct sockaddr_in sa; 1097 unsigned int idx; 1098 1099 if (nconns >= MAX_CONNS) 1100 return -1; 1101 idx = nconns; 1102 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv)) 1103 return -1; 1104 if (cfg.small_sockbuf) 1105 { 1106 int bs = 2048; 1107 1108 (void) setsockopt (sv[0], SOL_SOCKET, SO_RCVBUF, &bs, sizeof (bs)); 1109 (void) setsockopt (sv[1], SOL_SOCKET, SO_SNDBUF, &bs, sizeof (bs)); 1110 } 1111 memset (&sa, 0, sizeof (sa)); 1112 sa.sin_family = AF_INET; 1113 sa.sin_port = htons (44444); 1114 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 1115 csock[idx] = sv[0]; 1116 if (MHD_YES != MHD_add_connection (d, 1117 (MHD_socket) sv[1], 1118 (const struct sockaddr *) &sa, 1119 (socklen_t) sizeof (sa))) 1120 { 1121 /* MHD has already closed sv[1] in that case. */ 1122 (void) close (sv[0]); 1123 csock[idx] = -1; 1124 return -1; 1125 } 1126 nconns++; 1127 cur_conn = idx; 1128 return (int) idx; 1129 } 1130 1131 1132 /** 1133 * Drop our end of connection @a i. 1134 * 1135 * @param graceful non-zero to shut the write side down first (an orderly 1136 * client close), zero to just close (an abrupt one, which MHD sees 1137 * as a reset) 1138 */ 1139 static void 1140 close_conn (unsigned int i, 1141 int graceful) 1142 { 1143 if ( (i >= MAX_CONNS) || 1144 (0 > csock[i]) ) 1145 return; 1146 if (graceful) 1147 (void) shutdown (csock[i], SHUT_WR); 1148 (void) close (csock[i]); 1149 csock[i] = -1; 1150 } 1151 1152 1153 static void 1154 send_bytes (unsigned int i, 1155 const void *buf, 1156 size_t len) 1157 { 1158 const char *p = (const char *) buf; 1159 size_t off = 0; 1160 unsigned int tries = 0; 1161 1162 if ( (i >= MAX_CONNS) || 1163 (0 > csock[i]) || 1164 (0 == len) ) 1165 return; 1166 while ( (off < len) && 1167 (tries < 4) ) 1168 { 1169 ssize_t s = send (csock[i], p + off, len - off, MSG_DONTWAIT); 1170 1171 if (0 < s) 1172 { 1173 off += (size_t) s; 1174 continue; 1175 } 1176 tries++; 1177 /* The peer's receive buffer is full because MHD has not run yet, or 1178 MHD is gone. One round is enough to tell the two apart; the rest 1179 of the fragment is simply dropped, which is a split point like any 1180 other. */ 1181 if (NULL != cur_daemon) 1182 (void) MHD_run (cur_daemon); 1183 if ( (0 > s) && 1184 (EAGAIN != errno) && 1185 (EWOULDBLOCK != errno) && 1186 (EINTR != errno) ) 1187 break; 1188 } 1189 } 1190 1191 1192 /** 1193 * Request fragments. Whole requests, halves of requests and pipelines, 1194 * so that a schedule can leave a connection in any parser state while it 1195 * plays with the event loop. 1196 */ 1197 static const char *const frag_tbl[16] = { 1198 "GET / HTTP/1.1\r\nHost: x\r\n\r\n", 1199 "GET /a HTTP/1.1\r\nHost: x\r\n", 1200 "\r\n", 1201 "POST /p HTTP/1.1\r\nHost: x\r\nContent-Length: 10\r\n\r\n", 1202 "0123456789", 1203 "POST /c HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\n\r\n", 1204 "5\r\nabcde\r\n", 1205 "0\r\n\r\n", 1206 "GET / HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n", 1207 "GET / HTTP/1.0\r\n\r\n", 1208 "HEAD / HTTP/1.1\r\nHost: x\r\n\r\n", 1209 "GET / HTTP/1.1\r\nHost: x\r\n\r\nGET /2 HTTP/1.1\r\nHost: x\r\n\r\n", 1210 "G", 1211 "ET / HTTP/1.1\r\n", 1212 "Host: x\r\n\r\n", 1213 "\r\n\r\n" 1214 }; 1215 1216 1217 /* ------------------------------------------------------------------ */ 1218 /* The operation program */ 1219 /* ------------------------------------------------------------------ */ 1220 1221 enum op 1222 { 1223 OP_SEND_FRAG = 0, 1224 OP_SEND_RAW = 1, 1225 OP_FDSET = 2, 1226 OP_RUN = 3, 1227 OP_TIMEOUT = 4, 1228 OP_CLOCK = 5, 1229 OP_SUSPEND = 6, 1230 OP_RESUME = 7, 1231 OP_NEWCONN = 8, 1232 OP_CLOSECONN = 9, 1233 OP_SWITCH = 10, 1234 OP_QUIESCE = 11, 1235 OP_DRAIN = 12, 1236 OP_CONNOPT = 13, 1237 OP_INFO = 14, 1238 OP_POLL = 15 1239 }; 1240 1241 1242 /** 1243 * Wait in real time until the connection timeout of the current daemon 1244 * has certainly expired, so that the expiry path is actually reached. 1245 * 1246 * MHD_OPTION_CONNECTION_TIMEOUT has a resolution of one second, so this 1247 * costs about that much wall clock and is therefore globally budgeted. 1248 */ 1249 static void 1250 wait_for_expiry (struct MHD_Daemon *d) 1251 { 1252 struct timeval tv; 1253 1254 if ( (! cfg.allow_real_wait) || 1255 (1 != cfg.timeout_s) || 1256 (0 >= expiry_budget) ) 1257 return; 1258 expiry_budget--; 1259 stat_expiry_waits++; 1260 tv.tv_sec = 1; 1261 tv.tv_usec = 50000; 1262 (void) select (0, NULL, NULL, NULL, &tv); 1263 clk_ms += 1050; 1264 /* Everything parked has to come back first, or the expiry cannot be 1265 observed for it at all. */ 1266 (void) resume_all (); 1267 (void) MHD_run (d); 1268 (void) MHD_run (d); 1269 } 1270 1271 1272 static void 1273 op_quiesce (struct MHD_Daemon *d) 1274 { 1275 MHD_socket ls; 1276 1277 stat_quiesce++; 1278 ls = MHD_quiesce_daemon (d); 1279 if (MHD_INVALID_SOCKET == ls) 1280 return; 1281 if (MHD_INVALID_SOCKET != quiesced_fd) 1282 { 1283 /* MHD_quiesce_daemon() is documented to hand the socket over once 1284 and to answer MHD_INVALID_SOCKET afterwards. */ 1285 (void) close (ls); 1286 fuzz_report_finding ( 1287 "MHD_quiesce_daemon() handed out the listening socket twice"); 1288 return; 1289 } 1290 quiesced_fd = ls; 1291 } 1292 1293 1294 static void 1295 op_info (struct MHD_Daemon *d, 1296 unsigned int arg) 1297 { 1298 const union MHD_DaemonInfo *di; 1299 const union MHD_ConnectionInfo *ci; 1300 volatile size_t sink = 0; 1301 unsigned int i = arg % MAX_LIVE; 1302 1303 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); 1304 if (NULL != di) 1305 sink += (size_t) di->num_connections; 1306 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS); 1307 if (NULL != di) 1308 sink += (size_t) di->flags; 1309 if (NULL != lives[i].mc) 1310 { 1311 ci = MHD_get_connection_info (lives[i].mc, 1312 MHD_CONNECTION_INFO_CONNECTION_SUSPENDED); 1313 if (NULL != ci) 1314 sink += (size_t) ci->suspended; 1315 ci = MHD_get_connection_info (lives[i].mc, 1316 MHD_CONNECTION_INFO_DAEMON); 1317 if (NULL != ci) 1318 sink += (NULL != ci->daemon) ? 1u : 0u; 1319 } 1320 (void) sink; 1321 } 1322 1323 1324 static void 1325 op_connopt (unsigned int i, 1326 unsigned int val) 1327 { 1328 if ( (i >= MAX_LIVE) || 1329 (NULL == lives[i].mc) ) 1330 return; 1331 /* Note that MHD skips the whole update while connection->suspended is 1332 set, so this is not necessarily the timeout the connection ends up 1333 with -- which is why the oracle reads it back instead. */ 1334 (void) MHD_set_connection_option (lives[i].mc, 1335 MHD_CONNECTION_OPTION_TIMEOUT, 1336 val); 1337 } 1338 1339 1340 /* ------------------------------------------------------------------ */ 1341 /* The fuzz target */ 1342 /* ------------------------------------------------------------------ */ 1343 1344 int 1345 LLVMFuzzerTestOneInput (const uint8_t *data, 1346 size_t size) 1347 { 1348 struct MHD_Daemon *d; 1349 struct MHD_OptionItem opts[8]; 1350 unsigned int nopt = 0; 1351 unsigned int flags; 1352 size_t pos; 1353 unsigned int nops = 0; 1354 unsigned int i; 1355 1356 /* Must happen before the first write() into a socketpair. The built-in 1357 driver also does this, but that code is compiled out under 1358 -DFUZZ_NO_MAIN, which is exactly the build every external fuzzing 1359 engine uses; the call is idempotent. See fuzz_ignore_sigpipe() in 1360 fuzz_common.h for why the process dies without it. */ 1361 fuzz_ignore_sigpipe (); 1362 1363 if (size < 5) 1364 return 0; 1365 1366 if (! big_body_ready) 1367 { 1368 big_body_ready = 1; 1369 for (i = 0; i < BIG_BODY_LEN; i++) 1370 big_body[i] = (char) ('a' + (i % 26)); 1371 } 1372 if (! expiry_budget_read) 1373 { 1374 const char *e = getenv ("MHD_FUZZ_EXPIRY_BUDGET"); 1375 1376 expiry_budget_read = 1; 1377 if (NULL != e) 1378 expiry_budget = atoi (e); 1379 } 1380 1381 memset (&cfg, 0, sizeof (cfg)); 1382 /* Must never carry over: everything these point at belonged to the 1383 previous iteration's daemon and is long gone. */ 1384 memset (lives, 0, sizeof (lives)); 1385 for (i = 0; i < MAX_CONNS; i++) 1386 csock[i] = -1; 1387 nconns = 0; 1388 cur_conn = 0; 1389 tearing_down = 0; 1390 quiesced_fd = MHD_INVALID_SOCKET; 1391 clk_ms = 0; 1392 deadline_ms = 0; 1393 deadline_valid = 0; 1394 g_have_sets = 0; 1395 g_max_fd = MHD_INVALID_SOCKET; 1396 g_setsize = (unsigned int) FD_SETSIZE; 1397 1398 cfg.timeout_s = timeout_tbl[data[0] & 0x03]; 1399 cfg.listen_sock = (0 != (data[0] & 0x04)); 1400 cfg.app_fd_setsize = (0 != (data[0] & 0x08)); 1401 cfg.mem_limit = mem_limit_tbl[(data[0] >> 4) & 0x03]; 1402 cfg.conn_limit = (0 != (data[0] & 0x40)); 1403 cfg.small_sockbuf = (0 != (data[0] & 0x80)); 1404 1405 cfg.resp_kind = (unsigned int) (data[1] & 0x03); 1406 cfg.error_reply = (0 != (data[1] & 0x04)); 1407 cfg.susp_park = (0 != (data[1] & 0x08)); 1408 cfg.susp_now = (0 != (data[1] & 0x10)); 1409 cfg.hnd_connopt = (0 != (data[1] & 0x20)); 1410 cfg.hnd_info = (0 != (data[1] & 0x40)); 1411 cfg.auto_drain = (0 != (data[1] & 0x80)); 1412 1413 cfg.fdset_var = (unsigned int) (data[2] & 0x07); 1414 cfg.run_var = (unsigned int) ((data[2] >> 3) & 0x03); 1415 cfg.honour_timeout = (0 != (data[2] & 0x20)); 1416 cfg.timeout_every_run = (0 != (data[2] & 0x40)); 1417 cfg.quiesce_end = (0 != (data[2] & 0x80)); 1418 1419 cfg.nconn_up_front = 1u + (unsigned int) (data[3] & 0x03); 1420 cfg.check_always = (0 != (data[3] & 0x04)); 1421 cfg.allow_real_wait = (0 != (data[3] & 0x08)); 1422 cfg.clock_seed = data[4]; 1423 1424 if (0 != cfg.mem_limit) 1425 { 1426 opts[nopt].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT; 1427 opts[nopt].value = (intptr_t) cfg.mem_limit; 1428 opts[nopt].ptr_value = NULL; 1429 nopt++; 1430 } 1431 opts[nopt].option = MHD_OPTION_CONNECTION_TIMEOUT; 1432 opts[nopt].value = (intptr_t) cfg.timeout_s; 1433 opts[nopt].ptr_value = NULL; 1434 nopt++; 1435 if (cfg.conn_limit) 1436 { 1437 opts[nopt].option = MHD_OPTION_CONNECTION_LIMIT; 1438 opts[nopt].value = (intptr_t) 2; 1439 opts[nopt].ptr_value = NULL; 1440 nopt++; 1441 } 1442 if (cfg.app_fd_setsize) 1443 { 1444 opts[nopt].option = MHD_OPTION_APP_FD_SETSIZE; 1445 opts[nopt].value = (intptr_t) FD_SETSIZE; 1446 opts[nopt].ptr_value = NULL; 1447 nopt++; 1448 } 1449 opts[nopt].option = MHD_OPTION_END; 1450 opts[nopt].value = 0; 1451 opts[nopt].ptr_value = NULL; 1452 1453 /* MHD_ALLOW_SUSPEND_RESUME is always on: it is what this harness is 1454 about, and it implies MHD_USE_ITC, whose descriptor is one more thing 1455 MHD_get_fdset*() has to report correctly. */ 1456 flags = MHD_ALLOW_SUSPEND_RESUME; 1457 if (! cfg.listen_sock) 1458 flags |= MHD_USE_NO_LISTEN_SOCKET; 1459 if (fuzz_verbose) 1460 flags |= MHD_USE_ERROR_LOG; 1461 1462 MHD_set_panic_func (&panic_cb, NULL); 1463 d = MHD_start_daemon (flags, 1464 0, 1465 NULL, NULL, 1466 &ahc, NULL, 1467 MHD_OPTION_ARRAY, opts, 1468 /* through the varargs rather than the option 1469 array: storing a function pointer in the 1470 array's intptr_t member is not strictly 1471 conforming C */ 1472 MHD_OPTION_NOTIFY_CONNECTION, ¬ify_conn_cb, NULL, 1473 MHD_OPTION_END); 1474 if ( (NULL == d) && 1475 cfg.listen_sock) 1476 { 1477 /* No networking available: fall back to the socketpair-only daemon 1478 rather than losing the whole iteration. */ 1479 cfg.listen_sock = 0; 1480 flags |= MHD_USE_NO_LISTEN_SOCKET; 1481 d = MHD_start_daemon (flags, 1482 0, 1483 NULL, NULL, 1484 &ahc, NULL, 1485 MHD_OPTION_ARRAY, opts, 1486 MHD_OPTION_NOTIFY_CONNECTION, ¬ify_conn_cb, NULL, 1487 MHD_OPTION_END); 1488 } 1489 if (NULL == d) 1490 return 0; 1491 cur_daemon = d; 1492 stat_daemons++; 1493 if (! stats_registered) 1494 { 1495 stats_registered = 1; 1496 (void) atexit (&print_stats); 1497 } 1498 1499 for (i = 0; i < cfg.nconn_up_front; i++) 1500 if (0 > new_connection (d)) 1501 break; 1502 1503 pos = 5; 1504 while ( (pos < size) && 1505 (nops < MAX_OPS) ) 1506 { 1507 const unsigned int b = data[pos++]; 1508 const unsigned int opc = b >> 4; 1509 const unsigned int arg = b & 0x0F; 1510 1511 nops++; 1512 switch (opc) 1513 { 1514 case OP_SEND_FRAG: 1515 { 1516 const char *f = frag_tbl[arg]; 1517 1518 send_bytes (cur_conn, f, strlen (f)); 1519 break; 1520 } 1521 case OP_SEND_RAW: 1522 { 1523 size_t l; 1524 1525 if (pos >= size) 1526 break; 1527 l = data[pos++]; 1528 if (l > size - pos) 1529 l = size - pos; 1530 send_bytes (cur_conn, data + pos, l); 1531 pos += l; 1532 break; 1533 } 1534 case OP_FDSET: 1535 op_fdset (d, (0 != (arg & 0x08)) ? cfg.fdset_var : arg); 1536 break; 1537 case OP_RUN: 1538 op_run (d, arg & 0x03, (arg >> 2) & 0x03); 1539 break; 1540 case OP_TIMEOUT: 1541 check_timeouts (d); 1542 if ( (cfg.honour_timeout) && 1543 (deadline_valid) && 1544 (deadline_ms <= clk_ms) ) 1545 op_run (d, cfg.run_var, 0); 1546 break; 1547 case OP_CLOCK: 1548 if (15 == arg) 1549 wait_for_expiry (d); 1550 else 1551 { 1552 clk_ms += (uint64_t) (1u + arg) * (uint64_t) (1u + cfg.clock_seed % 64u); 1553 if ( (cfg.honour_timeout) && 1554 (deadline_valid) && 1555 (deadline_ms <= clk_ms) ) 1556 op_run (d, cfg.run_var, 0); 1557 } 1558 break; 1559 case OP_SUSPEND: 1560 do_suspend (arg % MAX_LIVE); 1561 break; 1562 case OP_RESUME: 1563 do_resume (arg % MAX_LIVE); 1564 break; 1565 case OP_NEWCONN: 1566 (void) new_connection (d); 1567 break; 1568 case OP_CLOSECONN: 1569 close_conn ((0 != (arg & 0x08)) ? cur_conn : (arg % MAX_CONNS), 1570 (0 != (arg & 0x04))); 1571 break; 1572 case OP_SWITCH: 1573 if ( (arg % MAX_CONNS) < nconns) 1574 cur_conn = arg % MAX_CONNS; 1575 break; 1576 case OP_QUIESCE: 1577 op_quiesce (d); 1578 break; 1579 case OP_DRAIN: 1580 if (0 != (arg & 0x08)) 1581 drain_all (); 1582 else 1583 drain_conn (arg % MAX_CONNS); 1584 break; 1585 case OP_CONNOPT: 1586 op_connopt (arg % MAX_LIVE, (arg >> 3) & 0x01); 1587 break; 1588 case OP_INFO: 1589 op_info (d, arg); 1590 break; 1591 default: 1592 op_poll (); 1593 break; 1594 } 1595 if (cfg.check_always) 1596 check_timeouts (d); 1597 } 1598 1599 /* ---- teardown ---- */ 1600 tearing_down = 1; 1601 for (i = 0; i < MAX_CONNS; i++) 1602 close_conn (i, 1); 1603 /* A connection left suspended makes MHD_stop_daemon() MHD_PANIC() 1604 ("called while we have suspended connections"), and 1605 MHD_resume_connection() alone is not enough: it only raises a flag, 1606 and the connection leaves the suspended list in MHD_run(). So flush 1607 and run until nothing is parked any more. tearing_down keeps the 1608 handler from parking anything new, which is what bounds this loop; 1609 the cap is only a backstop. */ 1610 for (i = 0; i < MAX_CONNS + 2u; i++) 1611 { 1612 if (! resume_all ()) 1613 break; 1614 (void) MHD_run (d); 1615 } 1616 (void) MHD_run (d); 1617 if (cfg.quiesce_end) 1618 op_quiesce (d); 1619 MHD_stop_daemon (d); 1620 cur_daemon = NULL; 1621 if (MHD_INVALID_SOCKET != quiesced_fd) 1622 { 1623 (void) close (quiesced_fd); 1624 quiesced_fd = MHD_INVALID_SOCKET; 1625 } 1626 for (i = 0; i < MAX_CONNS; i++) 1627 close_conn (i, 0); 1628 memset (lives, 0, sizeof (lives)); 1629 return 0; 1630 } 1631 1632 1633 /* ------------------------------------------------------------------ */ 1634 /* Structure-aware schedule generator */ 1635 /* ------------------------------------------------------------------ */ 1636 1637 struct sbuf 1638 { 1639 uint8_t *p; 1640 size_t len; 1641 size_t cap; 1642 }; 1643 1644 1645 static void 1646 sb_byte (struct sbuf *b, 1647 uint8_t v) 1648 { 1649 if (b->len < b->cap) 1650 b->p[b->len++] = v; 1651 } 1652 1653 1654 static void 1655 sb_op (struct sbuf *b, 1656 unsigned int opc, 1657 unsigned int arg) 1658 { 1659 sb_byte (b, (uint8_t) ((opc << 4) | (arg & 0x0F))); 1660 } 1661 1662 1663 /** 1664 * Fragment indices, weighted towards the ones that complete a request: 1665 * a schedule that never reaches the access handler exercises very little 1666 * of the connection life cycle. 1667 */ 1668 static const unsigned char gen_frag_bias[] = { 1669 0, 0, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 1, 2, 12, 13, 14, 15 1670 }; 1671 1672 1673 static unsigned int 1674 gen_frag (struct fuzz_rng *rng) 1675 { 1676 if (fuzz_chance (rng, 4)) 1677 return fuzz_below (rng, 16); 1678 return gen_frag_bias[fuzz_below (rng, 1679 (uint32_t) sizeof (gen_frag_bias))]; 1680 } 1681 1682 1683 /** 1684 * Emit "collect the descriptors, poll, run" -- the shape a real external 1685 * event loop has -- with a randomly chosen variant of each step. 1686 */ 1687 static void 1688 gen_loop_round (struct fuzz_rng *rng, 1689 struct sbuf *b) 1690 { 1691 unsigned int v; 1692 unsigned int fl; 1693 1694 if (! fuzz_chance (rng, 5)) 1695 sb_op (b, OP_FDSET, fuzz_below (rng, 16)); 1696 if (! fuzz_chance (rng, 3)) 1697 sb_op (b, OP_POLL, 0); 1698 if (fuzz_chance (rng, 3)) 1699 sb_op (b, OP_TIMEOUT, fuzz_below (rng, 16)); 1700 v = fuzz_below (rng, 4); 1701 /* Half the runs use the descriptor sets MHD actually asked for, so 1702 that requests make progress; the other half are the adversarial 1703 ones (all-zero, all-ones, read set only). */ 1704 fl = fuzz_chance (rng, 2) ? 0u : fuzz_below (rng, 4); 1705 sb_op (b, OP_RUN, v | (fl << 2)); 1706 } 1707 1708 1709 static size_t 1710 fuzz_generate (struct fuzz_rng *rng, 1711 uint8_t *buf, 1712 size_t cap) 1713 { 1714 struct sbuf b; 1715 unsigned int nrounds; 1716 unsigned int i; 1717 unsigned int r; 1718 1719 b.p = buf; 1720 b.len = 0; 1721 b.cap = cap; 1722 1723 /* --- configuration block --- */ 1724 sb_byte (&b, fuzz_byte (rng)); 1725 sb_byte (&b, fuzz_byte (rng)); 1726 sb_byte (&b, fuzz_byte (rng)); 1727 sb_byte (&b, fuzz_byte (rng)); 1728 sb_byte (&b, fuzz_byte (rng)); 1729 1730 nrounds = 3u + fuzz_below (rng, 40); 1731 for (i = 0; i < nrounds; i++) 1732 { 1733 switch (fuzz_below (rng, 24)) 1734 { 1735 case 0: 1736 case 1: 1737 case 2: 1738 case 3: 1739 case 4: 1740 case 5: 1741 /* feed the current connection */ 1742 sb_op (&b, OP_SEND_FRAG, gen_frag (rng)); 1743 gen_loop_round (rng, &b); 1744 break; 1745 case 6: 1746 /* raw literal, so that a mutator has somewhere to put bytes */ 1747 { 1748 unsigned int n = fuzz_below (rng, 24); 1749 unsigned int k; 1750 1751 sb_op (&b, OP_SEND_RAW, 0); 1752 sb_byte (&b, (uint8_t) n); 1753 for (k = 0; k < n; k++) 1754 sb_byte (&b, fuzz_byte (rng)); 1755 break; 1756 } 1757 case 7: 1758 case 8: 1759 gen_loop_round (rng, &b); 1760 break; 1761 case 9: 1762 r = fuzz_below (rng, 16); 1763 sb_op (&b, OP_SUSPEND, r); 1764 break; 1765 case 10: 1766 r = fuzz_below (rng, 16); 1767 sb_op (&b, OP_RESUME, r); 1768 break; 1769 case 11: 1770 sb_op (&b, OP_NEWCONN, 0); 1771 sb_op (&b, OP_SEND_FRAG, gen_frag (rng)); 1772 break; 1773 case 12: 1774 r = fuzz_below (rng, 16); 1775 sb_op (&b, OP_CLOSECONN, r); 1776 break; 1777 case 13: 1778 r = fuzz_below (rng, 16); 1779 sb_op (&b, OP_SWITCH, r); 1780 break; 1781 case 14: 1782 sb_op (&b, OP_QUIESCE, 0); 1783 break; 1784 case 15: 1785 r = fuzz_below (rng, 16); 1786 sb_op (&b, OP_DRAIN, r); 1787 break; 1788 case 16: 1789 r = fuzz_below (rng, 16); 1790 sb_op (&b, OP_CONNOPT, r); 1791 break; 1792 case 17: 1793 r = fuzz_below (rng, 16); 1794 sb_op (&b, OP_INFO, r); 1795 break; 1796 case 18: 1797 r = fuzz_below (rng, 16); 1798 sb_op (&b, OP_TIMEOUT, r); 1799 break; 1800 case 19: 1801 /* an artificial clock jump, occasionally the real one that lets a 1802 connection time out */ 1803 r = fuzz_chance (rng, 40) ? 15u : fuzz_below (rng, 15); 1804 sb_op (&b, OP_CLOCK, r); 1805 break; 1806 case 20: 1807 /* a run without ever asking MHD what it wanted */ 1808 r = fuzz_below (rng, 16); 1809 sb_op (&b, OP_RUN, r); 1810 break; 1811 case 21: 1812 sb_op (&b, OP_POLL, 0); 1813 break; 1814 default: 1815 sb_op (&b, OP_SEND_FRAG, gen_frag (rng)); 1816 break; 1817 } 1818 } 1819 /* Make sure most schedules end with the daemon actually run, so that 1820 the interesting states are reached rather than only set up. */ 1821 gen_loop_round (rng, &b); 1822 return b.len; 1823 } 1824 1825 1826 /* ------------------------------------------------------------------ */ 1827 /* Built-in seed corpus */ 1828 /* ------------------------------------------------------------------ */ 1829 1830 /** 1831 * A seed is the five configuration bytes plus a literal operation 1832 * program. Programs are short on purpose: each one is meant to pin down 1833 * one entry point or one life-cycle transition, and libFuzzer's -merge 1834 * keeps the shortest input reaching a given edge. 1835 */ 1836 struct seed_def 1837 { 1838 const char *name; 1839 unsigned char cfg[5]; 1840 unsigned char ops[24]; 1841 unsigned char nops; 1842 }; 1843 1844 #define OPB(o,a) (unsigned char) (((o) << 4) | (a)) 1845 1846 static const struct seed_def seeds[] = { 1847 /* MHD_get_fdset() (the real v1 entry point) + select() + 1848 MHD_run_from_select() (also v1) */ 1849 { "fdset-v1-run-from-select-v1", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1850 { OPB (OP_SEND_FRAG, 0), OPB (OP_FDSET, 0), OPB (OP_POLL, 0), 1851 OPB (OP_RUN, 0), OPB (OP_TIMEOUT, 0), OPB (OP_FDSET, 0), 1852 OPB (OP_POLL, 0), OPB (OP_RUN, 0) }, 8 }, 1853 1854 /* MHD_get_fdset2() + MHD_run_from_select2() */ 1855 { "fdset2-run-from-select2", { 0x00, 0x80, 0x09, 0x00, 0x00 }, 1856 { OPB (OP_SEND_FRAG, 0), OPB (OP_FDSET, 1), OPB (OP_POLL, 0), 1857 OPB (OP_RUN, 1), OPB (OP_TIMEOUT, 0), OPB (OP_FDSET, 1), 1858 OPB (OP_POLL, 0), OPB (OP_RUN, 1) }, 8 }, 1859 1860 /* a small FD_SETSIZE limit, which MHD has to refuse descriptors for */ 1861 { "fdset2-small-setsize", { 0x00, 0x80, 0x02, 0x00, 0x04 }, 1862 { OPB (OP_SEND_FRAG, 0), OPB (OP_FDSET, 2), OPB (OP_RUN, 1), 1863 OPB (OP_FDSET, 2), OPB (OP_TIMEOUT, 0), OPB (OP_RUN, 1) }, 6 }, 1864 1865 /* max_fd == NULL and except_fd_set == NULL, both documented shapes */ 1866 { "fdset2-null-args", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1867 { OPB (OP_SEND_FRAG, 0), OPB (OP_FDSET, 3), OPB (OP_RUN, 1), 1868 OPB (OP_FDSET, 4), OPB (OP_RUN, 1), OPB (OP_TIMEOUT, 0) }, 6 }, 1869 1870 /* MHD_run() and MHD_run_wait() */ 1871 { "run-and-run-wait", { 0x00, 0x80, 0x10, 0x00, 0x00 }, 1872 { OPB (OP_SEND_FRAG, 0), OPB (OP_RUN, 2), OPB (OP_RUN, 3), 1873 OPB (OP_TIMEOUT, 0), OPB (OP_RUN, 2) }, 5 }, 1874 1875 /* descriptor sets MHD never asked for: all-zero and all-ones */ 1876 { "run-from-select-bogus-sets", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1877 { OPB (OP_SEND_FRAG, 0), OPB (OP_RUN, 0x04), OPB (OP_RUN, 0x08), 1878 OPB (OP_RUN, 0x05), OPB (OP_RUN, 0x09), OPB (OP_TIMEOUT, 0), 1879 OPB (OP_RUN, 0x0C) }, 7 }, 1880 1881 /* stale sets: collect, close the connection, then run with them */ 1882 { "run-from-select-stale-sets", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1883 { OPB (OP_SEND_FRAG, 1), OPB (OP_FDSET, 1), OPB (OP_CLOSECONN, 0), 1884 OPB (OP_RUN, 0), OPB (OP_RUN, 1), OPB (OP_TIMEOUT, 0) }, 6 }, 1885 1886 /* suspend from the pump loop, across a full fdset/poll/run round */ 1887 { "suspend-across-loop", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1888 { OPB (OP_SEND_FRAG, 1), OPB (OP_RUN, 2), OPB (OP_SUSPEND, 0), 1889 OPB (OP_FDSET, 1), OPB (OP_TIMEOUT, 0), OPB (OP_POLL, 0), 1890 OPB (OP_RUN, 1), OPB (OP_RESUME, 0), OPB (OP_RUN, 2) }, 9 }, 1891 1892 /* the handler parks the connection; several are parked at once */ 1893 { "handler-parks-two-connections", { 0x00, 0x88, 0x00, 0x00, 0x00 }, 1894 { OPB (OP_SEND_FRAG, 0), OPB (OP_RUN, 2), OPB (OP_NEWCONN, 0), 1895 OPB (OP_SEND_FRAG, 0), OPB (OP_RUN, 2), OPB (OP_TIMEOUT, 0), 1896 OPB (OP_RESUME, 0), OPB (OP_RUN, 2) }, 8 }, 1897 1898 /* suspend while a resume is still pending (cancels the resume) */ 1899 { "suspend-cancels-pending-resume", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1900 { OPB (OP_SEND_FRAG, 1), OPB (OP_RUN, 2), OPB (OP_SUSPEND, 0), 1901 OPB (OP_RESUME, 0), OPB (OP_SUSPEND, 0), OPB (OP_TIMEOUT, 0), 1902 OPB (OP_RESUME, 0), OPB (OP_RUN, 2) }, 8 }, 1903 1904 /* quiesce a daemon that really has a listening socket, then check that 1905 it is gone from the descriptor sets */ 1906 { "quiesce-listening-daemon", { 0x04, 0x80, 0x00, 0x00, 0x00 }, 1907 { OPB (OP_SEND_FRAG, 0), OPB (OP_FDSET, 1), OPB (OP_RUN, 1), 1908 OPB (OP_QUIESCE, 0), OPB (OP_FDSET, 1), OPB (OP_TIMEOUT, 0), 1909 OPB (OP_RUN, 1), OPB (OP_QUIESCE, 0) }, 8 }, 1910 1911 /* a large response on a small socket buffer: the connection stays 1912 blocked on write over many rounds */ 1913 { "blocked-write-scheduling", { 0x80, 0x02, 0x00, 0x00, 0x00 }, 1914 { OPB (OP_SEND_FRAG, 0), OPB (OP_FDSET, 1), OPB (OP_POLL, 0), 1915 OPB (OP_RUN, 1), OPB (OP_FDSET, 1), OPB (OP_POLL, 0), 1916 OPB (OP_RUN, 1), OPB (OP_DRAIN, 8), OPB (OP_FDSET, 1), 1917 OPB (OP_RUN, 1), OPB (OP_TIMEOUT, 0) }, 11 }, 1918 1919 /* a real connection-timeout expiry */ 1920 { "connection-timeout-expiry", { 0x00, 0x80, 0x00, 0x08, 0x00 }, 1921 { OPB (OP_SEND_FRAG, 1), OPB (OP_RUN, 2), OPB (OP_TIMEOUT, 0), 1922 OPB (OP_CLOCK, 15), OPB (OP_TIMEOUT, 0), OPB (OP_RUN, 2) }, 6 }, 1923 1924 /* per-connection timeouts, which move the connection to the "manual" 1925 timeout list that MHD_get_timeout*() has to scan separately */ 1926 { "manual-timeout-list", { 0x00, 0x80, 0x00, 0x03, 0x00 }, 1927 { OPB (OP_SEND_FRAG, 1), OPB (OP_CONNOPT, 8), OPB (OP_TIMEOUT, 0), 1928 OPB (OP_CONNOPT, 1), OPB (OP_TIMEOUT, 0), OPB (OP_RUN, 2), 1929 OPB (OP_TIMEOUT, 0) }, 7 }, 1930 1931 /* pipelined requests plus a chunked upload, driven one run at a time */ 1932 { "pipelined-and-chunked", { 0x00, 0x81, 0x00, 0x00, 0x00 }, 1933 { OPB (OP_SEND_FRAG, 11), OPB (OP_RUN, 2), OPB (OP_SEND_FRAG, 5), 1934 OPB (OP_RUN, 2), OPB (OP_SEND_FRAG, 6), OPB (OP_RUN, 2), 1935 OPB (OP_SEND_FRAG, 7), OPB (OP_RUN, 2), OPB (OP_TIMEOUT, 0) }, 9 }, 1936 1937 /* never poll, never ask for descriptors, only run from empty sets */ 1938 { "never-poll", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1939 { OPB (OP_SEND_FRAG, 0), OPB (OP_RUN, 0x04), OPB (OP_RUN, 0x04), 1940 OPB (OP_RUN, 0x04), OPB (OP_RUN, 0x04), OPB (OP_TIMEOUT, 0) }, 6 }, 1941 1942 /* abrupt close in the middle of a request, with the descriptor sets 1943 collected before it */ 1944 { "abrupt-close-mid-request", { 0x00, 0x80, 0x00, 0x00, 0x00 }, 1945 { OPB (OP_SEND_FRAG, 3), OPB (OP_FDSET, 1), OPB (OP_CLOSECONN, 0), 1946 OPB (OP_RUN, 1), OPB (OP_TIMEOUT, 0), OPB (OP_RUN, 2) }, 6 }, 1947 1948 /* connection limit of two, so that MHD_add_connection() starts to fail */ 1949 { "connection-limit", { 0x40, 0x80, 0x00, 0x03, 0x00 }, 1950 { OPB (OP_NEWCONN, 0), OPB (OP_NEWCONN, 0), OPB (OP_SEND_FRAG, 0), 1951 OPB (OP_RUN, 2), OPB (OP_TIMEOUT, 0) }, 5 }, 1952 1953 /* no connection timeout at all: MHD_get_timeout*() must report that an 1954 indefinite wait is fine */ 1955 { "no-timeout-configured", { 0x02, 0x80, 0x00, 0x04, 0x00 }, 1956 { OPB (OP_SEND_FRAG, 1), OPB (OP_TIMEOUT, 0), OPB (OP_RUN, 2), 1957 OPB (OP_TIMEOUT, 0), OPB (OP_SEND_FRAG, 2), OPB (OP_RUN, 2) }, 6 } 1958 }; 1959 1960 static uint8_t seed_render_buf[64]; 1961 1962 1963 static size_t 1964 fuzz_seed_count (void) 1965 { 1966 return sizeof (seeds) / sizeof (seeds[0]); 1967 } 1968 1969 1970 static const uint8_t * 1971 fuzz_seed_get (size_t idx, 1972 size_t *len) 1973 { 1974 const struct seed_def *sd = &seeds[idx]; 1975 size_t n = sd->nops; 1976 1977 if (n > sizeof (sd->ops)) 1978 n = sizeof (sd->ops); 1979 if (n + sizeof (sd->cfg) > sizeof (seed_render_buf)) 1980 n = sizeof (seed_render_buf) - sizeof (sd->cfg); 1981 memcpy (seed_render_buf, sd->cfg, sizeof (sd->cfg)); 1982 memcpy (seed_render_buf + sizeof (sd->cfg), sd->ops, n); 1983 *len = sizeof (sd->cfg) + n; 1984 return seed_render_buf; 1985 }