Coverage Report

Created: 2025-08-24 06:26

/src/fuzz_str.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2025 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
//
15
////////////////////////////////////////////////////////////////////////////////
16
#include <cstring>
17
#include <stddef.h>
18
#include <stdint.h>
19
#include <string.h>
20
#include <stdlib.h>
21
#include <algorithm>
22
#include <vector>
23
24
#include <fuzzer/FuzzedDataProvider.h>
25
extern "C" {
26
  #include "mhd_str.h"
27
  #include "microhttpd2.h"
28
}
29
30
1.25k
static void fuzz_tokens(FuzzedDataProvider& fdp) {
31
  // Prepare random string for string comparison
32
1.25k
  std::string payload1 = fdp.ConsumeRandomLengthString(1024);
33
1.25k
  std::string payload2 = fdp.ConsumeRandomLengthString(1024);
34
1.25k
  std::string payload3 = fdp.ConsumeRandomLengthString(1024);
35
1.25k
  const char *payload_str1 = payload1.c_str();
36
1.25k
  const char *payload_str2 = payload2.c_str();
37
1.25k
  const char *payload_str3 = payload3.c_str();
38
1.25k
  size_t payload_size1 = payload1.size();
39
1.25k
  size_t payload_size2 = payload2.size();
40
1.25k
  size_t payload_size3 = payload3.size();
41
42
  // Fuzz mhd_str_equal_caseless
43
1.25k
  mhd_str_equal_caseless(payload_str1, payload_str2);
44
45
  // Fuzz mhd_str_equal_caseless_n
46
1.25k
  mhd_str_equal_caseless_n(payload_str1, payload_str2, fdp.ConsumeIntegral<size_t>());
47
48
  // Fuzz mhd_str_equal_caseless_bin_n
49
1.25k
  const size_t min_len = std::min(payload_size1, payload_size2);
50
1.25k
  if (min_len) {
51
341
    mhd_str_equal_caseless_bin_n(payload_str1, payload_str2, min_len);
52
341
  }
53
54
  // Fuzz mhd_str_has_token_caseless
55
1.25k
  mhd_str_has_token_caseless(payload_str1, payload_str2, payload_size1);
56
1.25k
  mhd_str_has_token_caseless(payload_str1, payload_str2, payload_size2);
57
58
  // Fuzz mhd_str_remove_token_caseless
59
1.25k
  ssize_t out_sz = (ssize_t)fdp.ConsumeIntegralInRange<int>(1, 1024);
60
1.25k
  char *out_buf = (char*) malloc((size_t)out_sz);
61
1.25k
  mhd_str_remove_token_caseless(payload_str1, payload_size1, payload_str2, payload_size2,
62
1.25k
                                out_buf, &out_sz);
63
1.25k
  free(out_buf);
64
65
  // Fuzz mhd_str_starts_with_token_opt_param
66
1.25k
  struct MHD_String mhd_str1 {
67
1.25k
    payload_size1, payload_str1
68
1.25k
  };
69
1.25k
  struct MHD_String mhd_str2 {
70
1.25k
    payload_size2, payload_str2
71
1.25k
  };
72
1.25k
  mhd_str_starts_with_token_opt_param(&mhd_str1, &mhd_str2);
73
74
  // Fuzz mhd_str_starts_with_token_req_param
75
1.25k
  bool needs_uni = fdp.ConsumeBool();
76
1.25k
  struct MHD_String mhd_str3 {
77
1.25k
    payload_size3, payload_str3
78
1.25k
  };
79
1.25k
  struct mhd_BufferConst str3_buf { 0, nullptr };
80
1.25k
  mhd_str_starts_with_token_req_param(&mhd_str1, &mhd_str2, &mhd_str3, &str3_buf, &needs_uni);
81
1.25k
}
82
83
1.17k
static void fuzz_conversion(FuzzedDataProvider& fdp) {
84
  // Prepare random string for string/int conversion
85
1.17k
  std::string payload = fdp.ConsumeRandomLengthString(1024);
86
1.17k
  const char *payload_str = payload.c_str();
87
1.17k
  size_t payload_size = payload.size();
88
89
1.17k
  uint_fast32_t u32 = 0;
90
1.17k
  uint_fast64_t u64 = 0;
91
1.17k
  char small[4], big[128];
92
1.17k
  size_t max_len = fdp.ConsumeIntegralInRange<size_t>(0, payload_size);
93
94
  // Fuzz conversion between string and uint64 with random payload
95
1.17k
  mhd_str_to_uint64(payload_str, &u64);
96
1.17k
  mhd_str_to_uint64_n(payload_str, max_len, &u64);
97
1.17k
  mhd_strx_to_uint64(payload_str, &u64);
98
1.17k
  mhd_strx_to_uint64_n(payload_str, max_len, &u64);
99
1.17k
  mhd_uint64_to_str((uint_fast64_t)fdp.ConsumeIntegral<uint64_t>(), small, sizeof(small));
100
1.17k
  mhd_uint64_to_str((uint_fast64_t)fdp.ConsumeIntegral<uint64_t>(), big, sizeof(big));
101
102
  // Fuzz string to uint32 conversion with random payload string
103
1.17k
  mhd_strx_to_uint32(payload_str, &u32);
104
1.17k
  mhd_strx_to_uint32_n(payload_str, max_len, &u32);
105
106
  // Fuzz uint16 to string conversion with random payload
107
1.17k
  mhd_uint16_to_str((uint_least16_t)fdp.ConsumeIntegralInRange<unsigned>(0, 65535), small, sizeof(small));
108
1.17k
  mhd_uint16_to_str((uint_least16_t)fdp.ConsumeIntegralInRange<unsigned>(0, 65535), big, sizeof(big));
109
1.17k
}
110
111
232
static void fuzz_decode(FuzzedDataProvider& fdp) {
112
  // Prepare random data for string decode
113
232
  bool ignored = false;
114
232
  std::string payload = fdp.ConsumeRandomLengthString(1024);
115
232
  char *payload_str = payload.data();
116
232
  size_t payload_size = payload.size();
117
118
  // Fuzz decode functions with random payload
119
232
  char *out1 = (char*) malloc(payload_size);
120
232
  char *out2 = (char*) malloc(payload_size);
121
232
  if (out1) {
122
232
    mhd_str_pct_decode_strict_n(payload_str, payload_size, out1, payload_size);
123
232
  }
124
232
  if (out2) {
125
232
    mhd_str_pct_decode_lenient_n(payload_str, payload_size, out2, payload_size, &ignored);
126
232
  }
127
128
  // Fuzz decode in place functions with random payload
129
232
  mhd_str_pct_decode_in_place_strict(payload_str);
130
232
  mhd_str_pct_decode_in_place_lenient(payload_str, &ignored);
131
132
232
  free(out1);
133
232
  free(out2);
134
232
}
135
136
183
static void fuzz_quoted(FuzzedDataProvider& fdp) {
137
  // Prepare random data for quote and equality check
138
183
  std::string payload1 = fdp.ConsumeRandomLengthString(1024);
139
183
  std::string payload2 = fdp.ConsumeRandomLengthString(1024);
140
183
  const char *payload_str1 = payload1.c_str();
141
183
  const char *payload_str2 = payload2.c_str();
142
183
  size_t payload_size1 = payload1.size();
143
183
  size_t payload_size2 = payload2.size();
144
145
  // Fuzz mhd_str_equal_quoted_bin_n with random string payload as binary
146
183
  mhd_str_equal_quoted_bin_n(payload_str1, payload_size1, payload_str2, payload_size2);
147
148
  // Fuzz mhd_str_quote and mhd_str_unquote with random string payload
149
183
  size_t max_out = payload_size1 * 2;
150
183
  char *out = (char*) malloc(max_out);
151
183
  if (out) {
152
183
    mhd_str_quote(payload_str1, payload_size1, out, max_out);
153
183
    mhd_str_unquote(payload_str1, payload_size1, out);
154
183
  }
155
183
  free(out);
156
157
183
  max_out = payload_size2 * 2;
158
183
  out = (char*) malloc(max_out);
159
183
  if (out) {
160
183
    mhd_str_quote(payload_str2, payload_size2, out, max_out);
161
183
    mhd_str_unquote(payload_str2, payload_size2, out);
162
183
  }
163
183
  free(out);
164
183
}
165
166
143
static void fuzz_base64(FuzzedDataProvider& fdp) {
167
  // Prepare random data for base64 conversion
168
143
  std::string payload = fdp.ConsumeRandomLengthString(1024);
169
143
  char *payload_str = payload.data();
170
143
  size_t payload_size = payload.size();
171
172
  // Prepare a valid base64 string from random payload
173
143
  static const char valid_chars[] =
174
143
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
175
19.2k
  for (size_t i = 0; i < payload_size; i++) {
176
19.0k
    payload_str[i] = valid_chars[((uint8_t)i) % 64];
177
19.0k
  }
178
179
  // Fuzz mhd_base64_to_bin_n with the random base64 string
180
143
  size_t max_out = (payload.size() / 4) * 4;
181
143
  uint8_t* out = (uint8_t*) malloc(payload_size);
182
143
  if (out) {
183
143
    mhd_base64_to_bin_n(payload_str, payload_size, out, max_out);
184
143
    free(out);
185
143
  }
186
143
}
187
188
146
static void fuzz_transformation(FuzzedDataProvider& fdp) {
189
  // Fuzz targets in multiple rounds
190
682
  for (int i = 0; i < fdp.ConsumeIntegralInRange<unsigned>(1, 8); i++) {
191
    // Generate random integer
192
536
    int value = fdp.ConsumeIntegral<int>();
193
194
    // Fuzz conversion functions
195
536
    MHD_http_method_to_string(static_cast<MHD_HTTP_Method>(value));
196
536
    MHD_predef_header_to_string(static_cast<MHD_PredefinedHeader>(value));
197
536
    MHD_protocol_version_to_string(static_cast<MHD_HTTP_ProtocolVersion>(value));
198
536
  }
199
146
}
200
201
123
static void fuzz_hex_conversion(FuzzedDataProvider& fdp) {
202
  // Prepare random data for hex conversion
203
123
  std::string payload = fdp.ConsumeRandomLengthString(1024);
204
123
  char *payload_str = payload.data();
205
123
  size_t payload_size = payload.size();
206
207
  // Fuzz mhd_hex_to_bin with random payload
208
123
  uint8_t *bin_out = (uint8_t*) malloc(payload_size);
209
123
  if (bin_out) {
210
123
    mhd_hex_to_bin(payload_str, payload_size, bin_out);
211
123
    free(bin_out);
212
123
  }
213
214
  // Fuzz mhd_bin_to_hex with random payload
215
123
  char *hex_out = (char *) malloc(payload_size * 2);
216
123
  if (hex_out) {
217
123
    if (!payload.empty()) {
218
109
      mhd_bin_to_hex(payload_str, payload_size, hex_out);
219
109
    }
220
123
    free(hex_out);
221
123
  }
222
223
123
  char *hexz_out = (char *) malloc(payload_size * 2 + 1);
224
123
  if (hexz_out) {
225
123
    if (!payload.empty()) {
226
109
      mhd_bin_to_hex(payload_str, payload_size, hexz_out);
227
109
    }
228
123
    free(hexz_out);
229
123
  }
230
123
}
231
232
2.32k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
233
2.32k
  FuzzedDataProvider fdp(data, size);
234
235
5.64k
  for (int i = 0; i < fdp.ConsumeIntegralInRange<unsigned>(1, 6); i++) {
236
3.32k
    switch (fdp.ConsumeIntegralInRange<int>(0, 7)) {
237
1.25k
      case 0: fuzz_tokens(fdp); break;
238
1.17k
      case 1: fuzz_conversion(fdp); break;
239
232
      case 2: fuzz_decode(fdp); break;
240
183
      case 3: fuzz_quoted(fdp); break;
241
143
      case 4: fuzz_base64(fdp); break;
242
146
      case 5: fuzz_transformation(fdp); break;
243
123
      case 6: fuzz_hex_conversion(fdp); break;
244
3.32k
    }
245
3.32k
  }
246
2.32k
  return 0;
247
2.32k
}