Coverage Report

Created: 2026-03-31 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/fuzz_h1_parse.c
Line
Count
Source
1
/*
2
 * Copyright 2026 Google LLC
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
/*
18
 * Fuzzer for HAProxy's HTTP/1 message parser (h1_headers_to_hdr_list).
19
 *
20
 * This targets the core HTTP/1.1 request and response parsing state machine
21
 * in src/h1.c, which is HAProxy's primary attack surface: every HTTP/1
22
 * request from an untrusted client passes through this parser.
23
 *
24
 * The parser handles:
25
 *   - Request line parsing (method, URI, version)
26
 *   - Response status line parsing
27
 *   - Header field parsing with folding/continuation
28
 *   - Transfer-Encoding validation (chunked smuggling detection)
29
 *   - Content-Length parsing and duplicate detection
30
 *   - Connection and Upgrade header processing
31
 *   - HTTP/1.0 vs 1.1 semantics
32
 *
33
 * We use the first byte of fuzz input to select between request and
34
 * response parsing modes, maximizing code coverage.
35
 */
36
37
#include <haproxy/h1.h>
38
#include <haproxy/http-hdr.h>
39
#include <haproxy/global.h>
40
41
#include <stdint.h>
42
#include <string.h>
43
#include <stdlib.h>
44
45
0
#define MAX_HDR_NUM 101
46
47
0
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
48
0
  struct h1m h1m;
49
0
  union h1_sl h1sl;
50
0
  struct http_hdr hdrs[MAX_HDR_NUM];
51
0
  char *buf;
52
53
0
  if (size < 2)
54
0
    return 0;
55
56
  /* Use first byte to select request vs response parsing */
57
0
  int parse_response = data[0] & 1;
58
0
  data++;
59
0
  size--;
60
61
  /* h1_headers_to_hdr_list modifies the buffer in-place (it writes
62
   * the sentinel \0 bytes), so we need a mutable copy. */
63
0
  buf = (char *)malloc(size + 1);
64
0
  if (!buf)
65
0
    return 0;
66
0
  memcpy(buf, data, size);
67
0
  buf[size] = '\0';
68
69
  /* Ensure global.tune.max_http_hdr is set */
70
0
  if (global.tune.max_http_hdr == 0)
71
0
    global.tune.max_http_hdr = MAX_HDR_NUM;
72
73
0
  if (parse_response) {
74
0
    h1m_init_res(&h1m);
75
0
  } else {
76
0
    h1m_init_req(&h1m);
77
0
  }
78
79
0
  h1_headers_to_hdr_list(buf, buf + size,
80
0
                         hdrs, MAX_HDR_NUM,
81
0
                         &h1m, &h1sl);
82
83
0
  free(buf);
84
0
  return 0;
85
0
}