Coverage Report

Created: 2023-03-26 06:11

/src/curl_fuzzer/curl_fuzzer_callback.cc
Line
Count
Source (jump to first uncovered line)
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.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 <fcntl.h>
24
#include <string.h>
25
#include <unistd.h>
26
#include <sys/un.h>
27
#include <curl/curl.h>
28
#include "curl_fuzzer.h"
29
30
/**
31
 * Define a macro which checks to see that allocated file descriptors are
32
 * valid and won't cause issue with FD_SETs.  Taken from lib/select.h
33
 */
34
0
#define FUZZ_VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
35
36
/**
37
 * Function for providing a socket to CURL already primed with data.
38
 */
39
curl_socket_t fuzz_open_socket(void *ptr,
40
                               curlsocktype purpose,
41
                               struct curl_sockaddr *address)
42
0
{
43
0
  FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
44
0
  int fds[2];
45
0
  int flags;
46
0
  int status;
47
0
  const uint8_t *data;
48
0
  size_t data_len;
49
0
  struct sockaddr_un client_addr;
50
0
  FUZZ_SOCKET_MANAGER *sman;
51
52
  /* Handle unused parameters */
53
0
  (void)purpose;
54
0
  (void)address;
55
56
0
  if(fuzz->sockman[0].fd_state != FUZZ_SOCK_CLOSED &&
57
0
     fuzz->sockman[1].fd_state != FUZZ_SOCK_CLOSED) {
58
    /* Both sockets have already been opened. */
59
0
    return CURL_SOCKET_BAD;
60
0
  }
61
0
  else if(fuzz->sockman[0].fd_state != FUZZ_SOCK_CLOSED) {
62
0
    sman = &fuzz->sockman[1];
63
0
  }
64
0
  else {
65
0
    FV_PRINTF(fuzz, "FUZZ: Using socket manager 0 \n");
66
0
    sman = &fuzz->sockman[0];
67
0
  }
68
0
  FV_PRINTF(fuzz, "FUZZ[%d]: Using socket manager %d \n",
69
0
            sman->index,
70
0
            sman->index);
71
72
0
  if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
73
    /* Failed to create a pair of sockets. */
74
0
    return CURL_SOCKET_BAD;
75
0
  }
76
77
0
  if(!FUZZ_VALID_SOCK(fds[0]) || !FUZZ_VALID_SOCK(fds[1])) {
78
    /* One or more of the file descriptors is too large to fit in an fd_set,
79
       so reject it here. Print out a message because this ought to be quite
80
       rare. */
81
0
    printf("FUZZ[%d]: Not using file descriptors %d,%d as FD_SETSIZE is %d\n",
82
0
           sman->index,
83
0
           fds[0],
84
0
           fds[1],
85
0
           FD_SETSIZE);
86
87
    /* Close the file descriptors so they don't leak. */
88
0
    close(fds[0]);
89
0
    close(fds[1]);
90
91
0
    return CURL_SOCKET_BAD;
92
0
  }
93
94
  /* Make the server non-blocking. */
95
0
  flags = fcntl(fds[0], F_GETFL, 0);
96
0
  status = fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
97
98
0
  if(status == -1) {
99
    /* Close the file descriptors so they don't leak. */
100
0
    close(fds[0]);
101
0
    close(fds[1]);
102
103
    /* Setting non-blocking failed. Return a negative response code. */
104
0
    return CURL_SOCKET_BAD;
105
0
  }
106
107
  /* At this point, the file descriptors in hand should be good enough to
108
     work with. */
109
0
  sman->fd = fds[0];
110
0
  sman->fd_state = FUZZ_SOCK_OPEN;
111
112
  /* If the server should be sending data immediately, send it here. */
113
0
  data = sman->responses[0].data;
114
0
  data_len = sman->responses[0].data_len;
115
116
0
  if(data != NULL) {
117
0
    FV_PRINTF(fuzz, "FUZZ[%d]: Sending initial response \n", sman->index);
118
119
0
    if(write(sman->fd, data, data_len) != (ssize_t)data_len) {
120
      /* Close the file descriptors so they don't leak. */
121
0
      close(sman->fd);
122
0
      sman->fd = -1;
123
124
0
      close(fds[1]);
125
126
      /* Failed to write all of the response data. */
127
0
      return CURL_SOCKET_BAD;
128
0
    }
129
0
  }
