Coverage Report

Created: 2026-10-28 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl_fuzzer/curl_fuzzer_tlv.cc
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 ***************************************************************************/
22
#include <stdlib.h>
23
#include <string.h>
24
#include <curl/curl.h>
25
#include "curl_fuzzer.h"
26
27
/**
28
 * TLV access function - gets the first TLV from a data stream.
29
 */
30
int fuzz_get_first_tlv(FUZZ_DATA *fuzz,
31
                       TLV *tlv)
32
398k
{
33
  /* Reset the cursor. */
34
398k
  fuzz->state.data_pos = 0;
35
398k
  return fuzz_get_tlv_comn(fuzz, tlv);
36
398k
}
37
38
/**
39
 * TLV access function - gets the next TLV from a data stream.
40
*/
41
int fuzz_get_next_tlv(FUZZ_DATA *fuzz,
42
                      TLV *tlv)
43
4.17M
{
44
  /* Advance the cursor by the full length of the previous TLV. */
45
4.17M
  fuzz->state.data_pos += sizeof(TLV_RAW) + tlv->length;
46
47
  /* Work out if there's a TLV's worth of data to read */
48
4.17M
  if(fuzz->state.data_pos + sizeof(TLV_RAW) > fuzz->state.data_len) {
49
    /* No more TLVs to parse */
50
335k
    return TLV_RC_NO_MORE_TLVS;
51
335k
  }
52
53
3.83M
  return fuzz_get_tlv_comn(fuzz, tlv);
54
4.17M
}
55
56
/**
57
 * Common TLV function for accessing TLVs in a data stream.
58
 */
59
int fuzz_get_tlv_comn(FUZZ_DATA *fuzz,
60
                      TLV *tlv)
61
4.23M
{
62
4.23M
  int rc = 0;
63
4.23M
  size_t data_offset;
64
4.23M
  TLV_RAW *raw;
65
66
  /* Start by casting the data stream to a TLV. */
67
4.23M
  raw = (TLV_RAW *)&fuzz->state.data[fuzz->state.data_pos];
68
4.23M
  data_offset = fuzz->state.data_pos + sizeof(TLV_RAW);
69
70
  /* Set the TLV values. */
71
4.23M
  tlv->type = to_u16(raw->raw_type);
72
4.23M
  tlv->length = to_u32(raw->raw_length);
73
4.23M
  tlv->value = &fuzz->state.data[data_offset];
74
75
4.23M
  FV_PRINTF(fuzz, "TLV: type %x length %u\n", tlv->type, tlv->length);
76
77
  /* Use uint64s to verify lengths of TLVs so that overflow problems don't
78
     matter. */
79
4.23M
  uint64_t check_length = data_offset;
80
4.23M
  check_length += tlv->length;
81
82
4.23M
  uint64_t remaining_len = fuzz->state.data_len;
83
4.23M
  FV_PRINTF(fuzz, "Check length of data: %" PRIu64 " \n", check_length);
84
4.23M
  FV_PRINTF(fuzz, "Remaining length of data: %" PRIu64 " \n", remaining_len);
85
86
  /* Sanity check that the TLV length is ok. */
87
4.23M
  if(check_length > remaining_len) {
88
42.6k
    FV_PRINTF(fuzz, "Returning TLV_RC_SIZE_ERROR\n");
89
42.6k
    rc = TLV_RC_SIZE_ERROR;
90
42.6k
  }
91
92
4.23M
  return rc;
93
4.23M
}
94
95
/**
96
 * Do different actions on the CURL handle for different received TLVs.
97
 */
98
int fuzz_parse_tlv(FUZZ_DATA *fuzz, TLV *tlv)
99
4.02M
{
100
4.02M
  int rc;
101
4.02M
  char *tmp = NULL;
102
4.02M
  long tmp_long;
103
4.02M
  curl_off_t tmp_off_t;
104
4.02M
  curl_slist *new_list;
105
106
4.02M
  switch(tlv->type) {
107
    /* The pointers in response TLVs will always be valid as long as the fuzz
108
       data is in scope, which is the entirety of this file. */
109
123k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE0, 0);
110
37.1k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE1, 1);
111
33.7k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE2, 2);
112
44.7k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE3, 3);
113
8.10k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE4, 4);
114
8.10k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE5, 5);
115
5.54k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE6, 6);
116
4.73k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE7, 7);
117
3.46k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE8, 8);
118
6.40k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE9, 9);
119
3.01k
    FRESPONSETLV(&fuzz->sockman[0], TLV_TYPE_RESPONSE10, 10);
120
121
7.84k
    FRESPONSETLV(&fuzz->sockman[1], TLV_TYPE_SECOND_RESPONSE0, 0);
122
7.91k
    FRESPONSETLV(&fuzz->sockman[1], TLV_TYPE_SECOND_RESPONSE1, 1);
123
124
3.79k
    case TLV_TYPE_UPLOAD1:
125
      /* The pointers in the TLV will always be valid as long as the fuzz data
126
         is in scope, which is the entirety of this file. */
127
128
3.79k
      FCHECK_OPTION_UNSET(fuzz, CURLOPT_UPLOAD);
129
130
3.78k
      fuzz->upload1_data = tlv->value;
131
3.78k
      fuzz->upload1_data_len = tlv->length;
132
133
3.78k
      FSET_OPTION(fuzz, CURLOPT_UPLOAD, 1L);
134
3.78k
      FSET_OPTION(fuzz,
135
3.78k
                  CURLOPT_INFILESIZE_LARGE,
136
3.78k
                  (curl_off_t)fuzz->upload1_data_len);
137
3.78k
      break;
138
139
381k
    case TLV_TYPE_HEADER:
140
      /* Limit the number of headers that can be added to a message to prevent
141
         timeouts. */
142
381k
      if(fuzz->header_list_count >= TLV_MAX_NUM_CURLOPT_HEADER) {
143
12
        rc = 255;
144
12
        goto EXIT_LABEL;
145
12
      }
