Coverage Report

Created: 2025-08-26 06:29

/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.26k
static void fuzz_tokens(FuzzedDataProvider& fdp) {
31
  // Prepare random string for string comparison
32
1.26k
  std::string payload1 = fdp.ConsumeRandomLengthString(1024);
33
1.26k
  std::string payload2 = fdp.ConsumeRandomLengthString(1024);
34
1.26k
  std::string payload3 = fdp.ConsumeRandomLengthString(1024);
35
1.26k
  const char *payload_str1 = payload1.c_str();
36
1.26k
  const char *payload_str2 = payload2.c_str();
37
1.26k
  const char *payload_str3 = payload3.c_str();
38
1.26k
  size_t payload_size1 = payload1.size();
39
1.26k
  size_t payload_size2 = payload2.size();
40
1.26k
  size_t payload_size3 = payload3.size();
41
42
  // Fuzz mhd_str_equal_caseless
43
1.26k
  mhd_str_equal_caseless(payload_str1, payload_str2);
44
45
  // Fuzz mhd_str_equal_caseless_n
46
1.26k
  mhd_str_equal_caseless_n(payload_str1, payload_str2, fdp.ConsumeIntegral<size_t>());
47
48
  // Fuzz mhd_str_equal_caseless_bin_n
49
1.26k
  const size_t min_len = std::min(payload_size1, payload_size2);
50
1.26k
  if (min_len) {
51
323
    mhd_str_equal_caseless_bin_n(payload_str1, payload_str2, min_len);
52
323
  }
53
54
  // Fuzz mhd_str_has_token_caseless
55
1.26k
  mhd_str_has_token_caseless(payload_str1, payload_str2, payload_size1);
56
1.26k
  mhd_str_has_token_caseless(payload_str1, payload_str2, payload_size2);
57
58
  // Fuzz mhd_str_remove_token_caseless
59
1.26k
  ssize_t out_sz = (ssize_t)fdp.ConsumeIntegralInRange<int>(1, 1024);
60
1.26k
  char *out_buf = (char*) malloc((size_t)out_sz);
61
1.26k
  mhd_str_remove_token_caseless(payload_str1, payload_size1, payload_str2, payload_size2,
62
1.26k
                                out_buf, &out_sz);
63
1.26k
  free(out_buf);
64
65
  // Fuzz mhd_str_starts_with_token_opt_param
66
1.26k
  struct MHD_String mhd_str1 {
67
1.26k
    payload_size1, payload_str1
68
1.26k
  };
69
1.26k
  struct MHD_String mhd_str2 {
70
1.26k
    payload_size2, payload_str2
71
1.26k
  };
72
1.26k
  mhd_str_starts_with_token_opt_param(&mhd_str1, &mhd_str2);
73
74
  // Fuzz mhd_str_starts_with_token_req_param
75
1.26k
  bool needs_uni = fdp.ConsumeBool();
76
1.26k
  struct MHD_String mhd_str3 {
77
1.26k
    payload_size3, payload_str3
78
1.26k
  };
79
1.26k
  struct mhd_BufferConst str3_buf { 0, nullptr };
80
1.26k
  mhd_str_starts_with_token_req_param(&mhd_str1, &mhd_str2, &mhd_str3, &str3_buf, &needs_uni);
81
1.26k
}
82
83
1.19k
static void fuzz_conversion(FuzzedDataProvider& fdp) {
84
  // Prepare random string for string/int conversion
85
1.19k
  std::string payload = fdp.ConsumeRandomLengthString(1024);
86
1.19k
  const char *payload_str = payload.c_str();
87
1.19k
  size_t payload_size = payload.size();
88
89
1.19k
  uint_fast32_t u32 = 0;
90
1.19k
  uint_fast64_t u64 = 0;
91
1.19k
  char small[4], big[128];
92
1.19k
  size_t max_len = fdp.ConsumeIntegralInRange<size_t>(0, payload_size);
93
94
  // Fuzz conversion between string and uint64 with random payload
95
1.19k
  mhd_str_to_uint64(payload_str, &u64);
96
1.19k
  mhd_str_to_uint64_n(payload_str, max_len, &u64);
97
1.19k
  mhd_strx_to_uint64(payload_str, &u64);
98
1.19k
  mhd_strx_to_uint64_n(payload_str, max_len, &u64);
99
1.19k
  mhd_uint64_to_str((uint_fast64_t)fdp.ConsumeIntegral<uint64_t>(), small, sizeof(small));
100
1.19k
  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.19k
  mhd_strx_to_uint32(payload_str, &u32);
104
1.19k
  mhd_strx_to_uint32_n(payload_str, max_len, &u32);
105
106
  // Fuzz uint16 to string conversion with random payload
107
1.19k
  mhd_uint16_to_str((uint_least16_t)fdp.ConsumeIntegralInRange<unsigned>(0, 65535), small, sizeof(small));
108
1.19k
  mhd_uint16_to_str((uint_least16_t)fdp.ConsumeIntegralInRange<unsigned>(0, 65535), big, sizeof(big));
109
1.19k
}
110
111
215
static void fuzz_decode(FuzzedDataProvider& fdp) {
112
  // Prepare random data for string decode
113
215
  bool ignored = false;
114
215
  std::string payload = fdp.ConsumeRandomLengthString(1024);
115
215
  char *payload_str = payload.data();
116
215
  size_t payload_size = payload.size();
117
118
  // Fuzz decode functions with random payload
119
215
  char *out1 = (char*) malloc(payload_size);
120
215
  char *out2 = (char*) malloc(payload_size);
121
215
  if (out1) {
122
215
    mhd_str_pct_decode_strict_n(payload_str, payload_size, out1, payload_size);
123
215
  }
124
215
  if (out2) {
125
215
    mhd_str_pct_decode_lenient_n(payload_str, payload_size, out2, payload_size, &ignored);
126
215
  }
127
128
  // Fuzz decode in place functions with random payload
129
215
  mhd_str_pct_decode_in_place_strict(payload_str);
130
215
  mhd_str_pct_decode_in_place_lenient(payload_str, &ignored);
131
132
215
  free(out1);
133
215
  free(out2);
134
215
}
135
136
200
static void fuzz_quoted(FuzzedDataProvider& fdp) {
137
  // Prepare random data for quote and equality check
138
200
  std::string payload1 = fdp.ConsumeRandomLengthString(1024);
139
200
  std::string payload2 = fdp.ConsumeRandomLengthString(1024);
140
200
  const char *payload_str1 = payload1.c_str();
141
200
  const char *payload_str2 = payload2.c_str();
142
200
  size_t payload_size1 = payload1.size();
143
200
  size_t payload_size2 = payload2.size();
144
145
  // Fuzz mhd_str_equal_quoted_bin_n with random string payload as binary
146
200
  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
200
  size_t max_out = payload_size1 * 2;
150
200
  char *out = (char*) malloc(max_out);
151
200
  if (out) {
152
200
    mhd_str_quote(payload_str1, payload_size1, out, max_out);
153
200
    mhd_str_unquote(payload_str1, payload_size1, out);
154
200
  }
155
200
  free(out);
156
157
200
  max_out = payload_size2 * 2;
158
200
  out = (char*) malloc(max_out);
159
200
  if (out) {
160
200
    mhd_str_quote(payload_str2, payload_size2, out, max_out);
161
200
    mhd_str_unquote(payload_str2, payload_size2, out);
162
200
  }
163
200
  free(out);
164
200
}
165
166
138
static void fuzz_base64(FuzzedDataProvider& fdp) {
167
  // Prepare random data for base64 conversion
168
138
  std::string payload = fdp.ConsumeRandomLengthString(1024);
169
138
  char *payload_str = payload.data();
170
138
  size_t payload_size = payload.size();
171
172
  // Prepare a valid base64 string from random payload
173
138
  static const char valid_chars[] =
174
138
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
175
21.6k
  for (size_t i = 0; i < payload_size; i++) {
176
21.5k
    payload_str[i] = valid_chars[((uint8_t)i) % 64];
177
21.5k
  }
178
179
  // Fuzz mhd_base64_to_bin_n with the random base64 string
180
138
  size_t max_out = (payload.size() / 4) * 4;
181
138
  uint8_t* out = (uint8_t*) malloc(payload_size);
182
138
  if (out) {
183
138
    mhd_base64_to_bin_n(payload_str, payload_size, out, max_out);
184
138
    free(out);
185
138
  }
186
138
}
187
188
153
static void fuzz_transformation(FuzzedDataProvider& fdp) {
189
  // Fuzz targets in multiple rounds
190
709
  for (int i = 0; i < fdp.ConsumeIntegralInRange<unsigned>(1, 8); i++) {
191
    // Generate random integer
192
556
    int value = fdp.ConsumeIntegral<int>();
193
194
    // Fuzz conversion functions
195
556
    MHD_http_method_to_string(static_cast<MHD_HTTP_Method>(value));
196
556
    MHD_predef_header_to_string(static_cast<MHD_PredefinedHeader>(value));
197
556
    MHD_protocol_version_to_string(static_cast<MHD_HTTP_ProtocolVersion>(value));
198
556
  }
199
153
}
200
201
124
static void fuzz_hex_conversion(FuzzedDataProvider& fdp) {
202
  // Prepare random data for hex conversion
203
124
  std::string payload = fdp.ConsumeRandomLengthString(1024);
204
124
  char *payload_str = payload.data();
205
124
  size_t payload_size = payload.size();
206
207
  // Fuzz mhd_hex_to_bin with random payload
208
124
  uint8_t *bin_out = (uint8_t*) malloc(payload_size);
209
124
  if (bin_out) {
210
124
    mhd_hex_to_bin(payload_str, payload_size, bin_out);
211
124
    free(bin_out);
212
124
  }
213
214
  // Fuzz mhd_bin_to_hex with random payload
215
124
  char *hex_out = (char *) malloc(payload_size * 2);
216
124
  if (hex_out) {
217
124
    if (!payload.empty()) {
218
111
      mhd_bin_to_hex(payload_str, payload_size, hex_out);
219
111
    }
220
124
    free(hex_out);
221
124
  }
222
223
124
  char *hexz_out = (char *) malloc(payload_size * 2 + 1);
224
124
  if (hexz_out) {
225
124
    if (!payload.empty()) {
226
111
      mhd_bin_to_hex(payload_str, payload_size, hexz_out);
227
111
    }
228
124
    free(hexz_out);
229
124
  }
230
124
}
231
232
2.35k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
233
2.35k
  FuzzedDataProvider fdp(data, size);
234
235
5.72k
  for (int i = 0; i < fdp.ConsumeIntegralInRange<unsigned>(1, 6); i++) {
236
3.36k
    switch (fdp.ConsumeIntegralInRange<int>(0, 7)) {
237
1.26k
      case 0: fuzz_tokens(fdp); break;
238
1.19k
      case 1: fuzz_conversion(fdp); break;
239
215
      case 2: fuzz_decode(fdp); break;
240
200
      case 3: fuzz_quoted(fdp); break;
241
138
      case 4: fuzz_base64(fdp); break;
242
153
      case 5: fuzz_transformation(fdp); break;
243
124
      case 6: fuzz_hex_conversion(fdp); break;
244
3.36k
    }
245
3.36k
  }
246
2.35k
  return 0;
247
2.35k
}