fuzz_request.c (99981B)
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_request.c 22 * @brief End-to-end in-process fuzzer for the MHD request parser. 23 * @author Christian Grothoff 24 * 25 * A real `struct MHD_Daemon` is created with #MHD_USE_NO_LISTEN_SOCKET 26 * and driven through a `socketpair()` that is handed to MHD with 27 * #MHD_add_connection(). The daemon runs in external-polling mode, so 28 * everything happens in the fuzzer's thread: fully deterministic, no 29 * TCP stack, no ports, no races. 30 * 31 * Input format (see README): 32 * 33 * byte 0 configuration: connection memory limit 34 * byte 1 configuration: handler behaviour bitmask 35 * byte 2 configuration: client discipline / insanity level 36 * byte 3 configuration: digest-auth parameters 37 * byte 4 response construction: which MHD_create_response_*() 38 * to use, how many response headers to add, footers, 39 * header-manipulation API 40 * byte 5 which authentication entry point to call: the v1/v2 41 * compatibility wrappers, the username/request-info 42 * queries, or the differing fail-response variants 43 * byte 6 event-loop mode (MHD_run() vs MHD_get_fdset*() + 44 * MHD_run_from_select*()) and the connection-introspection 45 * calls 46 * byte 7 suspend/resume and HTTP "Upgrade" 47 * byte 8 seed for the generated response header names/values 48 * byte 9 seed for the content-reader callback behaviour 49 * byte 10. a sequence of send-segments, each introduced by a 50 * little-endian 16 bit header (op << 14) | length 51 * op 0 send the payload 52 * op 1 the payload is the *expected* decoded request body 53 * (ground truth for the body oracle); nothing is sent 54 * op 2 send the payload and pump the daemon extra rounds 55 * op 3 close the connection, open a fresh one, send 56 * 57 * All ten configuration bytes are always present; an input shorter 58 * than that is rejected outright. The all-zero configuration is the 59 * plainest one -- a static two byte buffer response, MHD_run() as the 60 * event loop, no suspend, no upgrade, no extra introspection -- so 61 * zeroing bytes 4-9 of any input reduces it to what the harness did 62 * before those bytes existed. 63 * 64 * Splitting the byte stream into explicit segments matters: MHD's 65 * parser is incremental and several past bugs only showed up for 66 * particular split points. 67 * 68 * The literal ASCII token "%%NONCE%%" inside a segment is replaced, 69 * at send time, by the most recent `nonce="..."` value seen in a 70 * response from the daemon. This is what allows the fuzzer to walk 71 * through the Digest-Auth challenge/response handshake and reach the 72 * code that is only executed for a *valid* nonce. 73 */ 74 75 /* Must precede every #include: memfd_create() and MFD_CLOEXEC are only 76 declared by <sys/mman.h> under _GNU_SOURCE, and the OSS-Fuzz build 77 compiles this file with nothing but -DFUZZ_NO_MAIN (the library gets 78 _GNU_SOURCE from configure, the hand-compiled harnesses do not). 79 Without this the fd-backed response kinds silently fall back to a 80 buffer response and MHD_create_response_from_fd*() is never reached 81 -- a failure mode with no error message at all. */ 82 #ifndef _GNU_SOURCE 83 #define _GNU_SOURCE 1 84 #endif 85 86 #define FUZZ_HARNESS_NAME "fuzz_request" 87 #include "fuzz_common.h" 88 89 #include <microhttpd.h> 90 #include <sys/socket.h> 91 #include <netinet/in.h> 92 #include <sys/select.h> 93 94 /* MHD_create_response_from_data() and MHD_create_response_from_buffer() 95 with an explicit MHD_ResponseMemoryMode are deprecated but are still 96 shipped API and are therefore still worth fuzzing; the deprecation 97 warning would otherwise drown the build output. */ 98 #if defined(__GNUC__) || defined(__clang__) 99 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 100 #endif 101 102 /* memfd_create() gives a file descriptor backed by anonymous memory, 103 which is what makes the MHD_create_response_from_fd*() variants 104 affordable at fuzzing rates: no filesystem is touched. Where it is 105 unavailable the fd-backed response kinds fall back to a buffer 106 response (see make_response()). */ 107 #if defined(__linux__) 108 #include <sys/mman.h> 109 #if defined(MFD_CLOEXEC) 110 #define FUZZ_HAVE_MEMFD 1 111 #endif 112 #endif 113 114 #define MAX_SEGMENTS 96 115 #define MAX_CONNECTIONS 8 116 #define RESP_BUF_SIZE 16384 117 #define GEN_BUF_SIZE 8192 118 #define MAX_EXPECT_BODY 4096 119 120 /** Number of entries in the response-construction table. */ 121 #define RESP_KIND_COUNT 16 122 /** Number of authentication entry points selectable by byte 5. */ 123 #define DAUTH_VARIANT_COUNT 10 124 /** Largest digest MHD_digest_auth_calc_userdigest() can produce. */ 125 #define MAX_DIGEST_BIN 64 126 127 #define DIGEST_REALM "TestRealm" 128 #define DIGEST_USER "user" 129 #define DIGEST_PASS "pass" 130 131 /* ------------------------------------------------------------------ */ 132 /* Per-iteration state */ 133 /* ------------------------------------------------------------------ */ 134 135 struct fuzz_cfg 136 { 137 size_t mem_limit; 138 int discipline; 139 unsigned int insanity; 140 unsigned int nonce_nc_size; 141 enum MHD_DigestAuthMultiAlgo3 algo; 142 enum MHD_DigestAuthMultiQOP qop; 143 int do_digest; 144 int do_basic; 145 int do_postproc; 146 int do_iterate; 147 int chunked_reply; 148 int error_reply; 149 150 /* ---- configuration bytes 4-9; all zero is the plainest setting ---- */ 151 unsigned int resp_kind; /**< index into the response constructors */ 152 unsigned int resp_nhdr; /**< how many response headers to add */ 153 int resp_footer; /**< also add a response footer/trailer */ 154 int resp_hdr_api; /**< exercise get/del/set_response_options */ 155 unsigned int dauth_variant; /**< which digest entry point to call */ 156 unsigned int fail_variant; /**< which *_fail_response to queue */ 157 int basic_v1; /**< use the v1 basic-auth getter */ 158 int calc_helpers; /**< call the userdigest/userhash helpers */ 159 unsigned int loop_mode; /**< 0 MHD_run, 1..3 external event loop */ 160 int use_timeouts; /**< query MHD_get_timeout*() while pumping */ 161 int conn_lookup; /**< MHD_lookup_connection_value*() */ 162 int conn_setvalue; /**< MHD_set_connection_value() */ 163 int conn_info; /**< MHD_get_connection_info/daemon_info */ 164 int conn_option; /**< MHD_set_connection_option() */ 165 int quiesce; /**< MHD_quiesce_daemon() before stopping */ 166 unsigned int suspend_mode; /**< 0 none, 1 immediate, 2 deferred */ 167 int allow_upgrade; /**< MHD_ALLOW_UPGRADE + upgrade response */ 168 unsigned int upgrade_action; /**< which MHD_upgrade_action() to issue */ 169 uint8_t hdr_seed; /**< picks response header name/value */ 170 uint8_t crc_seed; /**< content-reader callback behaviour */ 171 }; 172 173 static struct fuzz_cfg cfg; 174 175 /** Most recent nonce harvested from a 401 response. */ 176 static char nonce_val[192]; 177 static size_t nonce_len; 178 179 /** Ground-truth body of a generated (pristine) request, see README. */ 180 static uint8_t expect_body[MAX_EXPECT_BODY]; 181 static size_t expect_body_len; 182 static int oracle_on; 183 184 /** Statistics, printed at exit with --verbose. */ 185 static unsigned long stat_daemons; 186 static unsigned long stat_handler_calls; 187 static unsigned long stat_final_calls; 188 static unsigned long stat_body_bytes; 189 static unsigned long stat_challenges; 190 static unsigned long stat_auth_ok; 191 static int stats_registered; 192 193 194 static void 195 print_stats (void) 196 { 197 if (! fuzz_verbose) 198 return; 199 fprintf (stderr, 200 "%s: daemons=%lu handler calls=%lu (final=%lu) body bytes=%lu " 201 "401 challenges=%lu authenticated=%lu\n", 202 FUZZ_HARNESS_NAME, 203 stat_daemons, stat_handler_calls, stat_final_calls, 204 stat_body_bytes, stat_challenges, stat_auth_ok); 205 } 206 207 208 /** Bytes received from the daemon during the current iteration. */ 209 static char resp_buf[RESP_BUF_SIZE]; 210 static size_t resp_len; 211 212 static const size_t mem_limit_tbl[] = { 213 0 /* MHD default */, 128, 192, 256, 320, 384, 512, 768, 1024, 1400, 1500, 214 2048, 4096, 32768 215 }; 216 217 static const int discipline_tbl[] = { -3, -2, -1, 0, 1, 2 }; 218 219 /** 220 * Lower bound for MHD_OPTION_CLIENT_DISCIPLINE_LVL, -3 is the full 221 * range. On a tree without the patches listed in README section 6, 222 * levels below 0 reach two stale mhd_assert()s in get_req_header(); 223 * set MHD_FUZZ_MIN_DISCIPLINE=0 there so that the rest of the state 224 * space keeps being explored. 225 */ 226 static int min_discipline = -3; 227 static int min_discipline_read; 228 229 /** 230 * Restrict the generator to a single grammar shape (see enum gen_shape). 231 * -1 (the default) means "pick a random shape every time". Set with 232 * MHD_FUZZ_SHAPE=<n>; handy for triage and for regression testing a 233 * specific past bug. 234 */ 235 static int forced_shape = -1; 236 static int forced_shape_read; 237 238 /** 239 * Lower bound for MHD_OPTION_CONNECTION_MEMORY_LIMIT. 0 (the default) 240 * fuzzes the full range, including the 128 byte pools that are needed 241 * to reach the read-buffer "shift back" code. On a tree without the 242 * patches listed in README section 6, pools below ~500 bytes combined 243 * with a chunked request body reach two mhd_assert()s in connection.c; 244 * set MHD_FUZZ_MIN_MEM_LIMIT=512 there. 245 */ 246 static size_t min_mem_limit; 247 static int min_mem_limit_read; 248 249 static const enum MHD_DigestAuthMultiAlgo3 algo_tbl[] = { 250 MHD_DIGEST_AUTH_MULT_ALGO3_SHA256, 251 MHD_DIGEST_AUTH_MULT_ALGO3_MD5, 252 MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256, 253 MHD_DIGEST_AUTH_MULT_ALGO3_SHA256 254 }; 255 256 static const unsigned int nnc_tbl[] = { 4, 1, 8, 64 }; 257 258 /** Fixed entropy so that nonces are reproducible across runs. */ 259 static const char digest_rnd[32] = 260 "\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef" 261 "\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10"; 262 263 264 /* ------------------------------------------------------------------ */ 265 /* Configuration byte 4: response construction */ 266 /* ------------------------------------------------------------------ */ 267 268 /* Defined with the access handler further down; decorate_response() 269 hands it to MHD_get_response_headers(). */ 270 static enum MHD_Result 271 kv_iter (void *cls, 272 enum MHD_ValueKind kind, 273 const char *key, 274 const char *value); 275 276 /** Daemon of the current iteration; needed by MHD_get_daemon_info(). */ 277 static struct MHD_Daemon *cur_daemon; 278 279 /** 280 * Connections suspended by suspend mode 2, which the pump loop still has 281 * to resume. An entry is cleared by completed_cb() so that a connection 282 * MHD has finished with is never resumed afterwards. 283 * 284 * This has to be a set, not a single slot: op 3 opens a fresh connection 285 * without waiting for the previous one to finish, so several connections 286 * can be parked at the same time. A single slot silently loses all but 287 * the last, and the forgotten one is still suspended when the iteration 288 * calls MHD_stop_daemon(), which answers with 289 * MHD_PANIC ("MHD_stop_daemon() called while we have suspended 290 * connections") -- a harness bug that looks exactly like an MHD bug. 291 */ 292 static struct MHD_Connection *pending_resume[MAX_CONNECTIONS]; 293 294 /** 295 * Set once the iteration has stopped feeding the daemon and only wants 296 * to drain it. suspend_maybe() then does nothing, which is what makes 297 * the flush loop in the teardown provably terminate: without it, 298 * resuming a connection lets the handler run and park it again, for as 299 * many rounds as there are pipelined requests still buffered. 300 */ 301 static int tearing_down; 302 303 304 /** 305 * Record @a c as suspended. Silently ignores the overflow case: the 306 * array has one slot per connection the harness can open, so it cannot 307 * overflow, and a dropped entry would only cost the resume below. 308 */ 309 static void 310 pending_resume_add (struct MHD_Connection *c) 311 { 312 unsigned int i; 313 314 for (i = 0; i < MAX_CONNECTIONS; i++) 315 { 316 if (NULL == pending_resume[i]) 317 { 318 pending_resume[i] = c; 319 return; 320 } 321 } 322 } 323 324 325 /** Forget @a c without resuming it (it is gone). */ 326 static void 327 pending_resume_drop (const struct MHD_Connection *c) 328 { 329 unsigned int i; 330 331 for (i = 0; i < MAX_CONNECTIONS; i++) 332 if (pending_resume[i] == c) 333 pending_resume[i] = NULL; 334 } 335 336 337 /** 338 * Resume everything still parked. 339 * 340 * @return non-zero if at least one connection was resumed, so that the 341 * caller knows the daemon needs another round to act on it 342 */ 343 static int 344 pending_resume_flush (void) 345 { 346 unsigned int i; 347 int any = 0; 348 349 for (i = 0; i < MAX_CONNECTIONS; i++) 350 { 351 struct MHD_Connection *c = pending_resume[i]; 352 353 if (NULL == c) 354 continue; 355 /* Clear first: MHD_resume_connection() can run the handler, which 356 may suspend the very same connection again. */ 357 pending_resume[i] = NULL; 358 MHD_resume_connection (c); 359 any = 1; 360 } 361 return any; 362 } 363 364 365 /** Body used by the buffer / fd / pipe / iovec response kinds. */ 366 static const char resp_body[] = "hello world, this is the response body"; 367 #define RESP_BODY_LEN (sizeof (resp_body) - 1) 368 369 /** 370 * Response header names and values, indexed by cfg.hdr_seed. The list 371 * mixes ordinary headers with ones MHD has to reject or handle 372 * specially: an empty name, a name carrying a control character, and a 373 * value containing CRLF -- the classic response-splitting vector, which 374 * MHD_add_response_header() is supposed to refuse. Exercising that 375 * validator is the point of this table. 376 * 377 * The message-framing headers are deliberately NOT here. MHD generates 378 * Content-Length and Transfer-Encoding itself from the response object, 379 * so an application that also sets them by hand is lying to the library 380 * about its own body: a manual "Transfer-Encoding: chunked" on, say, an 381 * iovec response sends MHD down the chunked path for a response that 382 * has neither a content reader nor a flat buffer, and it aborts in 383 * try_ready_chunked_body(). That is the harness misusing the API 384 * rather than a defect worth reporting, and leaving it in would bury 385 * every real finding under the same false report. MHD_RF_INSANITY_- 386 * HEADER_CONTENT_LENGTH, set through MHD_set_response_options() in 387 * decorate_response(), is the sanctioned way to explore that corner. 388 */ 389 static const char *const hdr_names[] = { 390 "X-Fuzz", "Content-Type", "Cache-Control", "Accept-Ranges", 391 /* "\x01" is split from the rest so that the hex escape stops after 392 one digit instead of swallowing the following "Bad". */ 393 "Connection", "Set-Cookie", "X-\x01" "Bad", "", "Trailer", "Date", 394 "X-Fuzz", "Server", "Location", "ETag", "Vary", "Age" 395 }; 396 397 static const char *const hdr_values[] = { 398 "1", "text/plain", "no-cache", "bytes", "keep-alive", "a=b", 399 "x\r\nInjected: yes", "", "X-Fuzz", "Thu, 01 Jan 1970 00:00:00 GMT", 400 "\x7f", "mhd", "/", "\"tag\"", "*", "0" 401 }; 402 403 #define HDR_COUNT (sizeof (hdr_names) / sizeof (hdr_names[0])) 404 405 406 /** 407 * State of one MHD_create_response_from_callback() response. Allocated 408 * per response and released through the free callback that MHD invokes 409 * from MHD_destroy_response(). 410 */ 411 struct crc_state 412 { 413 uint64_t total; /**< bytes to produce before end-of-stream */ 414 int calls; /**< how often the reader has been called */ 415 int err_at; /**< fail after this many calls, -1 to never fail */ 416 unsigned int pattern; 417 }; 418 419 420 static ssize_t 421 crc_cb (void *cls, 422 uint64_t pos, 423 char *buf, 424 size_t max) 425 { 426 struct crc_state *st = (struct crc_state *) cls; 427 size_t n; 428 size_t i; 429 430 st->calls++; 431 /* Deliberately reachable: an application content reader is allowed to 432 fail half way through a response body, and how MHD terminates the 433 connection in that case (especially a chunked one that can no 434 longer be framed correctly) is worth exercising. */ 435 if ( (0 <= st->err_at) && 436 (st->calls > st->err_at) ) 437 return MHD_CONTENT_READER_END_WITH_ERROR; 438 if (pos >= st->total) 439 return MHD_CONTENT_READER_END_OF_STREAM; 440 n = (size_t) (st->total - pos); 441 if (n > max) 442 n = max; 443 if (0 == n) 444 return MHD_CONTENT_READER_END_OF_STREAM; 445 for (i = 0; i < n; i++) 446 buf[i] = (char) ('a' + (int) ((pos + i + st->pattern) % 26)); 447 return (ssize_t) n; 448 } 449 450 451 static void 452 crc_free (void *cls) 453 { 454 free (cls); 455 } 456 457 458 /** 459 * Handler for an upgraded ("101 Switching Protocols") connection. 460 * 461 * @a extra_in holds whatever the client had already pipelined behind 462 * the request, which is attacker-controlled and therefore read here. 463 * 464 * The connection MUST be closed through MHD_upgrade_action(): the 465 * socket belongs to the application from this point on and 466 * MHD_stop_daemon() cannot complete while an upgraded connection is 467 * still outstanding. 468 */ 469 static void 470 upgrade_cb (void *cls, 471 struct MHD_Connection *connection, 472 void *req_cls, 473 const char *extra_in, 474 size_t extra_in_size, 475 MHD_socket sock, 476 struct MHD_UpgradeResponseHandle *urh) 477 { 478 volatile size_t sink = 0; 479 480 (void) cls; 481 (void) connection; 482 (void) req_cls; 483 (void) sock; 484 if ( (NULL != extra_in) && 485 (0 != extra_in_size) ) 486 sink += (size_t) (unsigned char) extra_in[extra_in_size - 1]; 487 (void) sink; 488 if (0 != (cfg.upgrade_action & 0x01u)) 489 (void) MHD_upgrade_action (urh, MHD_UPGRADE_ACTION_CORK_ON); 490 if (0 != (cfg.upgrade_action & 0x02u)) 491 (void) MHD_upgrade_action (urh, MHD_UPGRADE_ACTION_CORK_OFF); 492 (void) MHD_upgrade_action (urh, MHD_UPGRADE_ACTION_CLOSE); 493 } 494 495 496 /** 497 * A file descriptor holding RESP_BODY_LEN bytes, backed by anonymous 498 * memory so that no filesystem is involved. 499 * 500 * @return -1 if unavailable, in which case the caller falls back to a 501 * buffer response 502 */ 503 static int 504 make_memfd (void) 505 { 506 #ifdef FUZZ_HAVE_MEMFD 507 int fd; 508 509 fd = memfd_create ("mhd-fuzz", MFD_CLOEXEC); 510 if (0 > fd) 511 return -1; 512 if (RESP_BODY_LEN != (size_t) write (fd, resp_body, RESP_BODY_LEN)) 513 { 514 (void) close (fd); 515 return -1; 516 } 517 return fd; 518 #else 519 return -1; 520 #endif 521 } 522 523 524 /** 525 * The read end of a pipe holding RESP_BODY_LEN bytes. The body is far 526 * below the pipe capacity, so the write cannot block. 527 */ 528 static int 529 make_pipe_fd (void) 530 { 531 int pf[2]; 532 533 if (0 != pipe (pf)) 534 return -1; 535 if (RESP_BODY_LEN != (size_t) write (pf[1], resp_body, RESP_BODY_LEN)) 536 { 537 (void) close (pf[0]); 538 (void) close (pf[1]); 539 return -1; 540 } 541 (void) close (pf[1]); 542 return pf[0]; 543 } 544 545 546 /** 547 * Add response headers, footers and option flags as selected by byte 4 548 * and the header seed in byte 8. 549 * 550 * Footers are only meaningful for a chunked response -- MHD emits them 551 * as trailers after the last chunk -- which is why they are worth 552 * fuzzing together with the callback-based response kinds. 553 */ 554 static void 555 decorate_response (struct MHD_Response *r) 556 { 557 unsigned int i; 558 559 for (i = 0; i < cfg.resp_nhdr; i++) 560 { 561 unsigned int k = (cfg.hdr_seed + i) % HDR_COUNT; 562 563 (void) MHD_add_response_header (r, hdr_names[k], hdr_values[k]); 564 } 565 if (cfg.resp_footer) 566 { 567 unsigned int k = (unsigned int) (cfg.hdr_seed + 1u) % HDR_COUNT; 568 569 (void) MHD_add_response_footer (r, hdr_names[k], hdr_values[k]); 570 } 571 if (cfg.resp_hdr_api) 572 { 573 unsigned int k = cfg.hdr_seed % HDR_COUNT; 574 volatile size_t sink = 0; 575 const char *v; 576 577 v = MHD_get_response_header (r, hdr_names[k]); 578 if (NULL != v) 579 sink += strlen (v); 580 (void) sink; 581 (void) MHD_get_response_headers (r, &kv_iter, NULL); 582 (void) MHD_del_response_header (r, hdr_names[k], hdr_values[k]); 583 (void) MHD_set_response_options (r, 584 (enum MHD_ResponseFlags) 585 (((cfg.hdr_seed & 0x01) ? 586 MHD_RF_HTTP_VERSION_1_0_RESPONSE : 0) 587 | ((cfg.hdr_seed & 0x02) ? 588 MHD_RF_SEND_KEEP_ALIVE_HEADER : 0) 589 | ((cfg.hdr_seed & 0x04) ? 590 MHD_RF_INSANITY_HEADER_CONTENT_LENGTH 591 : 0) 592 | ((cfg.hdr_seed & 0x08) ? 593 MHD_RF_HEAD_ONLY_RESPONSE : 0)), 594 MHD_RO_END); 595 } 596 } 597 598 599 /** 600 * Build the response body for this iteration. 601 * 602 * Every constructor that fails is responsible for nothing: MHD releases 603 * neither the buffer nor the file descriptor when it returns NULL (see 604 * MHD_create_response_from_buffer_with_free_callback_cls() and 605 * MHD_create_response_from_pipe() in response.c), so ownership stays 606 * here and the resource has to be released explicitly. Getting this 607 * backwards would produce double frees that look exactly like MHD bugs. 608 */ 609 static struct MHD_Response * 610 make_response (void) 611 { 612 struct MHD_Response *r = NULL; 613 struct crc_state *st; 614 void *heap; 615 int fd; 616 617 switch (cfg.resp_kind) 618 { 619 case 0: 620 /* The two responses the harness used before byte 4 existed. Bit 621 0x20 of byte 1 (cfg.chunked_reply) selects between them and has 622 no other effect, so keeping the pair here is what keeps that bit 623 meaningful. */ 624 if (cfg.chunked_reply) 625 r = MHD_create_response_from_buffer_copy (11, "hello world"); 626 else 627 r = MHD_create_response_from_buffer_static (2, "ok"); 628 break; 629 case 1: 630 r = MHD_create_response_from_buffer_copy (RESP_BODY_LEN, resp_body); 631 break; 632 case 2: 633 r = MHD_create_response_empty (MHD_RF_NONE); 634 break; 635 case 3: 636 r = MHD_create_response_from_buffer (RESP_BODY_LEN, 637 (void *) (intptr_t) resp_body, 638 MHD_RESPMEM_PERSISTENT); 639 break; 640 case 4: 641 heap = malloc (RESP_BODY_LEN); 642 if (NULL == heap) 643 return NULL; 644 memcpy (heap, resp_body, RESP_BODY_LEN); 645 r = MHD_create_response_from_buffer (RESP_BODY_LEN, 646 heap, 647 MHD_RESPMEM_MUST_FREE); 648 if (NULL == r) 649 free (heap); 650 break; 651 case 5: 652 r = MHD_create_response_from_buffer (RESP_BODY_LEN, 653 (void *) (intptr_t) resp_body, 654 MHD_RESPMEM_MUST_COPY); 655 break; 656 case 6: 657 heap = malloc (RESP_BODY_LEN); 658 if (NULL == heap) 659 return NULL; 660 memcpy (heap, resp_body, RESP_BODY_LEN); 661 r = MHD_create_response_from_buffer_with_free_callback (RESP_BODY_LEN, 662 heap, 663 &free); 664 if (NULL == r) 665 free (heap); 666 break; 667 case 7: 668 r = MHD_create_response_from_data (RESP_BODY_LEN, 669 (void *) (intptr_t) resp_body, 670 0 /* must_free */, 671 1 /* must_copy */); 672 break; 673 case 8: 674 heap = malloc (RESP_BODY_LEN); 675 if (NULL == heap) 676 return NULL; 677 memcpy (heap, resp_body, RESP_BODY_LEN); 678 r = MHD_create_response_from_data (RESP_BODY_LEN, 679 heap, 680 1 /* must_free */, 681 0 /* must_copy */); 682 if (NULL == r) 683 free (heap); 684 break; 685 case 9: 686 case 10: 687 st = (struct crc_state *) calloc (1, sizeof (struct crc_state)); 688 if (NULL == st) 689 return NULL; 690 st->total = (uint64_t) (1u + (cfg.crc_seed & 0x7Fu)); 691 st->pattern = cfg.crc_seed; 692 /* Injecting a reader error is only interesting some of the time; 693 otherwise the body would rarely complete. */ 694 st->err_at = (0 != (cfg.crc_seed & 0x80u)) 695 ? (int) (1u + (cfg.crc_seed & 0x03u)) 696 : -1; 697 r = MHD_create_response_from_callback ( 698 (9 == cfg.resp_kind) ? st->total : MHD_SIZE_UNKNOWN, 699 (size_t) (16u + (cfg.crc_seed & 0x3Fu)), 700 &crc_cb, 701 st, 702 &crc_free); 703 if (NULL == r) 704 free (st); 705 break; 706 case 11: 707 case 12: 708 case 13: 709 fd = make_memfd (); 710 if (0 > fd) 711 { 712 r = MHD_create_response_from_buffer_static (2, "ok"); 713 break; 714 } 715 if (11 == cfg.resp_kind) 716 r = MHD_create_response_from_fd (RESP_BODY_LEN, fd); 717 else if (12 == cfg.resp_kind) 718 /* Parenthesised so that the deprecated *function* is called and 719 not the same-named macro that redirects to the 64 bit variant; 720 reaching the v1 entry point is the whole point here. */ 721 r = (MHD_create_response_from_fd_at_offset) ( 722 RESP_BODY_LEN / 2, 723 fd, 724 (off_t) (RESP_BODY_LEN / 4)); 725 else 726 r = MHD_create_response_from_fd64 ((uint64_t) RESP_BODY_LEN, fd); 727 if (NULL == r) 728 (void) close (fd); 729 break; 730 case 14: 731 fd = make_pipe_fd (); 732 if (0 > fd) 733 { 734 r = MHD_create_response_from_buffer_static (2, "ok"); 735 break; 736 } 737 r = MHD_create_response_from_pipe (fd); 738 if (NULL == r) 739 (void) close (fd); 740 break; 741 case 15: 742 default: 743 { 744 static struct MHD_IoVec iov[3]; 745 746 /* Static data, so no free callback is needed; MHD copies the 747 array itself (see the documentation of the @a iov parameter). */ 748 iov[0].iov_base = resp_body; 749 iov[0].iov_len = RESP_BODY_LEN / 2; 750 iov[1].iov_base = resp_body + (RESP_BODY_LEN / 2); 751 iov[1].iov_len = RESP_BODY_LEN - (RESP_BODY_LEN / 2); 752 iov[2].iov_base = resp_body; 753 iov[2].iov_len = (size_t) (cfg.crc_seed % (RESP_BODY_LEN + 1)); 754 r = MHD_create_response_from_iovec (iov, 755 (0 != iov[2].iov_len) ? 3u : 2u, 756 NULL, 757 NULL); 758 } 759 break; 760 } 761 if (NULL != r) 762 decorate_response (r); 763 return r; 764 } 765 766 767 /* ------------------------------------------------------------------ */ 768 /* Access handler */ 769 /* ------------------------------------------------------------------ */ 770 771 struct hstate 772 { 773 size_t body_off; 774 struct MHD_PostProcessor *pp; 775 int pp_tried; 776 }; 777 778 779 static enum MHD_Result 780 kv_iter (void *cls, 781 enum MHD_ValueKind kind, 782 const char *key, 783 const char *value) 784 { 785 volatile size_t sink = 0; 786 787 (void) cls; 788 (void) kind; 789 if (NULL != key) 790 sink += strlen (key); 791 if (NULL != value) 792 sink += strlen (value); 793 (void) sink; 794 return MHD_YES; 795 } 796 797 798 /** 799 * Length-aware counterpart of kv_iter(), for 800 * MHD_get_connection_values_n(). Unlike the NUL-terminated iterator it 801 * is handed explicit sizes, so it reads exactly what MHD says is there 802 * rather than trusting a terminator. 803 */ 804 static enum MHD_Result 805 kv_iter_n (void *cls, 806 enum MHD_ValueKind kind, 807 const char *key, 808 size_t key_size, 809 const char *value, 810 size_t value_size) 811 { 812 volatile size_t sink = 0; 813 814 (void) cls; 815 (void) kind; 816 if ( (NULL != key) && (0 != key_size) ) 817 sink += (size_t) (unsigned char) key[key_size - 1]; 818 if ( (NULL != value) && (0 != value_size) ) 819 sink += (size_t) (unsigned char) value[value_size - 1]; 820 (void) sink; 821 return MHD_YES; 822 } 823 824 825 static enum MHD_Result 826 post_iter (void *cls, 827 enum MHD_ValueKind kind, 828 const char *key, 829 const char *filename, 830 const char *content_type, 831 const char *transfer_encoding, 832 const char *data, 833 uint64_t off, 834 size_t size) 835 { 836 volatile size_t sink = 0; 837 838 (void) cls; 839 (void) kind; 840 (void) off; 841 if (NULL != key) 842 sink += strlen (key); 843 if (NULL != filename) 844 sink += strlen (filename); 845 if (NULL != content_type) 846 sink += strlen (content_type); 847 if (NULL != transfer_encoding) 848 sink += strlen (transfer_encoding); 849 if ( (NULL != data) && (0 != size) ) 850 sink += (size_t) (unsigned char) data[size - 1]; 851 (void) sink; 852 return MHD_YES; 853 } 854 855 856 /** 857 * Check the body MHD hands to the application against the body that 858 * the generator encoded into the request. MHD is allowed to reject 859 * the request at any point, but every byte that it *does* deliver must 860 * be the next expected byte. A mismatch means the framing layer 861 * (Content-Length or chunked transfer coding) got out of sync, which 862 * is exactly the class of bug that enables request smuggling. 863 */ 864 static void 865 oracle_check_body (struct hstate *hs, 866 const char *data, 867 size_t size) 868 { 869 if ( (! oracle_on) || 870 (0 == size) ) 871 return; 872 if ( (hs->body_off + size > expect_body_len) || 873 (0 != memcmp (expect_body + hs->body_off, data, size)) ) 874 fuzz_report_finding ( 875 "request body desync: the bytes MHD delivered to the application " 876 "differ from the body encoded in the generated request " 877 "(chunked/Content-Length framing bug, cf. HTTP request smuggling)"); 878 hs->body_off += size; 879 } 880 881 882 /* ------------------------------------------------------------------ */ 883 /* Configuration byte 5: authentication entry points */ 884 /* ------------------------------------------------------------------ */ 885 886 static const enum MHD_DigestAuthAlgorithm algo1_tbl[] = { 887 MHD_DIGEST_ALG_AUTO, 888 MHD_DIGEST_ALG_MD5, 889 MHD_DIGEST_ALG_SHA256, 890 MHD_DIGEST_ALG_AUTO 891 }; 892 893 static const enum MHD_DigestAuthAlgo3 algo3_tbl[] = { 894 MHD_DIGEST_AUTH_ALGO3_MD5, 895 MHD_DIGEST_AUTH_ALGO3_SHA256, 896 MHD_DIGEST_AUTH_ALGO3_SHA512_256, 897 MHD_DIGEST_AUTH_ALGO3_MD5_SESSION, 898 MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION, 899 MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION, 900 MHD_DIGEST_AUTH_ALGO3_MD5, 901 MHD_DIGEST_AUTH_ALGO3_SHA256 902 }; 903 904 /** Outcome of run_digest_check(). */ 905 #define DAUTH_CHALLENGE 0 906 #define DAUTH_PASSED 1 907 #define DAUTH_STALE 2 908 909 910 /** 911 * Exercise the digest helpers that take no connection: 912 * MHD_digest_get_hash_size(), MHD_digest_auth_calc_userdigest(), 913 * MHD_digest_auth_calc_userhash() and 914 * MHD_digest_auth_calc_userhash_hex(). 915 * 916 * The output buffers are heap allocations of *exactly* the size that is 917 * passed to MHD, and that size is deliberately varied down to zero. A 918 * correct implementation must reject every buffer that is too small; if 919 * it instead writes the full digest, ASAN's redzone catches it 920 * immediately. This is the shape of the bug fixed in commit 5a73c1ae, 921 * where an over-long userhash overflowed a fixed-size decode buffer. 922 */ 923 static void 924 call_calc_helpers (void) 925 { 926 enum MHD_DigestAuthAlgo3 a = algo3_tbl[cfg.hdr_seed 927 % (sizeof (algo3_tbl) 928 / sizeof (algo3_tbl[0]))]; 929 size_t hs; 930 size_t claim; 931 void *bin; 932 char *hex; 933 934 hs = MHD_digest_get_hash_size (a); 935 if ( (0 == hs) || 936 (hs > MAX_DIGEST_BIN) ) 937 return; 938 claim = hs - (size_t) (cfg.crc_seed % (unsigned int) (hs + 1u)); 939 940 bin = malloc (claim); 941 if (NULL != bin) 942 { 943 (void) MHD_digest_auth_calc_userdigest (a, 944 DIGEST_USER, 945 DIGEST_REALM, 946 DIGEST_PASS, 947 bin, 948 claim); 949 (void) MHD_digest_auth_calc_userhash (a, 950 DIGEST_USER, 951 DIGEST_REALM, 952 bin, 953 claim); 954 free (bin); 955 } 956 /* The hex form needs 2*hs+1 bytes; ask for less about half the time. */ 957 claim = (2u * hs + 1u) 958 - (size_t) (cfg.hdr_seed % (unsigned int) (2u * hs + 2u)); 959 hex = (char *) malloc (claim); 960 if (NULL != hex) 961 { 962 (void) MHD_digest_auth_calc_userhash_hex (a, 963 DIGEST_USER, 964 DIGEST_REALM, 965 hex, 966 claim); 967 free (hex); 968 } 969 } 970 971 972 /** 973 * Run the digest-authentication entry point selected by byte 5. 974 * 975 * Variant 0 is MHD_digest_auth_check3(), which is the plainest one and 976 * what the all-zero configuration selects. Variants 1-5 are the v1/v2 compatibility 977 * wrappers and the pre-computed-digest forms, which do their own buffer 978 * sizing and are therefore worth driving directly. Variants 6-8 are 979 * the query functions, which parse the client's Authorization header 980 * but return no verdict, so they run *in addition* to check3(). 981 * 982 * @return one of DAUTH_CHALLENGE, DAUTH_PASSED, DAUTH_STALE 983 */ 984 static int 985 run_digest_check (struct MHD_Connection *connection) 986 { 987 unsigned int variant = cfg.dauth_variant; 988 enum MHD_DigestAuthResult dres; 989 uint8_t ud[MAX_DIGEST_BIN]; 990 size_t hs; 991 int r1; 992 volatile size_t sink = 0; 993 994 switch (variant) 995 { 996 case 1: 997 r1 = MHD_digest_auth_check (connection, 998 DIGEST_REALM, 999 DIGEST_USER, 1000 DIGEST_PASS, 1001 0); 1002 if (MHD_YES == r1) 1003 return DAUTH_PASSED; 1004 return (MHD_INVALID_NONCE == r1) ? DAUTH_STALE : DAUTH_CHALLENGE; 1005 case 2: 1006 r1 = MHD_digest_auth_check2 (connection, 1007 DIGEST_REALM, 1008 DIGEST_USER, 1009 DIGEST_PASS, 1010 0, 1011 algo1_tbl[cfg.hdr_seed & 0x03]); 1012 if (MHD_YES == r1) 1013 return DAUTH_PASSED; 1014 return (MHD_INVALID_NONCE == r1) ? DAUTH_STALE : DAUTH_CHALLENGE; 1015 case 3: 1016 /* MHD_digest_auth_check_digest() is MD5-only by definition. */ 1017 if (MHD_YES != MHD_digest_auth_calc_userdigest ( 1018 MHD_DIGEST_AUTH_ALGO3_MD5, 1019 DIGEST_USER, DIGEST_REALM, DIGEST_PASS, 1020 ud, MHD_MD5_DIGEST_SIZE)) 1021 break; 1022 r1 = MHD_digest_auth_check_digest (connection, 1023 DIGEST_REALM, 1024 DIGEST_USER, 1025 ud, 1026 0); 1027 if (MHD_YES == r1) 1028 return DAUTH_PASSED; 1029 return (MHD_INVALID_NONCE == r1) ? DAUTH_STALE : DAUTH_CHALLENGE; 1030 case 4: 1031 case 5: 1032 { 1033 /* The pre-computed-digest entry points are stricter than the 1034 password-based ones: the digest and the algorithm have to 1035 agree, and naming more than one base hashing algorithm is an 1036 MHD_PANIC("API violation") rather than an error return. So the 1037 algorithm is chosen first here and the digest, its length and 1038 the algorithm argument are all derived from that one choice. 1039 1040 MHD_DIGEST_ALG_AUTO is deliberately not used for variant 4: 1041 MHD_digest_auth_check_digest2() maps it to 1042 MULT_ALGO3_ANY_NON_SESSION, which names three base algorithms 1043 and therefore trips that very panic. See README section 6. */ 1044 static const enum MHD_DigestAuthAlgo3 digest_algos[] = { 1045 MHD_DIGEST_AUTH_ALGO3_MD5, 1046 MHD_DIGEST_AUTH_ALGO3_SHA256, 1047 MHD_DIGEST_AUTH_ALGO3_SHA512_256, 1048 MHD_DIGEST_AUTH_ALGO3_MD5_SESSION, 1049 MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION, 1050 MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION 1051 }; 1052 enum MHD_DigestAuthAlgo3 a3; 1053 1054 if (4 == variant) 1055 /* check_digest2() only knows MD5 and SHA-256. */ 1056 a3 = (0 != (cfg.hdr_seed & 0x01)) 1057 ? MHD_DIGEST_AUTH_ALGO3_SHA256 1058 : MHD_DIGEST_AUTH_ALGO3_MD5; 1059 else 1060 a3 = digest_algos[cfg.hdr_seed 1061 % (sizeof (digest_algos) 1062 / sizeof (digest_algos[0]))]; 1063 hs = MHD_digest_get_hash_size (a3); 1064 if ( (0 == hs) || 1065 (hs > sizeof (ud)) || 1066 (MHD_YES != MHD_digest_auth_calc_userdigest (a3, 1067 DIGEST_USER, 1068 DIGEST_REALM, 1069 DIGEST_PASS, 1070 ud, 1071 hs)) ) 1072 break; 1073 if (4 == variant) 1074 { 1075 r1 = MHD_digest_auth_check_digest2 (connection, 1076 DIGEST_REALM, 1077 DIGEST_USER, 1078 ud, 1079 hs, 1080 0, 1081 (MHD_DIGEST_AUTH_ALGO3_SHA256 == a3) 1082 ? MHD_DIGEST_ALG_SHA256 1083 : MHD_DIGEST_ALG_MD5); 1084 if (MHD_YES == r1) 1085 return DAUTH_PASSED; 1086 return (MHD_INVALID_NONCE == r1) ? DAUTH_STALE : DAUTH_CHALLENGE; 1087 } 1088 dres = MHD_digest_auth_check_digest3 (connection, 1089 DIGEST_REALM, 1090 DIGEST_USER, 1091 ud, 1092 hs, 1093 0, 1094 0, 1095 cfg.qop, 1096 /* Exactly one base algorithm. 1097 The MULT_ALGO3_* constants are 1098 numerically identical to their 1099 ALGO3_* counterparts. */ 1100 (enum MHD_DigestAuthMultiAlgo3) a3); 1101 if (MHD_DAUTH_OK == dres) 1102 return DAUTH_PASSED; 1103 return (MHD_DAUTH_NONCE_STALE == dres) ? DAUTH_STALE : DAUTH_CHALLENGE; 1104 } 1105 case 6: 1106 { 1107 char *u = MHD_digest_auth_get_username (connection); 1108 1109 if (NULL != u) 1110 { 1111 sink += strlen (u); 1112 MHD_free (u); 1113 } 1114 } 1115 break; 1116 case 7: 1117 { 1118 struct MHD_DigestAuthUsernameInfo *ui; 1119 1120 ui = MHD_digest_auth_get_username3 (connection); 1121 if (NULL != ui) 1122 { 1123 if (NULL != ui->username) 1124 sink += ui->username_len; 1125 if (NULL != ui->userhash_hex) 1126 sink += ui->userhash_hex_len; 1127 MHD_free (ui); 1128 } 1129 } 1130 break; 1131 case 8: 1132 { 1133 struct MHD_DigestAuthInfo *ai; 1134 1135 ai = MHD_digest_auth_get_request_info3 (connection); 1136 if (NULL != ai) 1137 { 1138 if (NULL != ai->username) 1139 sink += ai->username_len; 1140 if (NULL != ai->realm) 1141 sink += ai->realm_len; 1142 if (NULL != ai->opaque) 1143 sink += ai->opaque_len; 1144 if (NULL != ai->userhash_hex) 1145 sink += ai->userhash_hex_len; 1146 sink += ai->cnonce_len; 1147 sink += (size_t) ai->nc; 1148 MHD_free (ai); 1149 } 1150 } 1151 break; 1152 default: 1153 break; 1154 } 1155 (void) sink; 1156 1157 /* Variant 0, the query variants and every early break end up here. */ 1158 dres = MHD_digest_auth_check3 (connection, 1159 DIGEST_REALM, 1160 DIGEST_USER, 1161 DIGEST_PASS, 1162 0 /* daemon default nonce timeout */, 1163 0 /* daemon default max_nc */, 1164 cfg.qop, 1165 MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION); 1166 if (MHD_DAUTH_OK == dres) 1167 return DAUTH_PASSED; 1168 return (MHD_DAUTH_NONCE_STALE == dres) ? DAUTH_STALE : DAUTH_CHALLENGE; 1169 } 1170 1171 1172 /** 1173 * Send the "authentication required" reply through the variant of the 1174 * API selected by byte 5. The v1/v2 forms take a plain response and an 1175 * algorithm rather than the qop/algo pair of the v3 form. 1176 */ 1177 static enum MHD_Result 1178 queue_auth_challenge (struct MHD_Connection *connection, 1179 int stale) 1180 { 1181 struct MHD_Response *resp; 1182 enum MHD_Result ret; 1183 1184 resp = MHD_create_response_from_buffer_static (0, ""); 1185 if (NULL == resp) 1186 return MHD_NO; 1187 switch (cfg.fail_variant) 1188 { 1189 case 1: 1190 ret = MHD_queue_auth_fail_response (connection, 1191 DIGEST_REALM, 1192 "0123456789abcdef", 1193 resp, 1194 stale ? MHD_YES : MHD_NO); 1195 break; 1196 case 2: 1197 ret = MHD_queue_auth_fail_response2 (connection, 1198 DIGEST_REALM, 1199 "0123456789abcdef", 1200 resp, 1201 stale ? MHD_YES : MHD_NO, 1202 algo1_tbl[cfg.hdr_seed & 0x03]); 1203 break; 1204 case 3: 1205 if (0 != (cfg.hdr_seed & 0x01)) 1206 ret = MHD_queue_basic_auth_required_response3 (connection, 1207 DIGEST_REALM, 1208 (0 != (cfg.hdr_seed 1209 & 0x02)) 1210 ? MHD_YES : MHD_NO, 1211 resp); 1212 else 1213 ret = MHD_queue_basic_auth_fail_response (connection, 1214 DIGEST_REALM, 1215 resp); 1216 break; 1217 case 0: 1218 default: 1219 ret = MHD_queue_auth_required_response3 (connection, 1220 DIGEST_REALM, 1221 "0123456789abcdef" /* opaque */, 1222 "/", 1223 resp, 1224 stale ? MHD_YES : MHD_NO, 1225 cfg.qop, 1226 cfg.algo, 1227 MHD_YES /* userhash */, 1228 MHD_NO); 1229 break; 1230 } 1231 MHD_destroy_response (resp); 1232 return ret; 1233 } 1234 1235 1236 /* ------------------------------------------------------------------ */ 1237 /* Configuration byte 6: connection introspection */ 1238 /* ------------------------------------------------------------------ */ 1239 1240 /** 1241 * Call the read-only connection accessors on attacker-supplied header 1242 * data. MHD_lookup_connection_value*() run the case-insensitive header 1243 * matcher over whatever the client sent, which is exactly the sort of 1244 * input the fuzzer is good at producing. 1245 */ 1246 static void 1247 exercise_connection_api (struct MHD_Connection *connection) 1248 { 1249 volatile size_t sink = 0; 1250 1251 if (cfg.conn_lookup) 1252 { 1253 static const char *const keys[] = { 1254 "Host", "Content-Length", "Transfer-Encoding", "Authorization", 1255 "Cookie", "", "X-Fuzz", "connection" 1256 }; 1257 const char *k = keys[cfg.hdr_seed % (sizeof (keys) / sizeof (keys[0]))]; 1258 const char *v; 1259 const char *vp = NULL; 1260 size_t vlen = 0; 1261 const char *uri = NULL; 1262 size_t ulen = 0; 1263 1264 v = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, k); 1265 if (NULL != v) 1266 sink += strlen (v); 1267 if (MHD_YES == MHD_lookup_connection_value_n (connection, 1268 MHD_HEADER_KIND, 1269 k, 1270 strlen (k), 1271 &vp, 1272 &vlen)) 1273 sink += vlen; 1274 if (MHD_YES == MHD_get_connection_URI_path_n (connection, &uri, &ulen)) 1275 sink += ulen; 1276 } 1277 if (cfg.conn_setvalue) 1278 (void) MHD_set_connection_value (connection, 1279 MHD_HEADER_KIND, 1280 "X-Fuzz-Added", 1281 "1"); 1282 if (cfg.conn_info) 1283 { 1284 static const enum MHD_ConnectionInfoType cinfo[] = { 1285 MHD_CONNECTION_INFO_CLIENT_ADDRESS, 1286 MHD_CONNECTION_INFO_DAEMON, 1287 MHD_CONNECTION_INFO_CONNECTION_FD, 1288 MHD_CONNECTION_INFO_SOCKET_CONTEXT, 1289 MHD_CONNECTION_INFO_CONNECTION_SUSPENDED, 1290 MHD_CONNECTION_INFO_CONNECTION_TIMEOUT, 1291 MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE, 1292 MHD_CONNECTION_INFO_HTTP_STATUS 1293 }; 1294 static const enum MHD_DaemonInfoType dinfo[] = { 1295 MHD_DAEMON_INFO_CURRENT_CONNECTIONS, 1296 MHD_DAEMON_INFO_FLAGS, 1297 MHD_DAEMON_INFO_LISTEN_FD, 1298 MHD_DAEMON_INFO_BIND_PORT 1299 }; 1300 unsigned int i; 1301 1302 for (i = 0; i < sizeof (cinfo) / sizeof (cinfo[0]); i++) 1303 if (NULL != MHD_get_connection_info (connection, cinfo[i])) 1304 sink++; 1305 for (i = 0; i < sizeof (dinfo) / sizeof (dinfo[0]); i++) 1306 if ( (NULL != cur_daemon) && 1307 (NULL != MHD_get_daemon_info (cur_daemon, dinfo[i])) ) 1308 sink++; 1309 } 1310 if (cfg.conn_option) 1311 (void) MHD_set_connection_option (connection, 1312 MHD_CONNECTION_OPTION_TIMEOUT, 1313 (unsigned int) (cfg.crc_seed & 0x0F)); 1314 if (cfg.conn_info) 1315 { 1316 /* Constant-output accessors. They cannot fail on attacker input, 1317 but they are cheap and leaving them uncovered makes the coverage 1318 report harder to read. 1319 MHD_fini() is deliberately NOT called anywhere: it tears down 1320 process-global library state, so a single call would break every 1321 later iteration in the same process. */ 1322 const char *v = MHD_get_version (); 1323 1324 if (NULL != v) 1325 sink += strlen (v); 1326 sink += (size_t) MHD_get_version_bin (); 1327 } 1328 (void) sink; 1329 } 1330 1331 1332 /** 1333 * Suspend the connection if byte 7 asks for it. 1334 * 1335 * Mode 1 suspends and resumes straight away, which exercises both state 1336 * transitions without leaving the connection parked. Mode 2 leaves it 1337 * suspended and records it in @e pending_resume so that the pump loop 1338 * resumes it on its next round; completed_cb() drops the record, so a 1339 * connection MHD has finished with is never resumed after the fact, and 1340 * the iteration flushes the whole set before stopping the daemon. A 1341 * connection left suspended makes MHD_stop_daemon() MHD_PANIC(). 1342 */ 1343 static void 1344 suspend_maybe (struct MHD_Connection *connection) 1345 { 1346 if ( (0 == cfg.suspend_mode) || 1347 tearing_down) 1348 return; 1349 MHD_suspend_connection (connection); 1350 if (1 == cfg.suspend_mode) 1351 { 1352 MHD_resume_connection (connection); 1353 return; 1354 } 1355 pending_resume_add (connection); 1356 } 1357 1358 1359 static enum MHD_Result 1360 ahc (void *cls, 1361 struct MHD_Connection *connection, 1362 const char *url, 1363 const char *method, 1364 const char *version, 1365 const char *upload_data, 1366 size_t *upload_data_size, 1367 void **req_cls) 1368 { 1369 struct hstate *hs = (struct hstate *) *req_cls; 1370 struct MHD_Response *resp; 1371 enum MHD_Result ret; 1372 volatile size_t sink = 0; 1373 const char *conn_hdr = NULL; 1374 char conn_lc[128]; 1375 1376 conn_lc[0] = '\0'; 1377 (void) cls; 1378 if (NULL == hs) 1379 { 1380 hs = (struct hstate *) calloc (1, sizeof (struct hstate)); 1381 if (NULL == hs) 1382 return MHD_NO; 1383 *req_cls = hs; 1384 return MHD_YES; 1385 } 1386 1387 stat_handler_calls++; 1388 /* Touch the parsed request line the way a real application would. */ 1389 if (NULL != url) 1390 sink += strlen (url); 1391 if (NULL != method) 1392 sink += strlen (method); 1393 if (NULL != version) 1394 sink += strlen (version); 1395 (void) sink; 1396 1397 if (0 != *upload_data_size) 1398 { 1399 stat_body_bytes += (unsigned long) *upload_data_size; 1400 oracle_check_body (hs, upload_data, *upload_data_size); 1401 if (cfg.do_postproc) 1402 { 1403 if ( (NULL == hs->pp) && 1404 (! hs->pp_tried) ) 1405 { 1406 hs->pp_tried = 1; 1407 hs->pp = MHD_create_post_processor (connection, 1408 1024, 1409 &post_iter, 1410 NULL); 1411 } 1412 if (NULL != hs->pp) 1413 (void) MHD_post_process (hs->pp, upload_data, *upload_data_size); 1414 } 1415 *upload_data_size = 0; 1416 return MHD_YES; 1417 } 1418 1419 stat_final_calls++; 1420 if (cfg.do_iterate) 1421 { 1422 const enum MHD_ValueKind kinds = MHD_HEADER_KIND 1423 | MHD_GET_ARGUMENT_KIND 1424 | MHD_COOKIE_KIND 1425 | MHD_FOOTER_KIND; 1426 1427 /* Alternate between the NUL-terminated iterator and the 1428 length-aware one, which are separate code paths in MHD. */ 1429 if (0 != (cfg.hdr_seed & 0x10)) 1430 (void) MHD_get_connection_values_n (connection, kinds, &kv_iter_n, NULL); 1431 else 1432 (void) MHD_get_connection_values (connection, kinds, &kv_iter, NULL); 1433 } 1434 1435 if (oracle_on && 1436 (hs->body_off != expect_body_len) ) 1437 fuzz_report_finding ( 1438 "request body truncated: MHD completed the request but delivered " 1439 "fewer body bytes than the generated request contained"); 1440 1441 exercise_connection_api (connection); 1442 1443 /* Lower-cased copy of the request's "Connection" header, used by the 1444 upgrade check further down. MHD's own token matcher is internal, 1445 so a plain case-folded substring test is used here; it only has to 1446 be good enough to keep the harness from queueing an upgrade 1447 response on a connection that cannot be upgraded. */ 1448 if (cfg.allow_upgrade) 1449 { 1450 conn_hdr = MHD_lookup_connection_value (connection, 1451 MHD_HEADER_KIND, 1452 MHD_HTTP_HEADER_CONNECTION); 1453 if (NULL != conn_hdr) 1454 { 1455 size_t i; 1456 1457 for (i = 0; (i + 1 < sizeof (conn_lc)) && ('\0' != conn_hdr[i]); i++) 1458 conn_lc[i] = (char) (( ('A' <= conn_hdr[i]) && ('Z' >= conn_hdr[i])) 1459 ? (conn_hdr[i] - 'A' + 'a') : conn_hdr[i]); 1460 conn_lc[i] = '\0'; 1461 } 1462 } 1463 1464 if (cfg.do_basic) 1465 { 1466 if (cfg.basic_v1) 1467 { 1468 /* The v1 getter returns two separate malloc()ed strings and is 1469 the one that historically had to be freed by hand. */ 1470 char *pass = NULL; 1471 char *user; 1472 1473 user = MHD_basic_auth_get_username_password (connection, &pass); 1474 if (NULL != user) 1475 sink += strlen (user); 1476 if (NULL != pass) 1477 sink += strlen (pass); 1478 if (NULL != user) 1479 MHD_free (user); 1480 if (NULL != pass) 1481 MHD_free (pass); 1482 } 1483 else 1484 { 1485 struct MHD_BasicAuthInfo *bai; 1486 1487 bai = MHD_basic_auth_get_username_password3 (connection); 1488 if (NULL != bai) 1489 { 1490 if (NULL != bai->username) 1491 sink += bai->username_len; 1492 if (NULL != bai->password) 1493 sink += bai->password_len; 1494 MHD_free (bai); 1495 } 1496 } 1497 } 1498 1499 if (cfg.calc_helpers) 1500 call_calc_helpers (); 1501 1502 if (cfg.do_digest) 1503 { 1504 int dres = run_digest_check (connection); 1505 1506 if (DAUTH_PASSED == dres) 1507 stat_auth_ok++; 1508 else 1509 { 1510 stat_challenges++; 1511 return queue_auth_challenge (connection, DAUTH_STALE == dres); 1512 } 1513 } 1514 1515 /* Only answer 101 for a request that really is an upgrade request: 1516 HTTP/1.1, an "Upgrade" header, and a "Connection" header naming the 1517 upgrade token (RFC 9110 section 7.8). This is the check a real 1518 application performs, and all three inputs come off the wire, so 1519 the path stays fully attacker-driven. 1520 1521 It is deliberately NOT enough to predict whether MHD will accept 1522 the upgrade, and it is not meant to be: MHD may have decided during 1523 header parsing that the connection must close, and does not expose 1524 that decision. That used to trip 1525 mhd_assert (NULL == r->upgrade_handler || 1526 MHD_CONN_MUST_UPGRADE == c->keepalive) 1527 in build_header_response() -- finding K7, see README section 6, 1528 reproducer corpus/known-findings/K7-upgrade-after-must-close.bin -- 1529 and MHD_queue_response() now returns MHD_NO for it instead, which 1530 the code below already handles. Do not "fix" this by tightening 1531 the condition here: the check above is what an application can 1532 actually do, and the harness has to behave like one. */ 1533 if (cfg.allow_upgrade && 1534 (NULL != version) && 1535 (0 == strcmp (version, MHD_HTTP_VERSION_1_1)) && 1536 (NULL != MHD_lookup_connection_value (connection, 1537 MHD_HEADER_KIND, 1538 MHD_HTTP_HEADER_UPGRADE)) && 1539 (NULL != conn_hdr) && 1540 (NULL != strstr (conn_lc, "upgrade")) && 1541 (NULL == strstr (conn_lc, "close"))) 1542 { 1543 resp = MHD_create_response_for_upgrade (&upgrade_cb, NULL); 1544 if (NULL != resp) 1545 { 1546 /* Mandatory: MHD_create_response_for_upgrade() documents that the 1547 upgrade headers are the application's job, and 1548 MHD_response_execute_upgrade_() asserts that "Upgrade" is 1549 present before it hands the socket over. Omitting it is an 1550 application-contract violation, not something worth fuzzing. */ 1551 (void) MHD_add_response_header (resp, 1552 MHD_HTTP_HEADER_UPGRADE, 1553 "fuzz-protocol"); 1554 decorate_response (resp); 1555 ret = MHD_queue_response (connection, 1556 MHD_HTTP_SWITCHING_PROTOCOLS, 1557 resp); 1558 MHD_destroy_response (resp); 1559 return ret; 1560 } 1561 } 1562 1563 resp = make_response (); 1564 if (NULL == resp) 1565 return MHD_NO; 1566 ret = MHD_queue_response (connection, 1567 cfg.error_reply 1568 ? MHD_HTTP_FORBIDDEN : MHD_HTTP_OK, 1569 resp); 1570 MHD_destroy_response (resp); 1571 /* Only after a response was actually accepted. Returning MHD_NO 1572 tells MHD to terminate the connection, and terminating a connection 1573 that this callback has just suspended trips 1574 mhd_assert (! connection->suspended) in MHD_connection_close_(). 1575 That is the harness contradicting itself, not an MHD defect: the 1576 two requests are mutually exclusive by construction. (MHD_NO is 1577 reachable here for real -- MHD_queue_response() rejects, for 1578 instance, a response carrying MHD_RF_HEAD_ONLY_RESPONSE on a GET, 1579 which decorate_response() can set.) */ 1580 if (MHD_YES == ret) 1581 suspend_maybe (connection); 1582 return ret; 1583 } 1584 1585 1586 static void 1587 completed_cb (void *cls, 1588 struct MHD_Connection *connection, 1589 void **req_cls, 1590 enum MHD_RequestTerminationCode toe) 1591 { 1592 struct hstate *hs = (struct hstate *) *req_cls; 1593 1594 (void) cls; 1595 (void) toe; 1596 /* MHD is done with this connection, so the deferred resume of 1597 suspend mode 2 must not fire for it any more. */ 1598 pending_resume_drop (connection); 1599 if (NULL == hs) 1600 return; 1601 if (NULL != hs->pp) 1602 (void) MHD_destroy_post_processor (hs->pp); 1603 free (hs); 1604 *req_cls = NULL; 1605 } 1606 1607 1608 static void 1609 panic_cb (void *cls, 1610 const char *file, 1611 unsigned int line, 1612 const char *reason) 1613 { 1614 char msg[512]; 1615 1616 (void) cls; 1617 (void) snprintf (msg, sizeof (msg), 1618 "MHD_PANIC() reached from network input at %s:%u: %s", 1619 (NULL != file) ? file : "?", 1620 line, 1621 (NULL != reason) ? reason : "?"); 1622 fuzz_report_finding (msg); 1623 } 1624 1625 1626 /* ------------------------------------------------------------------ */ 1627 /* Driving the daemon */ 1628 /* ------------------------------------------------------------------ */ 1629 1630 /** 1631 * Read whatever the daemon has produced so far and look for a fresh 1632 * Digest-Auth nonce in it. 1633 */ 1634 static void 1635 drain_and_harvest (int sock) 1636 { 1637 for (;;) 1638 { 1639 ssize_t n; 1640 char tmp[4096]; 1641 1642 n = recv (sock, tmp, sizeof (tmp), MSG_DONTWAIT); 1643 if (0 >= n) 1644 break; 1645 if (resp_len + (size_t) n < RESP_BUF_SIZE) 1646 { 1647 memcpy (resp_buf + resp_len, tmp, (size_t) n); 1648 resp_len += (size_t) n; 1649 resp_buf[resp_len] = '\0'; 1650 } 1651 } 1652 if (0 != resp_len) 1653 { 1654 const char *p = resp_buf; 1655 1656 while (NULL != (p = strstr (p, "nonce=\""))) 1657 { 1658 const char *s = p + 7; 1659 const char *e = strchr (s, '"'); 1660 1661 p = s; 1662 if (NULL == e) 1663 break; 1664 if ((size_t) (e - s) < sizeof (nonce_val)) 1665 { 1666 memcpy (nonce_val, s, (size_t) (e - s)); 1667 nonce_len = (size_t) (e - s); 1668 nonce_val[nonce_len] = '\0'; 1669 } 1670 } 1671 } 1672 } 1673 1674 1675 /** 1676 * Advance the daemon by one cycle, through the event-loop API selected 1677 * by byte 6 of the input. 1678 * 1679 * Mode 0 is MHD_run(), which is what the harness used before the 1680 * extension and which does the descriptor bookkeeping internally. 1681 * Modes 1-3 drive the daemon the way an application with its own event 1682 * loop does: MHD_get_fdset*() to collect the descriptors, select(), then 1683 * MHD_run_from_select*(). That is the most common production 1684 * integration and none of it was reachable before. 1685 * 1686 * The select() timeout is always zero. The harness is single threaded 1687 * and whatever the daemon is waiting for has already been written into 1688 * the socketpair, so blocking would only burn wall clock; select() is 1689 * called purely to populate the ready sets. 1690 */ 1691 static void 1692 run_once (struct MHD_Daemon *d) 1693 { 1694 fd_set rs; 1695 fd_set ws; 1696 fd_set es; 1697 MHD_socket max_fd = MHD_INVALID_SOCKET; 1698 struct timeval tv; 1699 1700 if (0 == cfg.loop_mode) 1701 { 1702 (void) MHD_run (d); 1703 return; 1704 } 1705 FD_ZERO (&rs); 1706 FD_ZERO (&ws); 1707 FD_ZERO (&es); 1708 if (1 == cfg.loop_mode) 1709 { 1710 /* Parenthesised so that the real v1 function is called: 1711 microhttpd.h also defines MHD_get_fdset as a macro that forwards 1712 to MHD_get_fdset2 with FD_SETSIZE, so the unparenthesised name 1713 would never reach the v1 entry point at all. Same trick for 1714 MHD_run_from_select below. */ 1715 if (MHD_YES != (MHD_get_fdset) (d, &rs, &ws, &es, &max_fd)) 1716 { 1717 (void) MHD_run (d); 1718 return; 1719 } 1720 } 1721 else 1722 { 1723 if (MHD_YES != MHD_get_fdset2 (d, &rs, &ws, &es, &max_fd, 1724 (unsigned int) FD_SETSIZE)) 1725 { 1726 (void) MHD_run (d); 1727 return; 1728 } 1729 } 1730 if (cfg.use_timeouts) 1731 { 1732 MHD_UNSIGNED_LONG_LONG tl = 0; 1733 uint64_t t64 = 0; 1734 volatile int64_t sink; 1735 1736 (void) MHD_get_timeout (d, &tl); 1737 (void) MHD_get_timeout64 (d, &t64); 1738 sink = MHD_get_timeout64s (d); 1739 sink += (int64_t) MHD_get_timeout_i (d); 1740 (void) sink; 1741 } 1742 tv.tv_sec = 0; 1743 tv.tv_usec = 0; 1744 if (MHD_INVALID_SOCKET != max_fd) 1745 (void) select ((int) max_fd + 1, &rs, &ws, &es, &tv); 1746 if (1 == cfg.loop_mode) 1747 (void) (MHD_run_from_select) (d, &rs, &ws, &es); 1748 else 1749 (void) MHD_run_from_select2 (d, &rs, &ws, &es, (unsigned int) FD_SETSIZE); 1750 } 1751 1752 1753 static void 1754 pump (struct MHD_Daemon *d, 1755 int sock, 1756 unsigned int rounds) 1757 { 1758 unsigned int i; 1759 1760 for (i = 0; i < rounds; i++) 1761 { 1762 /* Deferred resume of suspend mode 2. Each slot is cleared before 1763 its connection is resumed, which keeps this correct even if the 1764 resume makes MHD complete (and forget) the connection, or run the 1765 handler again so that it suspends the same one anew. */ 1766 (void) pending_resume_flush (); 1767 run_once (d); 1768 drain_and_harvest (sock); 1769 } 1770 } 1771 1772 1773 /** 1774 * Copy @a in to @a out, expanding every occurrence of the ASCII token 1775 * "%%NONCE%%" to the harvested nonce. 1776 * 1777 * @return number of bytes written to @a out 1778 */ 1779 static size_t 1780 expand_nonce (const uint8_t *in, 1781 size_t in_len, 1782 uint8_t *out, 1783 size_t out_cap) 1784 { 1785 static const char tok[] = "%%NONCE%%"; 1786 const size_t tok_len = sizeof (tok) - 1; 1787 size_t i = 0; 1788 size_t o = 0; 1789 1790 while (i < in_len) 1791 { 1792 if ( (i + tok_len <= in_len) && 1793 (0 == memcmp (in + i, tok, tok_len)) ) 1794 { 1795 if (o + nonce_len > out_cap) 1796 break; 1797 memcpy (out + o, nonce_val, nonce_len); 1798 o += nonce_len; 1799 i += tok_len; 1800 continue; 1801 } 1802 if (o >= out_cap) 1803 break; 1804 out[o++] = in[i++]; 1805 } 1806 return o; 1807 } 1808 1809 1810 static void 1811 send_all (struct MHD_Daemon *d, 1812 int sock, 1813 const uint8_t *data, 1814 size_t len) 1815 { 1816 size_t off = 0; 1817 unsigned int stall = 0; 1818 1819 while ( (off < len) && 1820 (stall < 64) ) 1821 { 1822 ssize_t s = send (sock, data + off, len - off, MSG_DONTWAIT); 1823 1824 if (0 < s) 1825 { 1826 off += (size_t) s; 1827 stall = 0; 1828 continue; 1829 } 1830 stall++; 1831 pump (d, sock, 2); 1832 if ( (0 > s) && 1833 (EAGAIN != errno) && 1834 (EWOULDBLOCK != errno) && 1835 (EINTR != errno) ) 1836 break; 1837 } 1838 } 1839 1840 1841 static int 1842 new_connection (struct MHD_Daemon *d, 1843 int *sock) 1844 { 1845 int sv[2]; 1846 struct sockaddr_in sa; 1847 1848 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv)) 1849 return -1; 1850 memset (&sa, 0, sizeof (sa)); 1851 sa.sin_family = AF_INET; 1852 sa.sin_port = htons (44444); 1853 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 1854 if (MHD_YES != MHD_add_connection (d, 1855 (MHD_socket) sv[1], 1856 (const struct sockaddr *) &sa, 1857 (socklen_t) sizeof (sa))) 1858 { 1859 /* MHD has already closed sv[1] in that case */ 1860 (void) close (sv[0]); 1861 return -1; 1862 } 1863 *sock = sv[0]; 1864 return 0; 1865 } 1866 1867 1868 static void 1869 close_connection (struct MHD_Daemon *d, 1870 int *sock) 1871 { 1872 if (0 > *sock) 1873 return; 1874 (void) shutdown (*sock, SHUT_WR); 1875 pump (d, *sock, 4); 1876 (void) close (*sock); 1877 *sock = -1; 1878 } 1879 1880 1881 /* ------------------------------------------------------------------ */ 1882 /* The fuzz target */ 1883 /* ------------------------------------------------------------------ */ 1884 1885 int 1886 LLVMFuzzerTestOneInput (const uint8_t *data, 1887 size_t size) 1888 { 1889 struct MHD_Daemon *d; 1890 struct MHD_OptionItem opts[8]; 1891 unsigned int nopt = 0; 1892 unsigned int flags; 1893 int sock = -1; 1894 size_t pos; 1895 unsigned int nseg = 0; 1896 unsigned int nconn = 1; 1897 static uint8_t xbuf[FUZZ_MAX_INPUT + 4096]; 1898 1899 /* Must happen before the first write() into the socketpair. The 1900 built-in driver also does this from fuzz_install_handlers(), but 1901 that is compiled out under -DFUZZ_NO_MAIN, which is exactly the 1902 build every external fuzzing engine uses; the call is idempotent, 1903 so doing it from both places is harmless. See fuzz_ignore_sigpipe() 1904 in fuzz_common.h for why the process dies without it. */ 1905 fuzz_ignore_sigpipe (); 1906 1907 /* The ten configuration bytes are mandatory. Anything shorter has 1908 no segment stream either, so there is nothing to fuzz. */ 1909 if (size < 10) 1910 return 0; 1911 1912 nonce_len = 0; 1913 nonce_val[0] = '\0'; 1914 resp_len = 0; 1915 resp_buf[0] = '\0'; 1916 1917 memset (&cfg, 0, sizeof (cfg)); 1918 cfg.mem_limit = 1919 mem_limit_tbl[data[0] % (sizeof (mem_limit_tbl) 1920 / sizeof (mem_limit_tbl[0]))]; 1921 cfg.do_digest = (0 != (data[1] & 0x01)); 1922 cfg.do_basic = (0 != (data[1] & 0x02)); 1923 cfg.do_postproc = (0 != (data[1] & 0x04)); 1924 cfg.do_iterate = (0 != (data[1] & 0x08)); 1925 /* Bits 0x10 and 0x80 of byte 1 are unused. 0x10 used to gate the 1926 configuration bytes 4-9 back when they were optional; it is left 1927 free rather than reassigned so that the meaning of the corpus 1928 files written while it was a gate does not silently change. */ 1929 cfg.chunked_reply = (0 != (data[1] & 0x20)); 1930 cfg.error_reply = (0 != (data[1] & 0x40)); 1931 if (! min_mem_limit_read) 1932 { 1933 const char *e = getenv ("MHD_FUZZ_MIN_MEM_LIMIT"); 1934 1935 min_mem_limit_read = 1; 1936 if (NULL != e) 1937 min_mem_limit = (size_t) strtoul (e, NULL, 10); 1938 } 1939 if ( (0 != cfg.mem_limit) && 1940 (cfg.mem_limit < min_mem_limit) ) 1941 cfg.mem_limit = min_mem_limit; 1942 if (! min_discipline_read) 1943 { 1944 const char *e = getenv ("MHD_FUZZ_MIN_DISCIPLINE"); 1945 1946 min_discipline_read = 1; 1947 if (NULL != e) 1948 min_discipline = atoi (e); 1949 } 1950 cfg.discipline = 1951 discipline_tbl[(data[2] & 0x0F) % (sizeof (discipline_tbl) 1952 / sizeof (discipline_tbl[0]))]; 1953 if (cfg.discipline < min_discipline) 1954 cfg.discipline = min_discipline; 1955 cfg.insanity = (unsigned int) MHD_DSC_SANE; 1956 cfg.algo = algo_tbl[data[3] & 0x03]; 1957 cfg.qop = (0 != (data[3] & 0x04)) 1958 ? MHD_DIGEST_AUTH_MULT_QOP_AUTH 1959 : MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT; 1960 cfg.nonce_nc_size = nnc_tbl[(data[3] >> 4) & 0x03]; 1961 1962 cfg.resp_kind = (unsigned int) (data[4] & 0x0F); 1963 cfg.resp_nhdr = (unsigned int) ((data[4] >> 4) & 0x03); 1964 cfg.resp_footer = (0 != (data[4] & 0x40)); 1965 cfg.resp_hdr_api = (0 != (data[4] & 0x80)); 1966 1967 cfg.dauth_variant = (unsigned int) (data[5] & 0x0F) % DAUTH_VARIANT_COUNT; 1968 cfg.fail_variant = (unsigned int) ((data[5] >> 4) & 0x03); 1969 cfg.basic_v1 = (0 != (data[5] & 0x40)); 1970 cfg.calc_helpers = (0 != (data[5] & 0x80)); 1971 1972 cfg.loop_mode = (unsigned int) (data[6] & 0x03); 1973 cfg.use_timeouts = (0 != (data[6] & 0x04)); 1974 cfg.conn_lookup = (0 != (data[6] & 0x08)); 1975 cfg.conn_setvalue = (0 != (data[6] & 0x10)); 1976 cfg.conn_info = (0 != (data[6] & 0x20)); 1977 cfg.conn_option = (0 != (data[6] & 0x40)); 1978 cfg.quiesce = (0 != (data[6] & 0x80)); 1979 1980 /* Only modes 0-2 exist; 3 folds onto the immediate-resume mode 1981 rather than being a fourth, unimplemented behaviour. */ 1982 cfg.suspend_mode = (unsigned int) (data[7] & 0x03); 1983 if (3 == cfg.suspend_mode) 1984 cfg.suspend_mode = 1; 1985 cfg.allow_upgrade = 1986 (0 != (data[7] & 0x04)) && 1987 (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_UPGRADE)); 1988 cfg.upgrade_action = (unsigned int) ((data[7] >> 3) & 0x03); 1989 1990 cfg.hdr_seed = data[8]; 1991 cfg.crc_seed = data[9]; 1992 1993 oracle_on = 0; 1994 expect_body_len = 0; 1995 /* Must never carry over: the connections these pointed at belonged to 1996 the previous iteration's daemon and are long gone. */ 1997 memset (pending_resume, 0, sizeof (pending_resume)); 1998 tearing_down = 0; 1999 2000 if (0 != cfg.mem_limit) 2001 { 2002 opts[nopt].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT; 2003 opts[nopt].value = (intptr_t) cfg.mem_limit; 2004 opts[nopt].ptr_value = NULL; 2005 nopt++; 2006 } 2007 opts[nopt].option = MHD_OPTION_CLIENT_DISCIPLINE_LVL; 2008 opts[nopt].value = (intptr_t) cfg.discipline; 2009 opts[nopt].ptr_value = NULL; 2010 nopt++; 2011 opts[nopt].option = MHD_OPTION_SERVER_INSANITY; 2012 opts[nopt].value = (intptr_t) cfg.insanity; 2013 opts[nopt].ptr_value = NULL; 2014 nopt++; 2015 opts[nopt].option = MHD_OPTION_NONCE_NC_SIZE; 2016 opts[nopt].value = (intptr_t) cfg.nonce_nc_size; 2017 opts[nopt].ptr_value = NULL; 2018 nopt++; 2019 opts[nopt].option = MHD_OPTION_DIGEST_AUTH_RANDOM; 2020 opts[nopt].value = (intptr_t) sizeof (digest_rnd); 2021 opts[nopt].ptr_value = (void *) (intptr_t) digest_rnd; 2022 nopt++; 2023 opts[nopt].option = MHD_OPTION_END; 2024 opts[nopt].value = 0; 2025 opts[nopt].ptr_value = NULL; 2026 2027 flags = MHD_USE_NO_LISTEN_SOCKET; 2028 if (fuzz_verbose) 2029 flags |= MHD_USE_ERROR_LOG; 2030 if (0 != cfg.suspend_mode) 2031 flags |= MHD_ALLOW_SUSPEND_RESUME; 2032 if (cfg.allow_upgrade) 2033 flags |= MHD_ALLOW_UPGRADE; 2034 2035 MHD_set_panic_func (&panic_cb, NULL); 2036 d = MHD_start_daemon (flags, 2037 0, 2038 NULL, NULL, 2039 &ahc, NULL, 2040 MHD_OPTION_ARRAY, opts, 2041 /* passed through the varargs rather than through 2042 the option array: storing a function pointer in 2043 the array's intptr_t member is not strictly 2044 conforming C */ 2045 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL, 2046 MHD_OPTION_END); 2047 if (NULL == d) 2048 return 0; 2049 cur_daemon = d; 2050 stat_daemons++; 2051 if (! stats_registered) 2052 { 2053 stats_registered = 1; 2054 (void) atexit (&print_stats); 2055 } 2056 2057 if (0 != new_connection (d, &sock)) 2058 { 2059 MHD_stop_daemon (d); 2060 cur_daemon = NULL; 2061 return 0; 2062 } 2063 2064 pos = 10u; 2065 while ( (pos + 2 <= size) && 2066 (nseg < MAX_SEGMENTS) ) 2067 { 2068 unsigned int hdr = (unsigned int) data[pos] 2069 | ((unsigned int) data[pos + 1] << 8); 2070 unsigned int op = hdr >> 14; 2071 size_t slen = (size_t) (hdr & 0x3FFF); 2072 size_t elen; 2073 2074 pos += 2; 2075 nseg++; 2076 if (slen > size - pos) 2077 slen = size - pos; 2078 2079 if (1 == op) 2080 { 2081 /* Ground-truth declaration, not wire data. */ 2082 if (fuzz_pristine && (slen <= MAX_EXPECT_BODY)) 2083 { 2084 memcpy (expect_body, data + pos, slen); 2085 expect_body_len = slen; 2086 oracle_on = 1; 2087 } 2088 pos += slen; 2089 continue; 2090 } 2091 if ( (3 == op) && 2092 (nconn < MAX_CONNECTIONS) ) 2093 { 2094 close_connection (d, &sock); 2095 if (0 != new_connection (d, &sock)) 2096 break; 2097 nconn++; 2098 } 2099 2100 elen = expand_nonce (data + pos, slen, xbuf, sizeof (xbuf)); 2101 pos += slen; 2102 if (0 != elen) 2103 send_all (d, sock, xbuf, elen); 2104 pump (d, sock, (2 == op) ? 12u : 3u); 2105 if (0 == slen) 2106 pump (d, sock, 4); 2107 } 2108 2109 close_connection (d, &sock); 2110 pump (d, sock, 4); 2111 /* A connection left suspended makes MHD_stop_daemon() MHD_PANIC() 2112 ("called while we have suspended connections"), and 2113 MHD_resume_connection() alone is not enough: it only raises a flag, 2114 and the connection is taken off the daemon's suspended list by 2115 MHD_run(). So flush and run until nothing is parked any more. 2116 tearing_down stops the handler from parking anything new, which is 2117 what bounds this loop; the cap is only a backstop. */ 2118 tearing_down = 1; 2119 { 2120 unsigned int i; 2121 2122 for (i = 0; i < MAX_CONNECTIONS + 2u; i++) 2123 { 2124 if (! pending_resume_flush ()) 2125 break; 2126 (void) MHD_run (d); 2127 } 2128 } 2129 if (cfg.quiesce) 2130 (void) MHD_quiesce_daemon (d); 2131 MHD_stop_daemon (d); 2132 cur_daemon = NULL; 2133 return 0; 2134 } 2135 2136 2137 /* ------------------------------------------------------------------ */ 2138 /* Structure-aware HTTP request generator */ 2139 /* ------------------------------------------------------------------ */ 2140 2141 struct sbuf 2142 { 2143 uint8_t *p; 2144 size_t len; 2145 size_t cap; 2146 }; 2147 2148 2149 static void 2150 sb_raw (struct sbuf *b, 2151 const void *v, 2152 size_t n) 2153 { 2154 if (b->len + n > b->cap) 2155 n = b->cap - b->len; 2156 memcpy (b->p + b->len, v, n); 2157 b->len += n; 2158 } 2159 2160 2161 static void 2162 sb_str (struct sbuf *b, 2163 const char *s) 2164 { 2165 sb_raw (b, s, strlen (s)); 2166 } 2167 2168 2169 static void 2170 sb_u64 (struct sbuf *b, 2171 uint64_t v, 2172 int hex, 2173 unsigned int min_digits) 2174 { 2175 char tmp[32]; 2176 unsigned int n = 0; 2177 2178 do 2179 { 2180 unsigned int dig = (unsigned int) (v % (hex ? 16u : 10u)); 2181 tmp[n++] = (char) ((dig < 10) ? ('0' + dig) : ('a' + dig - 10)); 2182 v /= (hex ? 16u : 10u); 2183 } 2184 while ( (0 != v) && (n < sizeof (tmp)) ); 2185 while ( (n < min_digits) && (n < sizeof (tmp)) ) 2186 tmp[n++] = '0'; 2187 while (0 != n) 2188 { 2189 char c = tmp[--n]; 2190 sb_raw (b, &c, 1); 2191 } 2192 } 2193 2194 2195 static const char *const gen_methods[] = { 2196 "GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE", "PATCH", 2197 "CONNECT", "BREW", "get", "M-SEARCH", "\tGET", "GET " 2198 }; 2199 2200 static const char *const gen_versions[] = { 2201 "HTTP/1.1", "HTTP/1.0", "HTTP/1.1", "HTTP/1.1", "HTTP/0.9", "HTTP/1.2", 2202 "HTTP/2.0", "http/1.1", "HTTP/1.", "HTTP/11" 2203 }; 2204 2205 static const char *const gen_targets[] = { 2206 "/", "/a", "/a/b/c", "/a?x=1", "/a?x=1&y=2", "/?novalue", "/?a=1&b", 2207 "/?a&b&c", "/%41%42", "/a%00b", "/%zz", "/a?%41=%42", "*", 2208 "http://example.org/a", "/a?x=1&novalue", "/..%2f..%2fetc", 2209 "/a?=", "/a?&", "/very/long/path/that/keeps/going/and/going/and/going" 2210 }; 2211 2212 static const char *const gen_hdr_names[] = { 2213 "Host", "Accept", "User-Agent", "Connection", "Cookie", "Content-Type", 2214 "Expect", "TE", "Trailer", "X-Custom", "Referer", "Accept-Encoding", 2215 "content-length", "transfer-encoding", "X-A-Very-Long-Header-Name-Indeed" 2216 }; 2217 2218 static const char *const gen_hdr_values[] = { 2219 "example.org", "*/*", "fuzz/1.0", "keep-alive", "close", 2220 "a=1; b=2; c", "100-continue", "trailers", "X-Trail", "value", 2221 "", " ", "\ttabbed", "a, b, c", "chunked", "identity, chunked" 2222 }; 2223 2224 /** Deliberately includes tokens MHD does not know: bug #1 lives here. */ 2225 static const char *const gen_algos[] = { 2226 "MD5", "SHA-256", "SHA-512-256", "MD5-sess", "SHA-256-sess", 2227 "SHA-512-256-sess", "sha-256", "SHA256", "BOGUS", "", "\"SHA-256\"", 2228 "MD5 ", "SHA-1", "xyzzy", "SHA-512", "\"BOGUS\"", "0" 2229 }; 2230 2231 static const char *const gen_ctypes[] = { 2232 "application/x-www-form-urlencoded", 2233 "multipart/form-data; boundary=--abc", 2234 "multipart/form-data; boundary=\"XY\"", 2235 "multipart/form-data", 2236 "text/plain" 2237 }; 2238 2239 2240 /** 2241 * Append a random query string, optionally ending in an argument 2242 * without '=' (which is the shape needed for the read-buffer shift-back 2243 * bug). 2244 */ 2245 static void 2246 gen_query (struct fuzz_rng *rng, 2247 struct sbuf *b, 2248 int force_trailing_novalue) 2249 { 2250 unsigned int n = fuzz_below (rng, 4); 2251 unsigned int i; 2252 2253 if ( (0 == n) && (! force_trailing_novalue) ) 2254 return; 2255 sb_str (b, "?"); 2256 for (i = 0; i < n; i++) 2257 { 2258 if (0 != i) 2259 sb_str (b, "&"); 2260 sb_str (b, "k"); 2261 sb_u64 (b, i, 0, 1); 2262 if (! fuzz_chance (rng, 3)) 2263 { 2264 sb_str (b, "="); 2265 sb_str (b, fuzz_chance (rng, 4) ? "%41%42" : "v"); 2266 } 2267 } 2268 if (force_trailing_novalue) 2269 { 2270 if (0 != n) 2271 sb_str (b, "&"); 2272 sb_str (b, "novalue"); 2273 } 2274 } 2275 2276 2277 static void 2278 gen_headers (struct fuzz_rng *rng, 2279 struct sbuf *b, 2280 unsigned int n) 2281 { 2282 unsigned int i; 2283 2284 for (i = 0; i < n; i++) 2285 { 2286 sb_str (b, gen_hdr_names[fuzz_below (rng, 2287 (uint32_t) (sizeof (gen_hdr_names) 2288 / sizeof (char *)))]); 2289 sb_str (b, fuzz_chance (rng, 8) ? " :" : ":"); 2290 if (! fuzz_chance (rng, 6)) 2291 sb_str (b, " "); 2292 sb_str (b, gen_hdr_values[fuzz_below (rng, 2293 (uint32_t) (sizeof (gen_hdr_values) 2294 / sizeof (char *)))]); 2295 if (fuzz_chance (rng, 12)) 2296 sb_str (b, "\r\n\tfolded-continuation"); 2297 if (fuzz_chance (rng, 20)) 2298 sb_str (b, "\n"); /* bare LF */ 2299 else if (fuzz_chance (rng, 25)) 2300 sb_str (b, "\r"); /* bare CR */ 2301 else 2302 sb_str (b, "\r\n"); 2303 } 2304 } 2305 2306 2307 /** 2308 * Emit a chunked body. When @a oracle is non-zero the body is 2309 * strictly RFC 9112 conformant and the decoded payload is recorded in 2310 * #expect_body, so that the harness can verify what MHD hands to the 2311 * application. Chunk extensions are emitted frequently on purpose. 2312 */ 2313 static void 2314 gen_chunked_body (struct fuzz_rng *rng, 2315 struct sbuf *b, 2316 int oracle) 2317 { 2318 unsigned int nchunks = 1 + fuzz_below (rng, 4); 2319 unsigned int i; 2320 2321 if (oracle) 2322 expect_body_len = 0; 2323 for (i = 0; i < nchunks; i++) 2324 { 2325 unsigned int clen = 1 + fuzz_below (rng, 24); 2326 unsigned int j; 2327 2328 sb_u64 (b, clen, 1, fuzz_chance (rng, 4) ? 4 : 1); 2329 /* chunk extension -- the parsing of the terminating CRLF of this 2330 very line was broken (bug #3) */ 2331 if (! fuzz_chance (rng, 2)) 2332 { 2333 switch (fuzz_below (rng, 5)) 2334 { 2335 case 0: 2336 sb_str (b, ";ext"); 2337 break; 2338 case 1: 2339 sb_str (b, ";ext=val"); 2340 break; 2341 case 2: 2342 sb_str (b, ";ext=\"quoted value\""); 2343 break; 2344 case 3: 2345 sb_str (b, ";a=1;b=2;c"); 2346 break; 2347 default: 2348 sb_str (b, ";x=\"a;b\""); 2349 break; 2350 } 2351 } 2352 sb_str (b, "\r\n"); 2353 for (j = 0; j < clen; j++) 2354 { 2355 char c = (char) ('A' + ((i * 7 + j) % 26)); 2356 2357 sb_raw (b, &c, 1); 2358 if (oracle && (expect_body_len < MAX_EXPECT_BODY)) 2359 expect_body[expect_body_len++] = (uint8_t) c; 2360 } 2361 sb_str (b, "\r\n"); 2362 } 2363 sb_str (b, "0"); 2364 if (fuzz_chance (rng, 4)) 2365 sb_str (b, ";final=\"x\""); 2366 sb_str (b, "\r\n"); 2367 if (fuzz_chance (rng, 3)) 2368 sb_str (b, "X-Trailer: value\r\n"); 2369 sb_str (b, "\r\n"); 2370 } 2371 2372 2373 static void 2374 gen_digest_header (struct fuzz_rng *rng, 2375 struct sbuf *b, 2376 const char *uri, 2377 int use_nonce_token, 2378 int overlong_response, 2379 int prefer_valid) 2380 { 2381 unsigned int nresp; 2382 unsigned int i; 2383 2384 sb_str (b, "Authorization: Digest "); 2385 sb_str (b, "username=\""); 2386 if (fuzz_chance (rng, prefer_valid ? 20 : 6)) 2387 { 2388 /* userhash notation: a long hex string is accepted here too */ 2389 unsigned int n = 2 * (16 + fuzz_below (rng, 48)); 2390 for (i = 0; i < n; i++) 2391 sb_str (b, "a"); 2392 } 2393 else 2394 sb_str (b, DIGEST_USER); 2395 sb_str (b, "\", "); 2396 if (fuzz_chance (rng, prefer_valid ? 25 : 8)) 2397 sb_str (b, "userhash=true, "); 2398 sb_str (b, "realm=\""); 2399 sb_str (b, fuzz_chance (rng, prefer_valid ? 25 : 8) 2400 ? "OtherRealm" : DIGEST_REALM); 2401 sb_str (b, "\", nonce=\""); 2402 if (use_nonce_token) 2403 sb_str (b, "%%NONCE%%"); 2404 else 2405 { 2406 unsigned int n = 8 + fuzz_below (rng, 80); 2407 for (i = 0; i < n; i++) 2408 sb_str (b, "0"); 2409 } 2410 sb_str (b, "\", uri=\""); 2411 sb_str (b, uri); 2412 sb_str (b, "\", qop="); 2413 sb_str (b, fuzz_chance (rng, prefer_valid ? 25 : 8) ? "auth-int" : "auth"); 2414 sb_str (b, ", nc="); 2415 sb_u64 (b, 1 + fuzz_below (rng, 3), 1, 8); 2416 sb_str (b, ", cnonce=\"deadbeef\", algorithm="); 2417 if (prefer_valid && (! fuzz_chance (rng, 5))) 2418 sb_str (b, "SHA-256"); /* must match the algorithm of the challenge */ 2419 else 2420 sb_str (b, gen_algos[fuzz_below (rng, 2421 (uint32_t) (sizeof (gen_algos) 2422 / sizeof (char *)))]); 2423 sb_str (b, ", opaque=\"0123456789abcdef\", response=\""); 2424 if (overlong_response) 2425 nresp = 66 + 2 * fuzz_below (rng, 32); /* 66 .. 128 hex digits */ 2426 else 2427 nresp = 2 * (1 + fuzz_below (rng, 66)); 2428 for (i = 0; i < nresp; i++) 2429 { 2430 char c = "0123456789abcdef"[fuzz_below (rng, 16)]; 2431 2432 sb_raw (b, &c, 1); 2433 } 2434 sb_str (b, "\"\r\n"); 2435 } 2436 2437 2438 enum gen_shape 2439 { 2440 SHAPE_PLAIN = 0, 2441 SHAPE_NOHDR_QARG, 2442 SHAPE_CL_BODY, 2443 SHAPE_CHUNKED, 2444 SHAPE_DIGEST_SIMPLE, 2445 SHAPE_DIGEST_REPLAY, 2446 SHAPE_BASIC, 2447 SHAPE_POST_FORM, 2448 SHAPE_WEIRD, 2449 SHAPE_COUNT 2450 }; 2451 2452 2453 /** 2454 * Build one HTTP request into @a b. 2455 * 2456 * @return non-zero if the request is exactly reproducible, i.e. the 2457 * #expect_body oracle may be used 2458 */ 2459 static int 2460 gen_one_request (struct fuzz_rng *rng, 2461 struct sbuf *b, 2462 enum gen_shape shape, 2463 int second_of_pair) 2464 { 2465 switch (shape) 2466 { 2467 case SHAPE_NOHDR_QARG: 2468 /* No header lines at all + a trailing query argument without '='; 2469 combined with a small connection memory pool this is the shape 2470 that reaches the read-buffer "shift back" computation. */ 2471 sb_str (b, "GET /"); 2472 gen_query (rng, b, 1); 2473 sb_str (b, " "); 2474 sb_str (b, fuzz_chance (rng, 2) ? "HTTP/1.0" : "HTTP/1.1"); 2475 sb_str (b, "\r\n\r\n"); 2476 return 0; 2477 2478 case SHAPE_CL_BODY: 2479 { 2480 unsigned int blen = fuzz_below (rng, 64); 2481 unsigned int i; 2482 2483 sb_str (b, "POST /a HTTP/1.1\r\nHost: x\r\nContent-Length: "); 2484 sb_u64 (b, blen, 0, 1); 2485 sb_str (b, "\r\n\r\n"); 2486 expect_body_len = 0; 2487 for (i = 0; i < blen; i++) 2488 { 2489 char c = (char) ('a' + (i % 26)); 2490 2491 sb_raw (b, &c, 1); 2492 if (expect_body_len < MAX_EXPECT_BODY) 2493 expect_body[expect_body_len++] = (uint8_t) c; 2494 } 2495 return 1; 2496 } 2497 2498 case SHAPE_CHUNKED: 2499 sb_str (b, "POST /a HTTP/1.1\r\nHost: x\r\n" 2500 "Transfer-Encoding: chunked\r\n\r\n"); 2501 gen_chunked_body (rng, b, 1); 2502 return 1; 2503 2504 case SHAPE_DIGEST_SIMPLE: 2505 sb_str (b, "GET /a HTTP/1.1\r\nHost: x\r\n"); 2506 gen_digest_header (rng, b, "/a", 0, fuzz_chance (rng, 2), 0); 2507 sb_str (b, "\r\n"); 2508 return 0; 2509 2510 case SHAPE_DIGEST_REPLAY: 2511 if (! second_of_pair) 2512 sb_str (b, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n"); 2513 else 2514 { 2515 sb_str (b, "GET /a HTTP/1.1\r\nHost: x\r\n"); 2516 gen_digest_header (rng, b, "/a", 1, 1, 1); 2517 sb_str (b, "\r\n"); 2518 } 2519 return 0; 2520 2521 case SHAPE_BASIC: 2522 sb_str (b, "GET /a HTTP/1.1\r\nHost: x\r\nAuthorization: Basic "); 2523 { 2524 unsigned int n = fuzz_below (rng, 40); 2525 unsigned int i; 2526 2527 for (i = 0; i < n; i++) 2528 { 2529 char c = 2530 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" 2531 [fuzz_below (rng, 65)]; 2532 2533 sb_raw (b, &c, 1); 2534 } 2535 } 2536 sb_str (b, "\r\n\r\n"); 2537 return 0; 2538 2539 case SHAPE_POST_FORM: 2540 { 2541 const char *ct = gen_ctypes[fuzz_below (rng, 2542 (uint32_t) (sizeof (gen_ctypes) 2543 / sizeof (char *)))]; 2544 2545 sb_str (b, "POST /a HTTP/1.1\r\nHost: x\r\nContent-Type: "); 2546 sb_str (b, ct); 2547 sb_str (b, "\r\nTransfer-Encoding: chunked\r\n\r\n"); 2548 gen_chunked_body (rng, b, 0); 2549 return 0; 2550 } 2551 2552 case SHAPE_WEIRD: 2553 sb_str (b, gen_methods[fuzz_below (rng, 2554 (uint32_t) (sizeof (gen_methods) 2555 / sizeof (char *)))]); 2556 sb_str (b, " "); 2557 sb_str (b, gen_targets[fuzz_below (rng, 2558 (uint32_t) (sizeof (gen_targets) 2559 / sizeof (char *)))]); 2560 sb_str (b, " "); 2561 sb_str (b, gen_versions[fuzz_below (rng, 2562 (uint32_t) (sizeof (gen_versions) 2563 / sizeof (char *)))]); 2564 sb_str (b, fuzz_chance (rng, 8) ? "\n" : "\r\n"); 2565 gen_headers (rng, b, fuzz_below (rng, 6)); 2566 sb_str (b, "\r\n"); 2567 return 0; 2568 2569 case SHAPE_PLAIN: 2570 case SHAPE_COUNT: 2571 default: 2572 sb_str (b, gen_methods[fuzz_below (rng, 3)]); 2573 sb_str (b, " /"); 2574 gen_query (rng, b, fuzz_chance (rng, 3)); 2575 sb_str (b, " HTTP/1.1\r\n"); 2576 gen_headers (rng, b, fuzz_below (rng, 4)); 2577 sb_str (b, "\r\n"); 2578 return 0; 2579 } 2580 } 2581 2582 2583 /** 2584 * Serialise @a body into the segment format understood by 2585 * LLVMFuzzerTestOneInput(), starting at @a out[*out_len]. 2586 */ 2587 static void 2588 emit_segments (struct fuzz_rng *rng, 2589 struct sbuf *out, 2590 const uint8_t *body, 2591 size_t body_len, 2592 int new_conn_first) 2593 { 2594 size_t off = 0; 2595 int first = 1; 2596 2597 while (off < body_len) 2598 { 2599 size_t chunk; 2600 unsigned int op; 2601 uint8_t hdr[2]; 2602 unsigned int hv; 2603 2604 switch (fuzz_below (rng, 6)) 2605 { 2606 case 0: 2607 chunk = 1; 2608 break; 2609 case 1: 2610 chunk = 2 + fuzz_below (rng, 6); 2611 break; 2612 case 2: 2613 chunk = 8 + fuzz_below (rng, 40); 2614 break; 2615 default: 2616 chunk = body_len - off; 2617 break; 2618 } 2619 if (chunk > body_len - off) 2620 chunk = body_len - off; 2621 if (chunk > 0x3FFF) 2622 chunk = 0x3FFF; 2623 op = (first && new_conn_first) ? 3u : (fuzz_chance (rng, 4) ? 2u : 0u); 2624 hv = (op << 14) | (unsigned int) chunk; 2625 hdr[0] = (uint8_t) (hv & 0xFF); 2626 hdr[1] = (uint8_t) (hv >> 8); 2627 if (out->len + 2 + chunk > out->cap) 2628 return; 2629 sb_raw (out, hdr, 2); 2630 sb_raw (out, body + off, chunk); 2631 off += chunk; 2632 first = 0; 2633 } 2634 } 2635 2636 2637 static size_t 2638 fuzz_generate (struct fuzz_rng *rng, 2639 uint8_t *buf, 2640 size_t cap) 2641 { 2642 struct sbuf out; 2643 uint8_t req[GEN_BUF_SIZE]; 2644 struct sbuf rb; 2645 enum gen_shape shape; 2646 uint8_t cfg_bytes[4]; 2647 int oracle; 2648 unsigned int nreq; 2649 unsigned int i; 2650 2651 expect_body_len = 0; 2652 2653 out.p = buf; 2654 out.len = 0; 2655 out.cap = cap; 2656 2657 if (! forced_shape_read) 2658 { 2659 const char *e = getenv ("MHD_FUZZ_SHAPE"); 2660 2661 forced_shape_read = 1; 2662 if (NULL != e) 2663 forced_shape = atoi (e); 2664 } 2665 if (0 <= forced_shape) 2666 shape = (enum gen_shape) (forced_shape % (int) SHAPE_COUNT); 2667 else 2668 shape = (enum gen_shape) fuzz_below (rng, (uint32_t) SHAPE_COUNT); 2669 2670 /* --- configuration bytes --- */ 2671 cfg_bytes[0] = fuzz_byte (rng); 2672 cfg_bytes[1] = fuzz_byte (rng); 2673 cfg_bytes[2] = fuzz_byte (rng); 2674 cfg_bytes[3] = fuzz_byte (rng); 2675 switch (shape) 2676 { 2677 case SHAPE_NOHDR_QARG: 2678 /* small connection memory pool: indices 1..9 of mem_limit_tbl */ 2679 cfg_bytes[0] = (uint8_t) (1 + fuzz_below (rng, 9)); 2680 break; 2681 case SHAPE_DIGEST_SIMPLE: 2682 case SHAPE_DIGEST_REPLAY: 2683 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 2) ? 0 : 12); 2684 cfg_bytes[1] = (uint8_t) ((cfg_bytes[1] | 0x01u) & ~0x04u); 2685 /* SHA-256 challenge: 32 byte digest -> 128 hex chars pass the 2686 'response' length check while hash1_bin[] is only 32 bytes */ 2687 cfg_bytes[3] = (uint8_t) ((cfg_bytes[3] & 0xF0u) | 0x00u); 2688 break; 2689 case SHAPE_POST_FORM: 2690 cfg_bytes[1] |= 0x04u; 2691 break; 2692 case SHAPE_CHUNKED: 2693 case SHAPE_CL_BODY: 2694 cfg_bytes[1] &= (uint8_t) ~0x04u; /* keep the body oracle clean */ 2695 break; 2696 default: 2697 break; 2698 } 2699 cfg_bytes[1] |= 0x08u; /* always iterate the values */ 2700 sb_raw (&out, cfg_bytes, 4); 2701 2702 nreq = (SHAPE_DIGEST_REPLAY == shape) ? 2u : (1u + (fuzz_chance (rng, 6) 2703 ? 1u : 0u)); 2704 oracle = 0; 2705 for (i = 0; i < nreq; i++) 2706 { 2707 rb.p = req; 2708 rb.len = 0; 2709 rb.cap = sizeof (req); 2710 oracle = gen_one_request (rng, &rb, shape, (int) i); 2711 if (oracle && (1 == nreq) && (expect_body_len <= MAX_EXPECT_BODY)) 2712 { 2713 /* Declare the ground truth for the body oracle (op 1). */ 2714 unsigned int hv = (1u << 14) | (unsigned int) expect_body_len; 2715 uint8_t hdr[2]; 2716 2717 hdr[0] = (uint8_t) (hv & 0xFF); 2718 hdr[1] = (uint8_t) (hv >> 8); 2719 sb_raw (&out, hdr, 2); 2720 sb_raw (&out, expect_body, expect_body_len); 2721 } 2722 emit_segments (rng, &out, req, rb.len, 2723 (0 != i) || fuzz_chance (rng, 8)); 2724 } 2725 (void) oracle; 2726 return out.len; 2727 } 2728 2729 2730 /* ------------------------------------------------------------------ */ 2731 /* Built-in seed corpus */ 2732 /* ------------------------------------------------------------------ */ 2733 2734 /** 2735 * The built-in seed corpus is described symbolically and rendered into 2736 * the wire format at run time, so that segment lengths never have to be 2737 * spelled out by hand. 2738 */ 2739 struct seed_part 2740 { 2741 unsigned int op; /**< 0 send, 1 expected body, 3 new conn */ 2742 const char *txt; /**< NUL terminated payload */ 2743 }; 2744 2745 struct seed_def 2746 { 2747 const char *name; 2748 unsigned char cfg[4]; 2749 struct seed_part parts[4]; 2750 /* Configuration bytes 4-9. Declared after @e parts so that a seed 2751 which only cares about the wire data can leave the member out of 2752 its brace initialiser and get the all-zero (plainest) setting. */ 2753 unsigned char ext[6]; 2754 }; 2755 2756 #define P_END { 0, NULL } 2757 2758 static const struct seed_def seeds[] = { 2759 /* There is deliberately no bare "GET / HTTP/1.1" seed: every seed 2760 below opens with a request at least as simple, so a plain one adds 2761 no coverage of its own (libFuzzer -merge=1 drops it). */ 2762 { "content-length-body", { 0x00, 0x08, 0x03, 0x00 }, 2763 { { 1, "hello" }, 2764 { 0, "POST /a HTTP/1.1\r\nHost: x\r\nContent-Length: 5\r\n\r\nhello" }, 2765 P_END, P_END } }, 2766 2767 /* chunk extensions: the terminating CRLF of the chunk-size line used 2768 to be left in the stream (bug #3, commit c13f4c64) */ 2769 { "chunked-with-extensions", { 0x00, 0x08, 0x03, 0x00 }, 2770 { { 1, "ABCDE" }, 2771 { 0, "POST /a HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\n" 2772 "\r\n2;ext=val\r\nAB\r\n3;a=\"b;c\"\r\nCDE\r\n0\r\n\r\n" }, 2773 P_END, P_END } }, 2774 2775 { "chunked-split", { 0x00, 0x08, 0x03, 0x00 }, 2776 { { 1, "ABCDEF" }, 2777 { 0, "POST /a HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\n" 2778 "\r\n3\r\nABC\r\n3;x=\"y\"" }, 2779 { 2, "\r\nDEF\r\n0\r\n\r\n" }, 2780 P_END } }, 2781 2782 /* small connection memory pool + trailing query argument without '=' 2783 and no header lines at all (bug #2, commit 29eaa56b) */ 2784 { "small-pool-trailing-query-arg", { 0x06, 0x08, 0x03, 0x00 }, 2785 { { 0, "GET /?novalue HTTP/1.0\r\n\r\n" }, P_END, P_END, P_END } }, 2786 2787 { "small-pool-trailing-query-arg-2", { 0x03, 0x08, 0x03, 0x00 }, 2788 { { 0, "GET /?a=1&b HTTP/1.0\r\n\r\n" }, P_END, P_END, P_END } }, 2789 2790 /* unrecognised 'algorithm' token -> MHD_DIGEST_AUTH_ALGO3_INVALID 2791 (bug #1, commit bd49ce93) */ 2792 { "digest-unknown-algorithm", { 0x00, 0x09, 0x03, 0x00 }, 2793 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\nAuthorization: Digest " 2794 "username=\"user\", realm=\"TestRealm\", nonce=\"0000\", " 2795 "uri=\"/a\", algorithm=BOGUS, response=\"00\"\r\n\r\n" }, 2796 P_END, P_END, P_END } }, 2797 2798 /* full digest handshake: harvest the nonce from the 401 and replay it 2799 with a 128 hex digit 'response' value (bug #4, commit 5a73c1ae) */ 2800 { "digest-overlong-response", { 0x00, 0x09, 0x03, 0x00 }, 2801 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" }, 2802 { 3, "GET /a HTTP/1.1\r\nHost: x\r\nAuthorization: Digest " 2803 "username=\"user\", realm=\"TestRealm\", nonce=\"%%NONCE%%\", " 2804 "uri=\"/a\", qop=auth, nc=00000001, cnonce=\"deadbeef\", " 2805 "algorithm=SHA-256, response=\"" 2806 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" 2807 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" 2808 "\"\r\n\r\n" }, 2809 P_END, P_END } }, 2810 2811 { "digest-userhash", { 0x00, 0x09, 0x03, 0x00 }, 2812 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" }, 2813 { 3, "GET /a HTTP/1.1\r\nHost: x\r\nAuthorization: Digest " 2814 "username=\"" 2815 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2816 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2817 "\", userhash=true, realm=\"TestRealm\", nonce=\"%%NONCE%%\", " 2818 "uri=\"/a\", qop=auth, nc=00000001, cnonce=\"deadbeef\", " 2819 "algorithm=SHA-256, response=\"0123456789abcdef\"\r\n\r\n" }, 2820 P_END, P_END } }, 2821 2822 { "basic-auth", { 0x00, 0x0a, 0x03, 0x00 }, 2823 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n" 2824 "Authorization: Basic dXNlcjpwYXNz\r\n\r\n" }, 2825 P_END, P_END, P_END } }, 2826 2827 { "multipart-post", { 0x00, 0x0c, 0x03, 0x00 }, 2828 { { 0, "POST /a HTTP/1.1\r\nHost: x\r\n" 2829 "Content-Type: multipart/form-data; boundary=--abc\r\n" 2830 "Transfer-Encoding: chunked\r\n\r\n" 2831 "52\r\n----abc\r\nContent-Disposition: form-data; name=\"k\"\r\n\r\n" 2832 "value\r\n----abc--\r\n\r\n0\r\n\r\n" }, 2833 P_END, P_END, P_END } }, 2834 2835 { "urlencoded-post", { 0x00, 0x0c, 0x03, 0x00 }, 2836 { { 1, "a=1&b=%41&c" }, 2837 { 0, "POST /a HTTP/1.1\r\nHost: x\r\n" 2838 "Content-Type: application/x-www-form-urlencoded\r\n" 2839 "Content-Length: 11\r\n\r\na=1&b=%41&c" }, 2840 P_END, P_END } }, 2841 2842 { "folded-header", { 0x00, 0x08, 0x00, 0x00 }, 2843 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\nX-Fold: a\r\n\tb\r\n\r\n" }, 2844 P_END, P_END, P_END } }, 2845 2846 { "pipelined", { 0x00, 0x08, 0x03, 0x00 }, 2847 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" 2848 "GET /b?q HTTP/1.1\r\nHost: x\r\n\r\n" }, 2849 P_END, P_END, P_END } }, 2850 2851 /* ------------- seeds driving configuration bytes 4-9 ------------- 2852 The seeds above leave those bytes zero and only exercise the 2853 parser. Without at least one seed per area below, the rest of the 2854 API stays practically unreachable: libFuzzer would have to guess 2855 six configuration bytes before anything new runs. Each seed turns 2856 on exactly one area so that a minimiser keeps them distinguishable. 2857 ext[] is { response, auth, event-loop/introspection, suspend and 2858 upgrade, header seed, content-reader seed }. */ 2859 2860 /* Chunked reply produced by a content-reader callback, with response 2861 headers and a trailer -- the reply-side counterpart of the chunk 2862 parsing that commit c13f4c64 fixed on the request side. */ 2863 { "ext-callback-chunked", { 0x00, 0x08, 0x03, 0x00 }, 2864 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2865 { 0x0A | 0x20 | 0x40, 0x00, 0x00, 0x00, 0x01, 0x20 } }, 2866 2867 /* Known-length callback body, with a reader error injected part way 2868 through (crc_seed bit 0x80). */ 2869 { "ext-callback-error", { 0x00, 0x08, 0x03, 0x00 }, 2870 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2871 { 0x09, 0x00, 0x00, 0x00, 0x02, 0x82 } }, 2872 2873 { "ext-fd-response", { 0x00, 0x08, 0x03, 0x00 }, 2874 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2875 { 0x0B, 0x00, 0x00, 0x00, 0x00, 0x10 } }, 2876 2877 { "ext-fd-at-offset-response", { 0x00, 0x08, 0x03, 0x00 }, 2878 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2879 { 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10 } }, 2880 2881 { "ext-pipe-response", { 0x00, 0x08, 0x03, 0x00 }, 2882 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2883 { 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10 } }, 2884 2885 { "ext-iovec-response", { 0x00, 0x08, 0x03, 0x00 }, 2886 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2887 { 0x0F, 0x00, 0x00, 0x00, 0x00, 0x07 } }, 2888 2889 /* Empty response plus the header manipulation API (get/del/options). */ 2890 { "ext-empty-response-hdrapi", { 0x00, 0x08, 0x03, 0x00 }, 2891 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2892 { 0x02 | 0x30 | 0x40 | 0x80, 0x00, 0x00, 0x00, 0x05, 0x00 } }, 2893 2894 /* Digest through the pre-computed-userdigest entry point. */ 2895 { "ext-digest-check-digest3", { 0x00, 0x09, 0x03, 0x00 }, 2896 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2897 { 0, "GET / HTTP/1.1\r\nHost: x\r\nAuthorization: Digest " 2898 "username=\"user\", realm=\"TestRealm\", nonce=\"%%NONCE%%\", " 2899 "uri=\"/\", response=\"00000000000000000000000000000000\"\r\n\r\n" }, 2900 P_END, P_END }, 2901 { 0x00, 0x05 | 0x80, 0x00, 0x00, 0x01, 0x00 } }, 2902 2903 /* The v1 wrappers and the request-info query. */ 2904 { "ext-digest-v1-wrappers", { 0x00, 0x09, 0x03, 0x00 }, 2905 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2906 { 0x00, 0x01 | 0x10, 0x00, 0x00, 0x00, 0x00 } }, 2907 2908 { "ext-digest-request-info", { 0x00, 0x09, 0x03, 0x00 }, 2909 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2910 { 0x00, 0x08 | 0x20, 0x00, 0x00, 0x03, 0x00 } }, 2911 2912 /* Application-driven event loop: MHD_get_fdset2() + select() + 2913 MHD_run_from_select2(), with the timeout accessors. */ 2914 { "ext-external-event-loop", { 0x00, 0x08, 0x03, 0x00 }, 2915 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2916 { 0x01, 0x00, 0x02 | 0x04, 0x00, 0x00, 0x00 } }, 2917 2918 /* The v1 fdset/run_from_select pair. */ 2919 { "ext-external-event-loop-v1", { 0x00, 0x08, 0x03, 0x00 }, 2920 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2921 { 0x01, 0x00, 0x01 | 0x04, 0x00, 0x00, 0x00 } }, 2922 2923 /* Every connection-introspection accessor at once. */ 2924 { "ext-connection-api", { 0x00, 0x08, 0x03, 0x00 }, 2925 { { 0, "GET /path?a=1 HTTP/1.1\r\nHost: x\r\nCookie: a=b\r\n\r\n" }, 2926 P_END, P_END, P_END }, 2927 { 0x01, 0x00, 0x08 | 0x10 | 0x20 | 0x40 | 0x80, 0x00, 0x10, 0x00 } }, 2928 2929 /* Suspend the connection and resume it from the pump loop. */ 2930 { "ext-suspend-resume", { 0x00, 0x08, 0x03, 0x00 }, 2931 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2932 { 2, "" }, P_END, P_END }, 2933 { 0x01, 0x00, 0x00, 0x02, 0x00, 0x00 } }, 2934 2935 /* Two connections parked at the same time (op 3 opens the second 2936 without waiting for the first). The bookkeeping behind suspend 2937 mode 2 has to be a set for this: while it was a single slot the 2938 first connection was forgotten and stayed suspended, and 2939 MHD_stop_daemon() answered with 2940 MHD_PANIC ("called while we have suspended connections"). */ 2941 { "ext-suspend-two-connections", { 0x00, 0x08, 0x03, 0x00 }, 2942 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" }, 2943 { 3, "GET /b HTTP/1.1\r\nHost: x\r\n\r\n" }, 2944 { 2, "" }, P_END }, 2945 { 0x01, 0x00, 0x00, 0x02, 0x00, 0x00 } }, 2946 2947 /* HTTP "Upgrade": the client asks for it and the handler answers 101 2948 with an upgrade response, after which the socket is handed over. */ 2949 { "ext-upgrade", { 0x00, 0x08, 0x03, 0x00 }, 2950 { { 0, "GET / HTTP/1.1\r\nHost: x\r\nConnection: Upgrade\r\n" 2951 "Upgrade: fuzz-protocol\r\n\r\n" }, 2952 { 2, "" }, P_END, P_END }, 2953 { 0x01, 0x00, 0x00, 0x04 | 0x08, 0x00, 0x00 } }, 2954 2955 /* The remaining response constructors. One seed each, because the 2956 constructor is picked by the low nibble of ext[0] and a seed that 2957 does not name it leaves that entry point unreachable until the 2958 fuzzer happens to mutate the nibble. */ 2959 { "ext-buffer-persistent", { 0x00, 0x08, 0x03, 0x00 }, 2960 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2961 { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 } }, 2962 2963 { "ext-buffer-free-callback", { 0x00, 0x08, 0x03, 0x00 }, 2964 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2965 { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 } }, 2966 2967 { "ext-from-data", { 0x00, 0x08, 0x03, 0x00 }, 2968 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2969 { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 } }, 2970 2971 { "ext-fd64-response", { 0x00, 0x08, 0x03, 0x00 }, 2972 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2973 { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00 } }, 2974 2975 /* The v1 basic-auth getter, which returns two separate malloc()ed 2976 strings rather than one struct. */ 2977 { "ext-basic-auth-v1", { 0x00, 0x0a, 0x03, 0x00 }, 2978 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n" 2979 "Authorization: Basic dXNlcjpwYXNz\r\n\r\n" }, 2980 P_END, P_END, P_END }, 2981 { 0x01, 0x40, 0x00, 0x00, 0x00, 0x00 } }, 2982 2983 /* Answer the challenge with the basic-auth responses instead of the 2984 digest ones (fail_variant 3). */ 2985 { "ext-basic-auth-challenge", { 0x00, 0x09, 0x03, 0x00 }, 2986 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2987 { 0x01, 0x30, 0x00, 0x00, 0x00, 0x00 } }, 2988 2989 { "ext-basic-auth-challenge-utf8", { 0x00, 0x09, 0x03, 0x00 }, 2990 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2991 { 0x01, 0x30, 0x00, 0x00, 0x03, 0x00 } }, 2992 2993 /* The MD5-only and algorithm-parametrised pre-computed digest 2994 wrappers. */ 2995 { "ext-digest-check-digest-v1", { 0x00, 0x09, 0x03, 0x00 }, 2996 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 2997 { 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 } }, 2998 2999 { "ext-digest-check-digest2", { 0x00, 0x09, 0x03, 0x00 }, 3000 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END }, 3001 { 0x01, 0x04, 0x00, 0x00, 0x01, 0x00 } }, 3002 3003 /* The username queries. */ 3004 { "ext-digest-get-username-v1", { 0x00, 0x09, 0x03, 0x00 }, 3005 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n" 3006 "Authorization: Digest username=\"user\", realm=\"TestRealm\"\r\n\r\n" } 3007 , 3008 P_END, P_END, P_END }, 3009 { 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 } }, 3010 3011 { "ext-digest-get-username3", { 0x00, 0x09, 0x03, 0x00 }, 3012 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n" 3013 "Authorization: Digest userhash=true, username=\"aabb\", " 3014 "realm=\"TestRealm\"\r\n\r\n" }, 3015 P_END, P_END, P_END }, 3016 { 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 } } 3017 }; 3018 3019 static uint8_t seed_render_buf[4096]; 3020 3021 3022 static size_t 3023 fuzz_seed_count (void) 3024 { 3025 return sizeof (seeds) / sizeof (seeds[0]); 3026 } 3027 3028 3029 static const uint8_t * 3030 fuzz_seed_get (size_t idx, 3031 size_t *len) 3032 { 3033 const struct seed_def *sd = &seeds[idx]; 3034 struct sbuf b; 3035 unsigned int i; 3036 3037 b.p = seed_render_buf; 3038 b.len = 0; 3039 b.cap = sizeof (seed_render_buf); 3040 sb_raw (&b, sd->cfg, 4); 3041 sb_raw (&b, sd->ext, sizeof (sd->ext)); 3042 for (i = 0; i < sizeof (sd->parts) / sizeof (sd->parts[0]); i++) 3043 { 3044 size_t n; 3045 unsigned int hv; 3046 uint8_t hdr[2]; 3047 3048 if (NULL == sd->parts[i].txt) 3049 break; 3050 n = strlen (sd->parts[i].txt); 3051 if (n > 0x3FFF) 3052 n = 0x3FFF; 3053 hv = (sd->parts[i].op << 14) | (unsigned int) n; 3054 hdr[0] = (uint8_t) (hv & 0xFF); 3055 hdr[1] = (uint8_t) (hv >> 8); 3056 sb_raw (&b, hdr, 2); 3057 sb_raw (&b, sd->parts[i].txt, n); 3058 } 3059 *len = b.len; 3060 return seed_render_buf; 3061 }