146
147
381k
      tmp = fuzz_tlv_to_string(tlv);
148
381k
      if (tmp == NULL) {
149
        // keep on despite allocation failure
150
0
        break;
151
0
      }
152
381k
      new_list = curl_slist_append(fuzz->header_list, tmp);
153
381k
      if (new_list == NULL) {
154
0
        break;
155
0
      }
156
381k
      fuzz->header_list = new_list;
157
381k
      fuzz->header_list_count++;
158
381k
      break;
159
160
14.7k
    case TLV_TYPE_MAIL_RECIPIENT:
161
      /* Limit the number of headers that can be added to a message to prevent
162
         timeouts. */
163
14.7k
      if(fuzz->header_list_count >= TLV_MAX_NUM_CURLOPT_HEADER) {
164
12
        rc = 255;
165
12
        goto EXIT_LABEL;
166
12
      }
167
14.7k
      tmp = fuzz_tlv_to_string(tlv);
168
14.7k
      if (tmp == NULL) {
169
        // keep on despite allocation failure
170
0
        break;
171
0
      }
172
14.7k
      new_list = curl_slist_append(fuzz->mail_recipients_list, tmp);
173
14.7k
      if (new_list != NULL) {
174
14.7k
        fuzz->mail_recipients_list = new_list;
175
14.7k
        fuzz->header_list_count++;
176
14.7k
      }
177
14.7k
      break;
178
179
2.80M
    case TLV_TYPE_MIME_PART:
180
2.80M
      if(fuzz->mime == NULL) {
181
11.3k
        fuzz->mime = curl_mime_init(fuzz->easy);
182
11.3k
      }
183
184
2.80M
      fuzz->part = curl_mime_addpart(fuzz->mime);
185
186
      /* This TLV may have sub TLVs. */
187
2.80M
      fuzz_add_mime_part(tlv, fuzz->part);
188
189
2.80M
      break;
190
191
1.88k
    case TLV_TYPE_POSTFIELDS:
192
1.88k
      FCHECK_OPTION_UNSET(fuzz, CURLOPT_POSTFIELDS);
193
1.86k
      fuzz->postfields = fuzz_tlv_to_string(tlv);
194
1.86k
      FSET_OPTION(fuzz, CURLOPT_POSTFIELDS, fuzz->postfields);
195
1.86k
      break;
196
197
2.78k
    case TLV_TYPE_HTTPPOSTBODY:
198
2.78k
      FCHECK_OPTION_UNSET(fuzz, CURLOPT_HTTPPOST);
199
2.77k
      fuzz_setup_http_post(fuzz, tlv);
200
2.77k
      FSET_OPTION(fuzz, CURLOPT_HTTPPOST, fuzz->httppost);
201
2.77k
      break;
202
203
    /* Define a set of u32 options. */
204
20.5k
    FU32TLV(fuzz, TLV_TYPE_HTTPAUTH, CURLOPT_HTTPAUTH);
205
3.65k
    FU32TLV(fuzz, TLV_TYPE_OPTHEADER, CURLOPT_HEADER);
206
5.10k
    FU32TLV(fuzz, TLV_TYPE_NOBODY, CURLOPT_NOBODY);
207
38.0k
    FU32TLV(fuzz, TLV_TYPE_FOLLOWLOCATION, CURLOPT_FOLLOWLOCATION);
208
5.32k
    FU32TLV(fuzz, TLV_TYPE_WILDCARDMATCH, CURLOPT_WILDCARDMATCH);
209
4.52k
    FU32TLV(fuzz, TLV_TYPE_RTSP_REQUEST, CURLOPT_RTSP_REQUEST);
210
2.50k
    FU32TLV(fuzz, TLV_TYPE_RTSP_CLIENT_CSEQ, CURLOPT_RTSP_CLIENT_CSEQ);
211
52.0k
    FU32TLV(fuzz, TLV_TYPE_HTTP_VERSION, CURLOPT_HTTP_VERSION);
212
2.98k
    FU32TLV(fuzz, TLV_TYPE_NETRC, CURLOPT_NETRC);
213
2.16k
    FU32TLV(fuzz, TLV_TYPE_WS_OPTIONS, CURLOPT_WS_OPTIONS);
214
4.33k
    FU32TLV(fuzz, TLV_TYPE_CONNECT_ONLY, CURLOPT_CONNECT_ONLY);
215
5.43k
    FU32TLV(fuzz, TLV_TYPE_POST, CURLOPT_POST);
216
2.49k
    FU32TLV(fuzz, TLV_TYPE_PROXYTYPE, CURLOPT_PROXYTYPE);
217
5.18k
    FU32TLV(fuzz, TLV_TYPE_PORT, CURLOPT_PORT);
218
3.11k
    FU32TLV(fuzz, TLV_TYPE_LOW_SPEED_LIMIT, CURLOPT_LOW_SPEED_LIMIT);
219
4.12k
    FU32TLV(fuzz, TLV_TYPE_LOW_SPEED_TIME, CURLOPT_LOW_SPEED_TIME);
220
4.26k
    FU32TLV(fuzz, TLV_TYPE_RESUME_FROM, CURLOPT_RESUME_FROM);
221
935
    FU32TLV(fuzz, TLV_TYPE_TIMEVALUE, CURLOPT_TIMEVALUE);
222
6.75k
    FU32TLV(fuzz, TLV_TYPE_NOPROGRESS, CURLOPT_NOPROGRESS);
223
1.76k
    FU32TLV(fuzz, TLV_TYPE_FAILONERROR, CURLOPT_FAILONERROR);
224
703
    FU32TLV(fuzz, TLV_TYPE_DIRLISTONLY, CURLOPT_DIRLISTONLY);
225
736
    FU32TLV(fuzz, TLV_TYPE_APPEND, CURLOPT_APPEND);
