curl_fuzzer.cc
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2017, 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.haxx.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 
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <curl/curl.h>
29 #include "curl_fuzzer.h"
30 
35 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
36 {
37  int rc = 0;
38  int tlv_rc;
39  FUZZ_DATA fuzz;
40  TLV tlv;
41 
42  /* Have to set all fields to zero before getting to the terminate function */
43  memset(&fuzz, 0, sizeof(FUZZ_DATA));
44 
45  if(size < sizeof(TLV_RAW)) {
46  /* Not enough data for a single TLV - don't continue */
47  goto EXIT_LABEL;
48  }
49 
50  /* Try to initialize the fuzz data */
51  FTRY(fuzz_initialize_fuzz_data(&fuzz, data, size));
52 
53  for(tlv_rc = fuzz_get_first_tlv(&fuzz, &tlv);
54  tlv_rc == 0;
55  tlv_rc = fuzz_get_next_tlv(&fuzz, &tlv)) {
56 
57  /* Have the TLV in hand. Parse the TLV. */
58  rc = fuzz_parse_tlv(&fuzz, &tlv);
59 
60  if(rc != 0) {
61  /* Failed to parse the TLV. Can't continue. */
62  goto EXIT_LABEL;
63  }
64  }
65 
66  if(tlv_rc != TLV_RC_NO_MORE_TLVS) {
67  /* A TLV call failed. Can't continue. */
68  goto EXIT_LABEL;
69  }
70 
71  /* Do the CURL stuff! */
72  if(fuzz.header_list != NULL) {
73  curl_easy_setopt(fuzz.easy, CURLOPT_HTTPHEADER, fuzz.header_list);
74  }
75 
76  if(fuzz.mail_recipients_list != NULL) {
77  curl_easy_setopt(fuzz.easy, CURLOPT_MAIL_RCPT, fuzz.mail_recipients_list);
78  }
79 
80  curl_easy_perform(fuzz.easy);
81 
82 EXIT_LABEL:
83 
85 
86  /* This function must always return 0. Non-zero codes are reserved. */
87  return 0;
88 }
89 
93 uint32_t to_u32(uint8_t b[4])
94 {
95  uint32_t u;
96  u = (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];
97  return u;
98 }
99 
103 uint16_t to_u16(uint8_t b[2])
104 {
105  uint16_t u;
106  u = (b[0] << 8) + b[1];
107  return u;
108 }
109 
114  const uint8_t *data,
115  size_t data_len)
116 {
117  int rc = 0;
118 
119  /* Initialize the fuzz data. */
120  memset(fuzz, 0, sizeof(FUZZ_DATA));
121 
122  /* Create an easy handle. This will have all of the settings configured on
123  it. */
124  fuzz->easy = curl_easy_init();
125  FCHECK(fuzz->easy != NULL);
126 
127  /* Set some standard options on the CURL easy handle. We need to override the
128  socket function so that we create our own sockets to present to CURL. */
129  FTRY(curl_easy_setopt(fuzz->easy,
130  CURLOPT_OPENSOCKETFUNCTION,
132  FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_OPENSOCKETDATA, fuzz));
133 
134  /* In case something tries to set a socket option, intercept this. */
135  FTRY(curl_easy_setopt(fuzz->easy,
136  CURLOPT_SOCKOPTFUNCTION,
138 
139  /* Set the standard read function callback. */
140  FTRY(curl_easy_setopt(fuzz->easy,
141  CURLOPT_READFUNCTION,
143  FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_READDATA, fuzz));
144 
145  /* Set the standard write function callback. */
146  FTRY(curl_easy_setopt(fuzz->easy,
147  CURLOPT_WRITEFUNCTION,
149  FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_WRITEDATA, fuzz));
150 
151  /* Can enable verbose mode by changing 0L to 1L */
152  FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_VERBOSE, 0L));
153 
154  /* Set up the state parser */
155  fuzz->state.data = data;
156  fuzz->state.data_len = data_len;
157 
158 EXIT_LABEL:
159 
160  return rc;
161 }
162 
167 {
168  fuzz_free((void **)&fuzz->url);
169  fuzz_free((void **)&fuzz->username);
170  fuzz_free((void **)&fuzz->password);
171  fuzz_free((void **)&fuzz->postfields);
172  fuzz_free((void **)&fuzz->cookie);
173  fuzz_free((void **)&fuzz->range);
174  fuzz_free((void **)&fuzz->customrequest);
175  fuzz_free((void **)&fuzz->mail_from);
176 
177  if(fuzz->header_list != NULL) {
179  fuzz->header_list = NULL;
180  }
181 
182  if(fuzz->mail_recipients_list != NULL) {
184  fuzz->mail_recipients_list = NULL;
185  }
186 
187  if(fuzz->easy != NULL) {
188  curl_easy_cleanup(fuzz->easy);
189  fuzz->easy = NULL;
190  }
191 }
192 
196 void fuzz_free(void **ptr)
197 {
198  if(*ptr != NULL) {
199  free(*ptr);
200  *ptr = NULL;
201  }
202 }
203 
208  curlsocktype purpose,
209  struct curl_sockaddr *address)
210 {
211  FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
212  int fds[2];
213  curl_socket_t server_fd;
214  curl_socket_t client_fd;
215 
216  /* Handle unused parameters */
217  (void)purpose;
218  (void)address;
219 
220  if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
221  /* Failed to create a pair of sockets. */
222  return CURL_SOCKET_BAD;
223  }
224 
225  server_fd = fds[0];
226  client_fd = fds[1];
227 
228  /* Try and write the response data to the server file descriptor so the
229  client can read it. */
230  if(write(server_fd,
231  fuzz->rsp1_data,
232  fuzz->rsp1_data_len) != (ssize_t)fuzz->rsp1_data_len) {
233  /* Failed to write the data. */
234  return CURL_SOCKET_BAD;
235  }
236 
237  if(shutdown(server_fd, SHUT_WR)) {
238  return CURL_SOCKET_BAD;
239  }
240 
241  return client_fd;
242 }
243 
248 static int fuzz_sockopt_callback(void *ptr,
249  curl_socket_t curlfd,
250  curlsocktype purpose)
251 {
252  (void)ptr;
253  (void)curlfd;
254  (void)purpose;
255 
257 }
258 
262 static size_t fuzz_read_callback(char *buffer,
263  size_t size,
264  size_t nitems,
265  void *ptr)
266 {
267  FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
268  curl_off_t nread;
269 
270  /* If no upload data has been specified, then return an error code. */
271  if(fuzz->upload1_data_len == 0) {
272  /* No data to upload */
273  return CURL_READFUNC_ABORT;
274  }
275 
276  /* Send the upload data. */
277  memcpy(buffer,
278  fuzz->upload1_data,
279  fuzz->upload1_data_len);
280 
281  return fuzz->upload1_data_len;
282 }
283 
287 static size_t fuzz_write_callback(void *contents,
288  size_t size,
289  size_t nmemb,
290  void *ptr)
291 {
292  size_t total = size * nmemb;
293  FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
294  size_t copy_len = total;
295 
296  /* Restrict copy_len to at most TEMP_WRITE_ARRAY_SIZE. */
297  if(copy_len > TEMP_WRITE_ARRAY_SIZE) {
298  copy_len = TEMP_WRITE_ARRAY_SIZE;
299  }
300 
301  /* Copy bytes to the temp store just to ensure the parameters are
302  exercised. */
303  memcpy(fuzz->write_array, contents, copy_len);
304 
305  return total;
306 }
307 
312  TLV *tlv)
313 {
314  /* Reset the cursor. */
315  fuzz->state.data_pos = 0;
316  return fuzz_get_tlv_comn(fuzz, tlv);
317 }
318 
323  TLV *tlv)
324 {
325  /* Advance the cursor by the full length of the previous TLV. */
326  fuzz->state.data_pos += sizeof(TLV_RAW) + tlv->length;
327 
328  /* Work out if there's a TLV's worth of data to read */
329  if(fuzz->state.data_pos + sizeof(TLV_RAW) > fuzz->state.data_len) {
330  /* No more TLVs to parse */
331  return TLV_RC_NO_MORE_TLVS;
332  }
333 
334  return fuzz_get_tlv_comn(fuzz, tlv);
335 }
336 
341  TLV *tlv)
342 {
343  int rc = 0;
344  size_t data_offset;
345  TLV_RAW *raw;
346 
347  /* Start by casting the data stream to a TLV. */
348  raw = (TLV_RAW *)&fuzz->state.data[fuzz->state.data_pos];
349  data_offset = fuzz->state.data_pos + sizeof(TLV_RAW);
350 
351  /* Set the TLV values. */
352  tlv->type = to_u16(raw->raw_type);
353  tlv->length = to_u32(raw->raw_length);
354  tlv->value = &fuzz->state.data[data_offset];
355 
356  /* Sanity check that the TLV length is ok. */
357  if(data_offset + tlv->length > fuzz->state.data_len) {
358  rc = TLV_RC_SIZE_ERROR;
359  }
360 
361  return rc;
362 }
363 
368 {
369  int rc;
370  char *tmp;
371 
372  switch(tlv->type) {
373  case TLV_TYPE_RESPONSE1:
374  /* The pointers in the TLV will always be valid as long as the fuzz data
375  is in scope, which is the entirety of this file. */
376  fuzz->rsp1_data = tlv->value;
377  fuzz->rsp1_data_len = tlv->length;
378  break;
379 
380  case TLV_TYPE_UPLOAD1:
381  /* The pointers in the TLV will always be valid as long as the fuzz data
382  is in scope, which is the entirety of this file. */
383  fuzz->upload1_data = tlv->value;
384  fuzz->upload1_data_len = tlv->length;
385 
386  curl_easy_setopt(fuzz->easy, CURLOPT_UPLOAD, 1L);
387  curl_easy_setopt(fuzz->easy,
388  CURLOPT_INFILESIZE_LARGE,
390  break;
391 
392  case TLV_TYPE_HEADER:
393  tmp = fuzz_tlv_to_string(tlv);
394  fuzz->header_list = curl_slist_append(fuzz->header_list, tmp);
395  fuzz_free((void **)&tmp);
396  break;
397 
399  tmp = fuzz_tlv_to_string(tlv);
400  fuzz->mail_recipients_list =
402  fuzz_free((void **)&tmp);
403  break;
404 
405  /* Define a set of singleton TLVs - they can only have their value set once
406  and all follow the same pattern. */
407  FSINGLETONTLV(TLV_TYPE_URL, url, CURLOPT_URL);
408  FSINGLETONTLV(TLV_TYPE_USERNAME, username, CURLOPT_USERNAME);
409  FSINGLETONTLV(TLV_TYPE_PASSWORD, password, CURLOPT_PASSWORD);
410  FSINGLETONTLV(TLV_TYPE_POSTFIELDS, postfields, CURLOPT_POSTFIELDS);
411  FSINGLETONTLV(TLV_TYPE_COOKIE, cookie, CURLOPT_COOKIE);
412  FSINGLETONTLV(TLV_TYPE_RANGE, range, CURLOPT_RANGE);
413  FSINGLETONTLV(TLV_TYPE_CUSTOMREQUEST, customrequest, CURLOPT_CUSTOMREQUEST);
414  FSINGLETONTLV(TLV_TYPE_MAIL_FROM, mail_from, CURLOPT_MAIL_FROM);
415 
416  default:
417  /* The fuzzer generates lots of unknown TLVs - we don't want these in the
418  corpus so we reject any unknown TLVs. */
419  rc = 255;
420  goto EXIT_LABEL;
421  break;
422  }
423 
424  rc = 0;
425 
426 EXIT_LABEL:
427 
428  return rc;
429 }
430 
435 {
436  char *tlvstr;
437 
438  /* Allocate enough space, plus a null terminator */
439  tlvstr = (char *)malloc(tlv->length + 1);
440 
441  if(tlvstr != NULL) {
442  memcpy(tlvstr, tlv->value, tlv->length);
443  tlvstr[tlv->length] = 0;
444  }
445 
446  return tlvstr;
447 }
FUZZ_PARSE_STATE state
Definition: curl_fuzzer.h:102
#define free(ptr)
Definition: curl_memory.h:130
#define TLV_TYPE_COOKIE
Definition: curl_fuzzer.h:35
#define TLV_TYPE_USERNAME
Definition: curl_fuzzer.h:31
const uint8_t * rsp1_data
Definition: curl_fuzzer.h:108
struct tlv_raw TLV_RAW
Byte stream representation of the TLV header.
size_t rsp1_data_len
Definition: curl_fuzzer.h:109
char * password
Definition: curl_fuzzer.h:118
uint32_t to_u32(uint8_t b[4])
Utility function to convert 4 bytes to a u32 predictably.
Definition: curl_fuzzer.cc:93
int fuzz_get_first_tlv(FUZZ_DATA *fuzz, TLV *tlv)
TLV access function - gets the first TLV from a data stream.
Definition: curl_fuzzer.cc:311
#define FTRY(FUNC)
Definition: curl_fuzzer.h:162
char * customrequest
Definition: curl_fuzzer.h:122
#define TLV_TYPE_CUSTOMREQUEST
Definition: curl_fuzzer.h:38
size_t upload1_data_len
Definition: curl_fuzzer.h:113
#define CURL_SOCKET_BAD
Definition: curl.h:131
CURL * easy
Definition: curl_fuzzer.h:99
UNITTEST_START char * ptr
Definition: unit1330.c:38
int fuzz_get_next_tlv(FUZZ_DATA *fuzz, TLV *tlv)
TLV access function - gets the next TLV from a data stream.
Definition: curl_fuzzer.cc:322
char * fuzz_tlv_to_string(TLV *tlv)
Converts a TLV data and length into an allocated string.
Definition: curl_fuzzer.cc:434
char * cookie
Definition: curl_fuzzer.h:120
#define TLV_RC_NO_MORE_TLVS
Definition: curl_fuzzer.h:46
#define TLV_TYPE_RANGE
Definition: curl_fuzzer.h:37
int fuzz_initialize_fuzz_data(FUZZ_DATA *fuzz, const uint8_t *data, size_t data_len)
Initialize the local fuzz data structure.
Definition: curl_fuzzer.cc:113
#define TLV_TYPE_PASSWORD
Definition: curl_fuzzer.h:32
static char * password
Definition: unit1304.c:27
static size_t fuzz_write_callback(void *contents, size_t size, size_t nmemb, void *ptr)
Callback function for handling data output quietly.
Definition: curl_fuzzer.cc:287
#define malloc(size)
Definition: curl_memory.h:124
int fuzz_parse_tlv(FUZZ_DATA *fuzz, TLV *tlv)
Do different actions on the CURL handle for different received TLVs.
Definition: curl_fuzzer.cc:367
#define curl_easy_setopt(handle, option, value)
Definition: typecheck-gcc.h:41
char buffer[]
Definition: unit1308.c:48
void fuzz_free(void **ptr)
If a pointer has been allocated, free that pointer.
Definition: curl_fuzzer.cc:196
char * username
Definition: curl_fuzzer.h:117
int fuzz_get_tlv_comn(FUZZ_DATA *fuzz, TLV *tlv)
Common TLV function for accessing TLVs in a data stream.
Definition: curl_fuzzer.cc:340
static curl_socket_t fuzz_open_socket(void *ptr, curlsocktype purpose, struct curl_sockaddr *address)
Function for providing a socket to CURL already primed with data.
Definition: curl_fuzzer.cc:207
uint8_t raw_type[2]
Definition: curl_fuzzer.h:59
#define TLV_RC_SIZE_ERROR
Definition: curl_fuzzer.h:47
memcpy(filename, filename1, strlen(filename1))
char * postfields
Definition: curl_fuzzer.h:119
char * mail_from
Definition: curl_fuzzer.h:123
#define FSINGLETONTLV(TLVNAME, FIELDNAME, OPTNAME)
Definition: curl_fuzzer.h:181
#define TLV_TYPE_POSTFIELDS
Definition: curl_fuzzer.h:33
UNITTEST_START int rc
Definition: unit1301.c:31
CURL_EXTERN struct curl_slist * curl_slist_append(struct curl_slist *, const char *)
Definition: slist.c:89
CURL_EXTERN CURL * curl_easy_init(void)
Definition: easy.c:343
void fuzz_terminate_fuzz_data(FUZZ_DATA *fuzz)
Terminate the fuzz data structure, including freeing any allocated memory.
Definition: curl_fuzzer.cc:166
UNITTEST_START struct Curl_easy data
Definition: unit1399.c:82
curlsocktype
Definition: curl.h:360
const uint8_t * value
Definition: curl_fuzzer.h:75
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Fuzzing entry point.
Definition: curl_fuzzer.cc:35
CURL_EXTERN void curl_easy_cleanup(CURL *curl)
char write_array[TEMP_WRITE_ARRAY_SIZE]
Definition: curl_fuzzer.h:105
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition: system.h:420
#define TLV_TYPE_HEADER
Definition: curl_fuzzer.h:34
#define TEMP_WRITE_ARRAY_SIZE
Definition: curl_fuzzer.h:50
#define CURL_READFUNC_ABORT
Definition: curl.h:350
static size_t fuzz_read_callback(char *buffer, size_t size, size_t nitems, void *ptr)
Callback function for doing data uploads.
Definition: curl_fuzzer.cc:262
#define TLV_TYPE_MAIL_RECIPIENT
Definition: curl_fuzzer.h:39
uint32_t length
Definition: curl_fuzzer.h:72
const uint8_t * data
Definition: curl_fuzzer.h:85
#define ssize_t
Definition: config-win32.h:382
Byte stream representation of the TLV header.
Definition: curl_fuzzer.h:56
uint16_t type
Definition: curl_fuzzer.h:69
uint16_t to_u16(uint8_t b[2])
Utility function to convert 2 bytes to a u16 predictably.
Definition: curl_fuzzer.cc:103
char * url
Definition: curl_fuzzer.h:116
#define TLV_TYPE_RESPONSE1
Definition: curl_fuzzer.h:30
Data local to a fuzzing run.
Definition: curl_fuzzer.h:96
#define TLV_TYPE_URL
TLV types.
Definition: curl_fuzzer.h:29
static int fuzz_sockopt_callback(void *ptr, curl_socket_t curlfd, curlsocktype purpose)
Callback function for setting socket options on the sockets created by fuzz_open_socket.
Definition: curl_fuzzer.cc:248
uint8_t raw_length[4]
Definition: curl_fuzzer.h:62
#define FCHECK(COND)
Definition: curl_fuzzer.h:172
size_t size
Definition: unit1302.c:52
#define TLV_TYPE_MAIL_FROM
Definition: curl_fuzzer.h:40
struct curl_slist * mail_recipients_list
Definition: curl_fuzzer.h:129
int curl_socket_t
Definition: curl.h:130
CURL_EXTERN void curl_slist_free_all(struct curl_slist *)
Definition: slist.c:129
#define CURL_SOCKOPT_ALREADY_CONNECTED
Definition: curl.h:371
#define TLV_TYPE_UPLOAD1
Definition: curl_fuzzer.h:36
const uint8_t * upload1_data
Definition: curl_fuzzer.h:112
struct curl_slist * header_list
Definition: curl_fuzzer.h:126
char * range
Definition: curl_fuzzer.h:121
Definition: debug.c:29
CURL_EXTERN CURLcode curl_easy_perform(CURL *curl)


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:08