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