226
4.40k
    FU32TLV(fuzz, TLV_TYPE_TRANSFERTEXT, CURLOPT_TRANSFERTEXT);
227
3.84k
    FU32TLV(fuzz, TLV_TYPE_AUTOREFERER, CURLOPT_AUTOREFERER);
228
2.44k
    FU32TLV(fuzz, TLV_TYPE_PROXYPORT, CURLOPT_PROXYPORT);
229
    // too easy for API misuse FU32TLV(fuzz, TLV_TYPE_POSTFIELDSIZE, CURLOPT_POSTFIELDSIZE);
230
659
    FU32TLV(fuzz, TLV_TYPE_HTTPPROXYTUNNEL, CURLOPT_HTTPPROXYTUNNEL);
231
12.0k
    FU32TLV(fuzz, TLV_TYPE_SSL_VERIFYPEER, CURLOPT_SSL_VERIFYPEER);
232
4.31k
    FU32TLV(fuzz, TLV_TYPE_MAXREDIRS, CURLOPT_MAXREDIRS);
233
1.05k
    FU32TLV(fuzz, TLV_TYPE_FILETIME, CURLOPT_FILETIME);
234
2.16k
    FU32TLV(fuzz, TLV_TYPE_MAXCONNECTS, CURLOPT_MAXCONNECTS);
235
1.38k
    FU32TLV(fuzz, TLV_TYPE_FRESH_CONNECT, CURLOPT_FRESH_CONNECT);
236
930
    FU32TLV(fuzz, TLV_TYPE_FORBID_REUSE, CURLOPT_FORBID_REUSE);
237
4.05k
    FU32TLV(fuzz, TLV_TYPE_CONNECTTIMEOUT, CURLOPT_CONNECTTIMEOUT);
238
712
    FU32TLV(fuzz, TLV_TYPE_HTTPGET, CURLOPT_HTTPGET);
239
2.44k
    FU32TLV(fuzz, TLV_TYPE_SSL_VERIFYHOST, CURLOPT_SSL_VERIFYHOST);
240
565
    FU32TLV(fuzz, TLV_TYPE_FTP_USE_EPSV, CURLOPT_FTP_USE_EPSV);
241
1.65k
    FU32TLV(fuzz, TLV_TYPE_SSLENGINE_DEFAULT, CURLOPT_SSLENGINE_DEFAULT);
242
4.91k
    FU32TLV(fuzz, TLV_TYPE_DNS_CACHE_TIMEOUT, CURLOPT_DNS_CACHE_TIMEOUT);
243
635
    FU32TLV(fuzz, TLV_TYPE_COOKIESESSION, CURLOPT_COOKIESESSION);
244
8.54k
    FU32TLV(fuzz, TLV_TYPE_BUFFERSIZE, CURLOPT_BUFFERSIZE);
245
1.04k
    FU32TLV(fuzz, TLV_TYPE_NOSIGNAL, CURLOPT_NOSIGNAL);
246
1.24k
    FU32TLV(fuzz, TLV_TYPE_UNRESTRICTED_AUTH, CURLOPT_UNRESTRICTED_AUTH);
247
706
    FU32TLV(fuzz, TLV_TYPE_FTP_USE_EPRT, CURLOPT_FTP_USE_EPRT);
248
1.51k
    FU32TLV(fuzz, TLV_TYPE_FTP_CREATE_MISSING_DIRS, CURLOPT_FTP_CREATE_MISSING_DIRS);
249
3.52k
    FU32TLV(fuzz, TLV_TYPE_MAXFILESIZE, CURLOPT_MAXFILESIZE);
250
661
    FU32TLV(fuzz, TLV_TYPE_TCP_NODELAY, CURLOPT_TCP_NODELAY);
251
860
    FU32TLV(fuzz, TLV_TYPE_IGNORE_CONTENT_LENGTH, CURLOPT_IGNORE_CONTENT_LENGTH);
252
611
    FU32TLV(fuzz, TLV_TYPE_FTP_SKIP_PASV_IP, CURLOPT_FTP_SKIP_PASV_IP);
253
2.82k
    FU32TLV(fuzz, TLV_TYPE_LOCALPORT, CURLOPT_LOCALPORT);
254
2.73k
    FU32TLV(fuzz, TLV_TYPE_LOCALPORTRANGE, CURLOPT_LOCALPORTRANGE);
255
633
    FU32TLV(fuzz, TLV_TYPE_SSL_SESSIONID_CACHE, CURLOPT_SSL_SESSIONID_CACHE);
256
1.44k
    FU32TLV(fuzz, TLV_TYPE_FTP_SSL_CCC, CURLOPT_FTP_SSL_CCC);
257
9.84k
    FU32TLV(fuzz, TLV_TYPE_CONNECTTIMEOUT_MS, CURLOPT_CONNECTTIMEOUT_MS);
258
1.42k
    FU32TLV(fuzz, TLV_TYPE_HTTP_TRANSFER_DECODING, CURLOPT_HTTP_TRANSFER_DECODING);
259
990
    FU32TLV(fuzz, TLV_TYPE_HTTP_CONTENT_DECODING, CURLOPT_HTTP_CONTENT_DECODING);
260
1.66k
    FU32TLV(fuzz, TLV_TYPE_NEW_FILE_PERMS, CURLOPT_NEW_FILE_PERMS);
261
68
    FU32TLV(fuzz, TLV_TYPE_NEW_DIRECTORY_PERMS, CURLOPT_NEW_DIRECTORY_PERMS);
262
816
    FU32TLV(fuzz, TLV_TYPE_PROXY_TRANSFER_MODE, CURLOPT_PROXY_TRANSFER_MODE);
263
7.27k
    FU32TLV(fuzz, TLV_TYPE_ADDRESS_SCOPE, CURLOPT_ADDRESS_SCOPE);
264
619
    FU32TLV(fuzz, TLV_TYPE_CERTINFO, CURLOPT_CERTINFO);