130
131
  /* Check to see if the socket should be shut down immediately. */
132
0
  if(sman->responses[1].data == NULL) {
133
0
    FV_PRINTF(fuzz,
134
0
              "FUZZ[%d]: Shutting down server socket: %d \n",
135
0
              sman->index,
136
0
              sman->fd);
137
0
    shutdown(sman->fd, SHUT_WR);
138
0
    sman->fd_state = FUZZ_SOCK_SHUTDOWN;
139
0
  }
140
141
  /* Return the other half of the socket pair. */
142
0
  return fds[1];
143
0
}
144
145
/**
146
 * Callback function for setting socket options on the sockets created by
147
 * fuzz_open_socket. In our testbed the sockets are "already connected".
148
 */
149
int fuzz_sockopt_callback(void *ptr,
150
                          curl_socket_t curlfd,
151
                          curlsocktype purpose)
152
0
{
153
0
  (void)ptr;
154
0
  (void)curlfd;
155
0
  (void)purpose;
156
157
0
  return CURL_SOCKOPT_ALREADY_CONNECTED;
158
0
}
159
160
/**
161
 * Callback function for doing data uploads.
162
 */
163
size_t fuzz_read_callback(char *buffer,
164
                          size_t size,
165
                          size_t nitems,
166
                          void *ptr)
167
0
{
168
0
  FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
169
0
  size_t remaining_data;
170
0
  size_t buffer_size = size * nitems;
171
172
  /* If no upload data has been specified, then return an error code. */
173
0
  if(fuzz->upload1_data_len == 0) {
174
    /* No data to upload */
175
0
    return CURL_READFUNC_ABORT;
176
0
  }
177
178
  /* Work out how much data is remaining to upload. */
179
0
  remaining_data = fuzz->upload1_data_len - fuzz->upload1_data_written;
180
181
  /* Respect the buffer size that libcurl is giving us! */
182
0
  if(remaining_data > buffer_size) {
183
0
    remaining_data = buffer_size;
184
0
  }
185
186
0
  if(remaining_data > 0) {
187
0
    FV_PRINTF(fuzz,
188
0
              "FUZZ: Uploading %zu bytes from position %zu \n",
189
0
              remaining_data,
190
0
              fuzz->upload1_data_written);
191
192
    /* Send the upload data. */
193
0
    memcpy(buffer,
194
0
           &fuzz->upload1_data[fuzz->upload1_data_written],
195
0
           remaining_data);
196
197
    /* Increase the count of written data */
198
0
    fuzz->upload1_data_written += remaining_data;
199
0
  }
200
201
0
  return(remaining_data);
202
0
}
203
204
/**
205
 * Callback function for handling data output quietly.
206
 */
207
size_t fuzz_write_callback(void *contents,
208
                           size_t size,
209
                           size_t nmemb,
210
                           void *ptr)
211
0
{
212
0
  size_t total = size * nmemb;
213
0
  FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
214
0
  size_t copy_len = total;
215
216
  /* Restrict copy_len to at most TEMP_WRITE_ARRAY_SIZE. */
217
0
  if(copy_len > TEMP_WRITE_ARRAY_SIZE) {
218
0
    copy_len = TEMP_WRITE_ARRAY_SIZE;
219
0
  }
220
221
  /* Copy bytes to the temp store just to ensure the parameters are
222
     exercised. */
223
0
  memcpy(fuzz->write_array, contents, copy_len);
224
225
  /* Add on the total to the count. If it exceeds the maximum then return
226
     zero to the caller so that the transfer is terminated early. */
227
0
  fuzz->written_data += total;
228
229
0
  if(fuzz->written_data > MAXIMUM_WRITE_LENGTH) {
230
0
    FV_PRINTF(fuzz,
231
0
              "FUZZ: Exceeded maximum write length (%lu) \n",
232
0
              fuzz->written_data);
233
0
    total = 0;
234
0
  }
235
236
0
  return total;
237
0
}