265
2.38k
    FU32TLV(fuzz, TLV_TYPE_TFTP_BLKSIZE, CURLOPT_TFTP_BLKSIZE);
266
62
    FU32TLV(fuzz, TLV_TYPE_SOCKS5_GSSAPI_NEC, CURLOPT_SOCKS5_GSSAPI_NEC);
267
579
    FU32TLV(fuzz, TLV_TYPE_FTP_USE_PRET, CURLOPT_FTP_USE_PRET);
268
2.35k
    FU32TLV(fuzz, TLV_TYPE_RTSP_SERVER_CSEQ, CURLOPT_RTSP_SERVER_CSEQ);
269
7.72k
    FU32TLV(fuzz, TLV_TYPE_TRANSFER_ENCODING, CURLOPT_TRANSFER_ENCODING);
270
1.35k
    FU32TLV(fuzz, TLV_TYPE_ACCEPTTIMEOUT_MS, CURLOPT_ACCEPTTIMEOUT_MS);
271
2.04k
    FU32TLV(fuzz, TLV_TYPE_TCP_KEEPALIVE, CURLOPT_TCP_KEEPALIVE);
272
2.76k
    FU32TLV(fuzz, TLV_TYPE_TCP_KEEPIDLE, CURLOPT_TCP_KEEPIDLE);
273
2.50k
    FU32TLV(fuzz, TLV_TYPE_TCP_KEEPINTVL, CURLOPT_TCP_KEEPINTVL);
274
764
    FU32TLV(fuzz, TLV_TYPE_SASL_IR, CURLOPT_SASL_IR);
275
2.31k
    FU32TLV(fuzz, TLV_TYPE_SSL_ENABLE_ALPN, CURLOPT_SSL_ENABLE_ALPN);
276
3.16k
    FU32TLV(fuzz, TLV_TYPE_EXPECT_100_TIMEOUT_MS, CURLOPT_EXPECT_100_TIMEOUT_MS);
277
804
    FU32TLV(fuzz, TLV_TYPE_SSL_VERIFYSTATUS, CURLOPT_SSL_VERIFYSTATUS);
278
64
    FU32TLV(fuzz, TLV_TYPE_SSL_FALSESTART, CURLOPT_SSL_FALSESTART);
279
2.20k
    FU32TLV(fuzz, TLV_TYPE_PATH_AS_IS, CURLOPT_PATH_AS_IS);
280
654
    FU32TLV(fuzz, TLV_TYPE_PIPEWAIT, CURLOPT_PIPEWAIT);
281
2.17k
    FU32TLV(fuzz, TLV_TYPE_STREAM_WEIGHT, CURLOPT_STREAM_WEIGHT);
282
560
    FU32TLV(fuzz, TLV_TYPE_TFTP_NO_OPTIONS, CURLOPT_TFTP_NO_OPTIONS);
283
518
    FU32TLV(fuzz, TLV_TYPE_TCP_FASTOPEN, CURLOPT_TCP_FASTOPEN);
284
1.17k
    FU32TLV(fuzz, TLV_TYPE_KEEP_SENDING_ON_ERROR, CURLOPT_KEEP_SENDING_ON_ERROR);
285
771
    FU32TLV(fuzz, TLV_TYPE_PROXY_SSL_VERIFYPEER, CURLOPT_PROXY_SSL_VERIFYPEER);
286
732
    FU32TLV(fuzz, TLV_TYPE_PROXY_SSL_VERIFYHOST, CURLOPT_PROXY_SSL_VERIFYHOST);
287
562
    FU32TLV(fuzz, TLV_TYPE_PROXY_SSL_OPTIONS, CURLOPT_PROXY_SSL_OPTIONS);
288
993
    FU32TLV(fuzz, TLV_TYPE_SUPPRESS_CONNECT_HEADERS, CURLOPT_SUPPRESS_CONNECT_HEADERS);
289
1.56k
    FU32TLV(fuzz, TLV_TYPE_SOCKS5_AUTH, CURLOPT_SOCKS5_AUTH);
290
91
    FU32TLV(fuzz, TLV_TYPE_SSH_COMPRESSION, CURLOPT_SSH_COMPRESSION);
291
615
    FU32TLV(fuzz, TLV_TYPE_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS);
292
1.14k
    FU32TLV(fuzz, TLV_TYPE_HAPROXYPROTOCOL, CURLOPT_HAPROXYPROTOCOL);
293
906
    FU32TLV(fuzz, TLV_TYPE_DNS_SHUFFLE_ADDRESSES, CURLOPT_DNS_SHUFFLE_ADDRESSES);
294
541
    FU32TLV(fuzz, TLV_TYPE_DISALLOW_USERNAME_IN_URL, CURLOPT_DISALLOW_USERNAME_IN_URL);
295
10.0k
    FU32TLV(fuzz, TLV_TYPE_UPLOAD_BUFFERSIZE, CURLOPT_UPLOAD_BUFFERSIZE);
296
1.84k
    FU32TLV(fuzz, TLV_TYPE_UPKEEP_INTERVAL_MS, CURLOPT_UPKEEP_INTERVAL_MS);
297
2.77k
    FU32TLV(fuzz, TLV_TYPE_HTTP09_ALLOWED, CURLOPT_HTTP09_ALLOWED);
298
1.85k
    FU32TLV(fuzz, TLV_TYPE_ALTSVC_CTRL, CURLOPT_ALTSVC_CTRL);
299
2.22k
    FU32TLV(fuzz, TLV_TYPE_MAXAGE_CONN, CURLOPT_MAXAGE_CONN);
300
540
    FU32TLV(fuzz, TLV_TYPE_MAIL_RCPT_ALLOWFAILS, CURLOPT_MAIL_RCPT_ALLOWFAILS);
301
839
    FU32TLV(fuzz, TLV_TYPE_HSTS_CTRL, CURLOPT_HSTS_CTRL);
302
443
    FU32TLV(fuzz, TLV_TYPE_DOH_SSL_VERIFYPEER, CURLOPT_DOH_SSL_VERIFYPEER);
303
649
    FU32TLV(fuzz, TLV_TYPE_DOH_SSL_VERIFYHOST, CURLOPT_DOH_SSL_VERIFYHOST);
304
546
    FU32TLV(fuzz, TLV_TYPE_DOH_SSL_VERIFYSTATUS, CURLOPT_DOH_SSL_VERIFYSTATUS);
305
2.11k
    FU32TLV(fuzz, TLV_TYPE_MAXLIFETIME_CONN, CURLOPT_MAXLIFETIME_CONN);
306
1.02k
    FU32TLV(fuzz, TLV_TYPE_MIME_OPTIONS, CURLOPT_MIME_OPTIONS);
307
2.81k
    FU32TLV(fuzz, TLV_TYPE_CA_CACHE_TIMEOUT, CURLOPT_CA_CACHE_TIMEOUT);
308
547
    FU32TLV(fuzz, TLV_TYPE_QUICK_EXIT, CURLOPT_QUICK_EXIT);
309
1.44k
    FU32TLV(fuzz, TLV_TYPE_SERVER_RESPONSE_TIMEOUT_MS, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS);
310
2.72k
    FU32TLV(fuzz, TLV_TYPE_TCP_KEEPCNT, CURLOPT_TCP_KEEPCNT);
311
2.95k
    FU32TLV(fuzz, TLV_TYPE_SSLVERSION, CURLOPT_SSLVERSION);
312
3.16k
    FU32TLV(fuzz, TLV_TYPE_TIMECONDITION, CURLOPT_TIMECONDITION);
313
5.13k
    FU32TLV(fuzz, TLV_TYPE_PROXYAUTH, CURLOPT_PROXYAUTH);
314
3.48k
    FU32TLV(fuzz, TLV_TYPE_IPRESOLVE, CURLOPT_IPRESOLVE);
315
2.63k
    FU32TLV(fuzz, TLV_TYPE_USE_SSL, CURLOPT_USE_SSL);
316
1.37k
    FU32TLV(fuzz, TLV_TYPE_FTPSSLAUTH, CURLOPT_FTPSSLAUTH);
317
1.62k
    FU32TLV(fuzz, TLV_TYPE_FTP_FILEMETHOD, CURLOPT_FTP_FILEMETHOD);
318
77
    FU32TLV(fuzz, TLV_TYPE_SSH_AUTH_TYPES, CURLOPT_SSH_AUTH_TYPES);
319
1.72k
    FU32TLV(fuzz, TLV_TYPE_POSTREDIR, CURLOPT_POSTREDIR);
320
61
    FU32TLV(fuzz, TLV_TYPE_GSSAPI_DELEGATION, CURLOPT_GSSAPI_DELEGATION);
321
819
    FU32TLV(fuzz, TLV_TYPE_SSL_OPTIONS, CURLOPT_SSL_OPTIONS);
322
10.0k
    FU32TLV(fuzz, TLV_TYPE_HEADEROPT, CURLOPT_HEADEROPT);
323
814
    FU32TLV(fuzz, TLV_TYPE_PROXY_SSLVERSION, CURLOPT_PROXY_SSLVERSION);
324
5.37k
    FU32TLV_OFF_T(fuzz, TLV_TYPE_RESUME_FROM_LARGE,
325
5.37k
                  CURLOPT_RESUME_FROM_LARGE);
326
3.77k
    FU32TLV_OFF_T(fuzz, TLV_TYPE_MAXFILESIZE_LARGE,
327
3.77k
                  CURLOPT_MAXFILESIZE_LARGE);
328
    /* An arbitrary size can make libcurl read beyond POSTFIELDS' allocation,
329
       so POSTFIELDSIZE_LARGE remains deliberately unavailable. */
330
9.04k
    FU32TLV_OFF_T(fuzz, TLV_TYPE_MAX_SEND_SPEED_LARGE,
331
9.04k
                  CURLOPT_MAX_SEND_SPEED_LARGE);
332
22.3k
    FU32TLV_OFF_T(fuzz, TLV_TYPE_MAX_RECV_SPEED_LARGE,
333
22.3k
                  CURLOPT_MAX_RECV_SPEED_LARGE);
334
779
    FU32TLV_OFF_T(fuzz, TLV_TYPE_TIMEVALUE_LARGE, CURLOPT_TIMEVALUE_LARGE);
335
336
    /* Harness-owned loopback DoH responder. A non-empty DOH_URL alone makes
337
       every probe fail in the sandbox; these records let a seed opt into a
338
       reachable local endpoint and choose the response it serves. */
339
3.81k
    case TLV_TYPE_DOH_LOOPBACK:
340
3.81k
      fuzz->doh.enabled = 1;
341
3.81k
      break;
342
343
526
    case TLV_TYPE_DOH_RESPONSE:
344
526
      fuzz->doh.response = tlv->value;
345
526
      fuzz->doh.response_len = tlv->length;
346
526
      break;
347
348
1.16k
    case TLV_TYPE_DOH_HTTP_STATUS:
349
1.16k
      if(tlv->length >= 4)
350
336
        fuzz->doh.http_status = to_u32(tlv->value);
351
827
      else if(tlv->length >= 1)
352
431
        fuzz->doh.http_status = tlv->value[0];
353
1.16k
      break;
354
355
1.43k
    case TLV_TYPE_VERBOSE:
356
      /* Enable verbose tracing with a no-op debug callback so infof()
357
         arguments (notably the DoH status/error strings) are evaluated. */
358
1.43k
      fuzz->doh_verbose = 1;
359
1.43k
      break;
360
361
9.65k
    case TLV_TYPE_TRACE:
362
      /* Copy a bounded curl_global_trace() configuration. An empty value is
363
         treated as "all" when the options are applied. */
364
9.65k
      if(tlv->length > 0) {
365
8.27k
        size_t copy_len = tlv->length;
366
8.27k
        if(copy_len >= sizeof(fuzz->trace_config))
367
203
          copy_len = sizeof(fuzz->trace_config) - 1;
368
8.27k
        memcpy(fuzz->trace_config, tlv->value, copy_len);
369
8.27k
        fuzz->trace_config[copy_len] = '\0';
370
8.27k
      }
371
9.65k
      fuzz->trace_verbose = 1;
372
9.65k
      break;
373
374
3.86k
    case TLV_TYPE_TRACE_STDERR:
375
      /* Enable verbose tracing without a debug callback. The option applier
376
         redirects curl's stderr to /dev/null to keep the fuzzer quiet. */
377
3.86k
      fuzz->trace_stderr_verbose = 1;
378
3.86k
      break;
379
380
    /* Define a set of singleton TLVs - they can only have their value set once
381
       and all follow the same pattern. */
382
343k
    FSINGLETONTLV(fuzz, TLV_TYPE_URL, CURLOPT_URL);
383
3.82k
    FSINGLETONTLV(fuzz, TLV_TYPE_DOH_URL, CURLOPT_DOH_URL);
384
5.05k
    FSINGLETONTLV(fuzz, TLV_TYPE_USERNAME, CURLOPT_USERNAME);
385
4.57k
    FSINGLETONTLV(fuzz, TLV_TYPE_PASSWORD, CURLOPT_PASSWORD);
386
1.98k
    FSINGLETONTLV(fuzz, TLV_TYPE_COOKIE, CURLOPT_COOKIE);
387
3.88k
    FSINGLETONTLV(fuzz, TLV_TYPE_RANGE, CURLOPT_RANGE);
388
4.15k
    FSINGLETONTLV(fuzz, TLV_TYPE_CUSTOMREQUEST, CURLOPT_CUSTOMREQUEST);
389
1.02k
    FSINGLETONTLV(fuzz, TLV_TYPE_MAIL_FROM, CURLOPT_MAIL_FROM);
390
22.4k
    FSINGLETONTLV(fuzz, TLV_TYPE_ACCEPTENCODING, CURLOPT_ACCEPT_ENCODING);
391
1.30k
    FSINGLETONTLV(fuzz, TLV_TYPE_RTSP_SESSION_ID, CURLOPT_RTSP_SESSION_ID);
392
1.05k
    FSINGLETONTLV(fuzz, TLV_TYPE_RTSP_STREAM_URI, CURLOPT_RTSP_STREAM_URI);
393
1.07k
    FSINGLETONTLV(fuzz, TLV_TYPE_RTSP_TRANSPORT, CURLOPT_RTSP_TRANSPORT);
394
993
    FSINGLETONTLV(fuzz, TLV_TYPE_MAIL_AUTH, CURLOPT_MAIL_AUTH);
395
1.58k
    FSINGLETONTLV(fuzz, TLV_TYPE_LOGIN_OPTIONS, CURLOPT_LOGIN_OPTIONS);
396
2.98k
    FSINGLETONTLV(fuzz, TLV_TYPE_XOAUTH2_BEARER, CURLOPT_XOAUTH2_BEARER);
397
5.41k
    FSINGLETONTLV(fuzz, TLV_TYPE_USERPWD, CURLOPT_USERPWD);
398
2.33k
    FSINGLETONTLV(fuzz, TLV_TYPE_USERAGENT, CURLOPT_USERAGENT);
399
94
    FSINGLETONTLV(fuzz, TLV_TYPE_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256);
400
63.1k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY, CURLOPT_PROXY);
401
6.37k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXYUSERPWD, CURLOPT_PROXYUSERPWD);
402
1.83k
    FSINGLETONTLV(fuzz, TLV_TYPE_REFERER, CURLOPT_REFERER);
403
594
    FSINGLETONTLV(fuzz, TLV_TYPE_FTPPORT, CURLOPT_FTPPORT);
404
1.35k
    FSINGLETONTLV(fuzz, TLV_TYPE_SSLCERT, CURLOPT_SSLCERT);
405
945
    FSINGLETONTLV(fuzz, TLV_TYPE_KEYPASSWD, CURLOPT_KEYPASSWD);
406
3.02k
    FSINGLETONTLV(fuzz, TLV_TYPE_INTERFACE, CURLOPT_INTERFACE);
407
46
    FSINGLETONTLV(fuzz, TLV_TYPE_KRBLEVEL, CURLOPT_KRBLEVEL);
408
1.12k
    FSINGLETONTLV(fuzz, TLV_TYPE_CAINFO, CURLOPT_CAINFO);
409
14.7k
    FSINGLETONTLV(fuzz, TLV_TYPE_SSL_CIPHER_LIST, CURLOPT_SSL_CIPHER_LIST);
410
1.38k
    FSINGLETONTLV(fuzz, TLV_TYPE_SSLCERTTYPE, CURLOPT_SSLCERTTYPE);
411
1.02k
    FSINGLETONTLV(fuzz, TLV_TYPE_SSLKEY, CURLOPT_SSLKEY);
412
973
    FSINGLETONTLV(fuzz, TLV_TYPE_SSLKEYTYPE, CURLOPT_SSLKEYTYPE);
413
10.2k
    FSINGLETONTLV(fuzz, TLV_TYPE_SSLENGINE, CURLOPT_SSLENGINE);
414
2.73k
    FSINGLETONTLV(fuzz, TLV_TYPE_CAPATH, CURLOPT_CAPATH);
415
985
    FSINGLETONTLV(fuzz, TLV_TYPE_FTP_ACCOUNT, CURLOPT_FTP_ACCOUNT);
416
55.7k
    FSINGLETONTLV(fuzz, TLV_TYPE_COOKIELIST, CURLOPT_COOKIELIST);
417
861
    FSINGLETONTLV(fuzz, TLV_TYPE_FTP_ALTERNATIVE_TO_USER, CURLOPT_FTP_ALTERNATIVE_TO_USER);
418
34
    FSINGLETONTLV(fuzz, TLV_TYPE_SSH_PUBLIC_KEYFILE, CURLOPT_SSH_PUBLIC_KEYFILE);
419
30
    FSINGLETONTLV(fuzz, TLV_TYPE_SSH_PRIVATE_KEYFILE, CURLOPT_SSH_PRIVATE_KEYFILE);
420
38
    FSINGLETONTLV(fuzz, TLV_TYPE_SSH_HOST_PUBLIC_KEY_MD5, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5);
421
1.14k
    FSINGLETONTLV(fuzz, TLV_TYPE_ISSUERCERT, CURLOPT_ISSUERCERT);
422
3.75k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXYUSERNAME, CURLOPT_PROXYUSERNAME);
423
5.08k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXYPASSWORD, CURLOPT_PROXYPASSWORD);
424
13.1k
    FSINGLETONTLV(fuzz, TLV_TYPE_NOPROXY, CURLOPT_NOPROXY);
425
34
    FSINGLETONTLV(fuzz, TLV_TYPE_SSH_KNOWNHOSTS, CURLOPT_SSH_KNOWNHOSTS);
426
32
    FSINGLETONTLV(fuzz, TLV_TYPE_TLSAUTH_USERNAME, CURLOPT_TLSAUTH_USERNAME);
427
40
    FSINGLETONTLV(fuzz, TLV_TYPE_TLSAUTH_PASSWORD, CURLOPT_TLSAUTH_PASSWORD);
428
38
    FSINGLETONTLV(fuzz, TLV_TYPE_TLSAUTH_TYPE, CURLOPT_TLSAUTH_TYPE);
429
38
    FSINGLETONTLV(fuzz, TLV_TYPE_DNS_SERVERS, CURLOPT_DNS_SERVERS);
430
30
    FSINGLETONTLV(fuzz, TLV_TYPE_DNS_INTERFACE, CURLOPT_DNS_INTERFACE);
431
34
    FSINGLETONTLV(fuzz, TLV_TYPE_DNS_LOCAL_IP4, CURLOPT_DNS_LOCAL_IP4);
432
32
    FSINGLETONTLV(fuzz, TLV_TYPE_DNS_LOCAL_IP6, CURLOPT_DNS_LOCAL_IP6);
433
771
    FSINGLETONTLV(fuzz, TLV_TYPE_PINNEDPUBLICKEY, CURLOPT_PINNEDPUBLICKEY);
434
4.48k
    FSINGLETONTLV(fuzz, TLV_TYPE_UNIX_SOCKET_PATH, CURLOPT_UNIX_SOCKET_PATH);
435
1.84k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_SERVICE_NAME, CURLOPT_PROXY_SERVICE_NAME);
436
2.15k
    FSINGLETONTLV(fuzz, TLV_TYPE_SERVICE_NAME, CURLOPT_SERVICE_NAME);
437
17.0k
    FSINGLETONTLV(fuzz, TLV_TYPE_DEFAULT_PROTOCOL, CURLOPT_DEFAULT_PROTOCOL);
438
1.21k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_CAINFO, CURLOPT_PROXY_CAINFO);
439
703
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_CAPATH, CURLOPT_PROXY_CAPATH);
440
34
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_TLSAUTH_USERNAME, CURLOPT_PROXY_TLSAUTH_USERNAME);
441
40
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_TLSAUTH_PASSWORD, CURLOPT_PROXY_TLSAUTH_PASSWORD);
442
42
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_TLSAUTH_TYPE, CURLOPT_PROXY_TLSAUTH_TYPE);
443
1.23k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_SSLCERT, CURLOPT_PROXY_SSLCERT);
444
1.27k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_SSLCERTTYPE, CURLOPT_PROXY_SSLCERTTYPE);
445
1.27k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_SSLKEY, CURLOPT_PROXY_SSLKEY);
446
1.45k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_SSLKEYTYPE, CURLOPT_PROXY_SSLKEYTYPE);
447
1.82k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_KEYPASSWD, CURLOPT_PROXY_KEYPASSWD);
448
1.09k
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_SSL_CIPHER_LIST, CURLOPT_PROXY_SSL_CIPHER_LIST);
449
785
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_CRLFILE, CURLOPT_PROXY_CRLFILE);
450
5.09k
    FSINGLETONTLV(fuzz, TLV_TYPE_PRE_PROXY, CURLOPT_PRE_PROXY);
451
973
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_PINNEDPUBLICKEY, CURLOPT_PROXY_PINNEDPUBLICKEY);
452
2.03k
    FSINGLETONTLV(fuzz, TLV_TYPE_ABSTRACT_UNIX_SOCKET, CURLOPT_ABSTRACT_UNIX_SOCKET);
453
2.01k
    FSINGLETONTLV(fuzz, TLV_TYPE_REQUEST_TARGET, CURLOPT_REQUEST_TARGET);
454
3.01k
    FSINGLETONTLV(fuzz, TLV_TYPE_TLS13_CIPHERS, CURLOPT_TLS13_CIPHERS);
455
823
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_TLS13_CIPHERS, CURLOPT_PROXY_TLS13_CIPHERS);
456
2.28k
    FSINGLETONTLV(fuzz, TLV_TYPE_SASL_AUTHZID, CURLOPT_SASL_AUTHZID);
457
757
    FSINGLETONTLV(fuzz, TLV_TYPE_PROXY_ISSUERCERT, CURLOPT_PROXY_ISSUERCERT);
458
12.2k
    FSINGLETONTLV(fuzz, TLV_TYPE_SSL_EC_CURVES, CURLOPT_SSL_EC_CURVES);
459
24.3k
    FSINGLETONTLV(fuzz, TLV_TYPE_AWS_SIGV4, CURLOPT_AWS_SIGV4);
460
14.0k
    FSINGLETONTLV(fuzz, TLV_TYPE_REDIR_PROTOCOLS_STR, CURLOPT_REDIR_PROTOCOLS_STR);
461
2.14k
    FSINGLETONTLV(fuzz, TLV_TYPE_HAPROXY_CLIENT_IP, CURLOPT_HAPROXY_CLIENT_IP);
462
6.14k
    FSINGLETONTLV(fuzz, TLV_TYPE_ECH, CURLOPT_ECH);
463
368
    default:
464
      /* The fuzzer generates lots of unknown TLVs - we don't want these in the
465
         corpus so we reject any unknown TLVs. */
466
368
      rc = 127;
467
368
      goto EXIT_LABEL;
468
0
      break;
469
4.02M
  }
470
471
4.00M
  rc = 0;
472
473
4.02M
EXIT_LABEL:
474
475
4.02M
  fuzz_free((void **)&tmp);
476
477
4.02M
  return rc;
478
4.00M
}
479
480
/**
481
 * Converts a TLV data and length into an allocated string.
482
 */
483
char *fuzz_tlv_to_string(TLV *tlv)
484
817k
{
485
817k
  char *tlvstr;
486
487
  /* Allocate enough space, plus a null terminator */
488
817k
  tlvstr = (char *)malloc(tlv->length + 1);
489
490
817k
  if(tlvstr != NULL) {
491
817k
    memcpy(tlvstr, tlv->value, tlv->length);
492
817k
    tlvstr[tlv->length] = 0;
493
817k
  }
494
495
817k
  return tlvstr;
496
817k
}
497
498
/* set up for CURLOPT_HTTPPOST, an alternative API to CURLOPT_MIMEPOST */
499
void fuzz_setup_http_post(FUZZ_DATA *fuzz, TLV *tlv)
500
2.77k
{
501
2.77k
  if (fuzz->httppost == NULL) {
502
2.77k
    struct curl_httppost *post = NULL;
503
2.77k
    struct curl_httppost *last = NULL;
504
505
2.77k
    fuzz->post_body = fuzz_tlv_to_string(tlv);
506
2.77k
    if (fuzz->post_body == NULL) {
507
0
      return;
508
0
    }
509
510
    /* This is just one of several possible entrypoints to
511
     * the HTTPPOST API. see https://curl.se/libcurl/c/curl_formadd.html
512
     * for lots of others which could be added here.
513
     */
514
2.77k
    curl_formadd(&post, &last,
515
2.77k
                 CURLFORM_COPYNAME, FUZZ_HTTPPOST_NAME,
516
2.77k
                 CURLFORM_PTRCONTENTS, fuzz->post_body,
517
2.77k
                 CURLFORM_CONTENTLEN, (curl_off_t) strlen(fuzz->post_body),
518
2.77k
                 CURLFORM_END);
519
520
2.77k
    fuzz->last_post_part = last;
521
2.77k
    fuzz->httppost = post;
522
2.77k
  }
523
524
2.77k
  return;
525
2.77k
}
526
527
/**
528
 * Extract the values from the TLV.
529
 */
530
int fuzz_add_mime_part(TLV *src_tlv, curl_mimepart *part)
531
2.80M
{
532
2.80M
  FUZZ_DATA part_fuzz;
533
2.80M
  TLV tlv;
534
2.80M
  int rc = 0;
535
2.80M
  int tlv_rc;
536
537
2.80M
  memset(&part_fuzz, 0, sizeof(FUZZ_DATA));
538
539
2.80M
  if(src_tlv->length < sizeof(TLV_RAW)) {
540
    /* Not enough data for a single TLV - don't continue */
541
2.63M
    goto EXIT_LABEL;
542
2.63M
  }
543
544
  /* Set up the state parser */
545
171k
  part_fuzz.state.data = src_tlv->value;
546
171k
  part_fuzz.state.data_len = src_tlv->length;
547
548
171k
  for(tlv_rc = fuzz_get_first_tlv(&part_fuzz, &tlv);
549
333k
      tlv_rc == 0;
550
171k
      tlv_rc = fuzz_get_next_tlv(&part_fuzz, &tlv)) {
551
552
    /* Have the TLV in hand. Parse the TLV. */
553
165k
    rc = fuzz_parse_mime_tlv(part, &tlv);
554
555
165k
    if(rc != 0) {
556
      /* Failed to parse the TLV. Can't continue. */
557
3.56k
      goto EXIT_LABEL;
558
3.56k
    }
559
165k
  }
560
561
167k
  if(tlv_rc != TLV_RC_NO_MORE_TLVS) {
562
    /* A TLV call failed. Can't continue. */
563
41.6k
    goto EXIT_LABEL;
564
41.6k
  }
565
566
2.80M
EXIT_LABEL:
567
568
2.80M
  return rc;
569
167k
}
570
571
/**
572
 * Do different actions on the mime part for different received TLVs.
573
 */
574
int fuzz_parse_mime_tlv(curl_mimepart *part, TLV *tlv)
575
165k
{
576
165k
  int rc;
577
165k
  char *tmp;
578
579
165k
  switch(tlv->type) {
580
61.4k
    case TLV_TYPE_MIME_PART_NAME:
581
61.4k
      tmp = fuzz_tlv_to_string(tlv);
582
61.4k
      curl_mime_name(part, tmp);
583
61.4k
      fuzz_free((void **)&tmp);
584
61.4k
      break;
585
586
100k
    case TLV_TYPE_MIME_PART_DATA:
587
100k
      curl_mime_data(part, (const char *)tlv->value, tlv->length);
588
100k
      break;
589
590
3.56k
    default:
591
      /* The fuzzer generates lots of unknown TLVs - we don't want these in the
592
         corpus so we reject any unknown TLVs. */
593
3.56k
      rc = 255;
594
3.56k
      goto EXIT_LABEL;
595
0
      break;
596
165k
  }
597
598
161k
  rc = 0;
599
600
165k
EXIT_LABEL:
601
602
165k
  return rc;
603
161k
}