/src/curl_fuzzer/legacy_fuzzer.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 | | |
23 | | #include <stdlib.h> |
24 | | #include <signal.h> |
25 | | #include <string.h> |
26 | | #include <unistd.h> |
27 | | #include <curl/curl.h> |
28 | | #include "curl_fuzzer.h" |
29 | | #include "legacy_fuzzer.h" |
30 | | #include "legacy_protocol_allowlist.h" |
31 | | #include "legacy_tlv_mutator.h" |
32 | | |
33 | | /** |
34 | | * Run one legacy TLV input independently of the exported libFuzzer symbol. |
35 | | * Keeping the implementation behind a normal C++ function lets every |
36 | | * protocol binary expose its own same-named source entrypoint, which is how |
37 | | * Fuzz Introspector attributes a binary's runtime coverage to its call tree. |
38 | | */ |
39 | | int LegacyFuzzerTestOneInput(const uint8_t *data, size_t size) |
40 | 225k | { |
41 | 225k | int rc = 0; |
42 | 225k | int tlv_rc; |
43 | 225k | FUZZ_DATA fuzz; |
44 | 225k | TLV tlv; |
45 | | |
46 | | /* Ignore SIGPIPE errors. We'll handle the errors ourselves. */ |
47 | 225k | signal(SIGPIPE, SIG_IGN); |
48 | | |
49 | | /* Have to set all fields to zero before getting to the terminate function */ |
50 | 225k | memset(&fuzz, 0, sizeof(FUZZ_DATA)); |
51 | | |
52 | 225k | if(size < sizeof(TLV_RAW)) { |
53 | | /* Not enough data for a single TLV - don't continue */ |
54 | 64 | goto EXIT_LABEL; |
55 | 64 | } |
56 | | |
57 | | /* Try to initialize the fuzz data */ |
58 | 225k | FTRY(fuzz_initialize_fuzz_data(&fuzz, data, size)); |
59 | | |
60 | 225k | for(tlv_rc = fuzz_get_first_tlv(&fuzz, &tlv); |
61 | 7.28M | tlv_rc == 0; |
62 | 7.08M | tlv_rc = fuzz_get_next_tlv(&fuzz, &tlv)) { |
63 | | |
64 | | /* Have the TLV in hand. Parse the TLV. */ |
65 | 7.08M | rc = fuzz_parse_tlv(&fuzz, &tlv); |
66 | | |
67 | 7.08M | if(rc != 0) { |
68 | | /* Failed to parse the TLV. Can't continue. */ |
69 | 30.8k | goto EXIT_LABEL; |
70 | 30.8k | } |
71 | 7.08M | } |
72 | | |
73 | 194k | if(tlv_rc != TLV_RC_NO_MORE_TLVS) { |
74 | | /* A TLV call failed. Can't continue. */ |
75 | 2.68k | goto EXIT_LABEL; |
76 | 2.68k | } |
77 | | |
78 | | /* Set up the standard easy options. */ |
79 | 191k | FTRY(fuzz_set_easy_options(&fuzz)); |
80 | | |
81 | | /** |
82 | | * Add in more curl options that have been accumulated over possibly |
83 | | * multiple TLVs. |
84 | | */ |
85 | 186k | if(fuzz.header_list != NULL) { |
86 | 12.5k | curl_easy_setopt(fuzz.easy, CURLOPT_HTTPHEADER, fuzz.header_list); |
87 | 12.5k | } |
88 | | |
89 | 186k | if(fuzz.mail_recipients_list != NULL) { |
90 | 2.07k | curl_easy_setopt(fuzz.easy, CURLOPT_MAIL_RCPT, fuzz.mail_recipients_list); |
91 | 2.07k | } |
92 | | |
93 | 186k | if(fuzz.mime != NULL) { |
94 | 6.91k | curl_easy_setopt(fuzz.easy, CURLOPT_MIMEPOST, fuzz.mime); |
95 | 6.91k | } |
96 | | |
97 | 186k | if (fuzz.httppost != NULL) { |
98 | 1.69k | curl_easy_setopt(fuzz.easy, CURLOPT_HTTPPOST, fuzz.httppost); |
99 | 1.69k | } |
100 | | |
101 | | /* Run the transfer. */ |
102 | 186k | fuzz_handle_transfer(&fuzz); |
103 | | |
104 | 225k | EXIT_LABEL: |
105 | | |
106 | 225k | fuzz_terminate_fuzz_data(&fuzz); |
107 | | |
108 | | /* This function must always return 0. Non-zero codes are reserved. */ |
109 | 225k | return 0; |
110 | 186k | } |
111 | | |
112 | | /** |
113 | | * Utility function to convert 4 bytes to a u32 predictably. |
114 | | */ |
115 | | uint32_t to_u32(const uint8_t b[4]) |
116 | 7.34M | { |
117 | 7.34M | uint32_t u; |
118 | | /* Promote into the unsigned result type before shifting. uint8_t otherwise |
119 | | promotes to signed int, and values with the high bit set make the |
120 | | left-shift undefined before curl ever observes the fuzzed boundary. */ |
121 | 7.34M | u = (static_cast<uint32_t>(b[0]) << 24) | |
122 | 7.34M | (static_cast<uint32_t>(b[1]) << 16) | |
123 | 7.34M | (static_cast<uint32_t>(b[2]) << 8) | |
124 | 7.34M | static_cast<uint32_t>(b[3]); |
125 | 7.34M | return u; |
126 | 7.34M | } |
127 | | |
128 | | /** |
129 | | * Utility function to convert 2 bytes to a u16 predictably. |
130 | | */ |
131 | | uint16_t to_u16(const uint8_t b[2]) |
132 | 7.22M | { |
133 | 7.22M | uint16_t u; |
134 | 7.22M | u = (b[0] << 8) + b[1]; |
135 | 7.22M | return u; |
136 | 7.22M | } |
137 | | |
138 | | /** |
139 | | * Initialize the local fuzz data structure. |
140 | | */ |
141 | | int fuzz_initialize_fuzz_data(FUZZ_DATA *fuzz, |
142 | | const uint8_t *data, |
143 | | size_t data_len) |
144 | 225k | { |
145 | 225k | int rc = 0; |
146 | 225k | int ii; |
147 | | |
148 | | /* Initialize the fuzz data. */ |
149 | 225k | memset(fuzz, 0, sizeof(FUZZ_DATA)); |
150 | | |
151 | | /* Create an easy handle. This will have all of the settings configured on |
152 | | it. */ |
153 | 225k | fuzz->easy = curl_easy_init(); |
154 | 225k | FCHECK(fuzz->easy != NULL); |
155 | | |
156 | | /* Set up the state parser */ |
157 | 225k | fuzz->state.data = data; |
158 | 225k | fuzz->state.data_len = data_len; |
159 | | |
160 | | /* Set up the state of the server sockets. */ |
161 | 675k | for(ii = 0; ii < FUZZ_NUM_CONNECTIONS; ii++) { |
162 | 450k | fuzz->sockman[ii].index = ii; |
163 | 450k | fuzz->sockman[ii].fd_state = FUZZ_SOCK_CLOSED; |
164 | 450k | } |
165 | | |
166 | | /* Check for verbose mode. */ |
167 | 225k | fuzz->verbose = (getenv("FUZZ_VERBOSE") != NULL); |
168 | | |
169 | 225k | FCHECK(setenv("CURL_HSTS_HTTP", "1", 0) == 0); |
170 | 225k | FCHECK(setenv("CURL_ALTSVC_HTTP", "1", 0) == 0); |
171 | | |
172 | 225k | EXIT_LABEL: |
173 | | |
174 | 225k | return rc; |
175 | 225k | } |
176 | | |
177 | | /** |
178 | | * Reapply resolver-sensitive string options with their canonical loopback |
179 | | * values before starting a transfer. |
180 | | * |
181 | | * Custom mutation and crossover already finalize generated buffers, but an |
182 | | * initial corpus entry or standalone reproducer is executed without passing |
183 | | * through either callback. The option tracker identifies only values that the |
184 | | * TLV parser successfully applied, so this does not enable routing options that |
185 | | * were absent from the input. DNS_INTERFACE is deliberately excluded: with |
186 | | * c-ares it is a device name passed to ares_set_local_dev(), not a hostname. |
187 | | */ |
188 | | static int fuzz_finalize_routing_options(FUZZ_DATA *fuzz) |
189 | 191k | { |
190 | 191k | int rc = 0; |
191 | | |
192 | 191k | #define FFINALIZE_ROUTING_OPTION(TLVTYPE, CURLOPTNAME) \ |
193 | 766k | if(fuzz->options[(CURLOPTNAME) % 1000]) { \ |
194 | 25.9k | const char *canonical = \ |
195 | 25.9k | legacy_tlv_mutator::CanonicalRoutingValue((TLVTYPE)); \ |
196 | 25.9k | FCHECK(canonical != NULL); \ |
197 | 25.9k | FTRY(curl_easy_setopt(fuzz->easy, (CURLOPTNAME), canonical)); \ |
198 | 25.9k | } |
199 | | |
200 | 191k | FFINALIZE_ROUTING_OPTION(TLV_TYPE_PROXY, CURLOPT_PROXY); |
201 | 191k | FFINALIZE_ROUTING_OPTION(TLV_TYPE_FTPPORT, CURLOPT_FTPPORT); |
202 | 191k | FFINALIZE_ROUTING_OPTION(TLV_TYPE_INTERFACE, CURLOPT_INTERFACE); |
203 | 191k | FFINALIZE_ROUTING_OPTION(TLV_TYPE_PRE_PROXY, CURLOPT_PRE_PROXY); |
204 | | |
205 | 191k | #undef FFINALIZE_ROUTING_OPTION |
206 | | |
207 | 191k | EXIT_LABEL: |
208 | 191k | return rc; |
209 | 191k | } |
210 | | |
211 | | /** |
212 | | * Set standard options on the curl easy. |
213 | | */ |
214 | | int fuzz_set_easy_options(FUZZ_DATA *fuzz) |
215 | 191k | { |
216 | 191k | int rc = 0; |
217 | | |
218 | | /* Existing seeds and direct reproducers bypass the custom mutator. Close |
219 | | that path before any transfer can resolve a corpus-provided endpoint. */ |
220 | 191k | FTRY(fuzz_finalize_routing_options(fuzz)); |
221 | | |
222 | | /* Set some standard options on the CURL easy handle. We need to override the |
223 | | socket function so that we create our own sockets to present to CURL. */ |
224 | 191k | FTRY(curl_easy_setopt(fuzz->easy, |
225 | 191k | CURLOPT_OPENSOCKETFUNCTION, |
226 | 191k | fuzz_open_socket)); |
227 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_OPENSOCKETDATA, fuzz)); |
228 | | |
229 | | /* In case something tries to set a socket option, intercept this. */ |
230 | 191k | FTRY(curl_easy_setopt(fuzz->easy, |
231 | 191k | CURLOPT_SOCKOPTFUNCTION, |
232 | 191k | fuzz_sockopt_callback)); |
233 | | |
234 | | /* Set the standard read function callback. */ |
235 | 191k | FTRY(curl_easy_setopt(fuzz->easy, |
236 | 191k | CURLOPT_READFUNCTION, |
237 | 191k | fuzz_read_callback)); |
238 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_READDATA, fuzz)); |
239 | | |
240 | | /* Set the standard write function callback. */ |
241 | 191k | FTRY(curl_easy_setopt(fuzz->easy, |
242 | 191k | CURLOPT_WRITEFUNCTION, |
243 | 191k | fuzz_write_callback)); |
244 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_WRITEDATA, fuzz)); |
245 | | |
246 | | /* Set the writable cookie jar path so cookies are tested. */ |
247 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_COOKIEJAR, FUZZ_COOKIE_JAR_PATH)); |
248 | | |
249 | | /* Set the RO cookie file path so cookies are tested. */ |
250 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_COOKIEFILE, FUZZ_RO_COOKIE_FILE_PATH)); |
251 | | |
252 | | /* Set altsvc header cache filepath so that it can be fuzzed. */ |
253 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_ALTSVC, FUZZ_ALT_SVC_HEADER_CACHE_PATH)); |
254 | | |
255 | | /* Set the hsts header cache filepath so that it can be fuzzed. */ |
256 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_HSTS, FUZZ_HSTS_HEADER_CACHE_PATH)); |
257 | | |
258 | | /* Set the Certificate Revocation List file path so it can be fuzzed */ |
259 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CRLFILE, FUZZ_CRL_FILE_PATH)); |
260 | | |
261 | | /* Loading the host trust store for every WSS mutation dominates the |
262 | | WebSocket target even when the in-process mock immediately ends the TLS |
263 | | handshake. Keep this exception local to that target: the other legacy |
264 | | fuzzers should retain libcurl's verification default so their ordinary |
265 | | mutations continue to cover certificate setup. An explicit |
266 | | SSL_VERIFYPEER TLV still restores verification in the WebSocket target. */ |
267 | | #ifdef FUZZ_PROTOCOLS_WS |
268 | 20.0k | if(!fuzz->options[CURLOPT_SSL_VERIFYPEER % 1000]) { |
269 | 19.8k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_SSL_VERIFYPEER, 0L)); |
270 | 19.8k | } |
271 | 20.0k | #endif |
272 | | |
273 | | /* Set the .netrc file path so it can be fuzzed */ |
274 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_NETRC_FILE, FUZZ_NETRC_FILE_PATH)); |
275 | | |
276 | | /* Time out requests quickly. */ |
277 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_TIMEOUT_MS, 200L)); |
278 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_SERVER_RESPONSE_TIMEOUT, 1L)); |
279 | | |
280 | | /* Can enable verbose mode by having the environment variable FUZZ_VERBOSE. */ |
281 | 191k | if(fuzz->verbose) { |
282 | 0 | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_VERBOSE, 1L)); |
283 | 0 | } |
284 | | |
285 | | /* Force resolution of all addresses to a specific IP address. */ |
286 | 191k | fuzz->connect_to_list = curl_slist_append(NULL, "::127.0.1.127:"); |
287 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CONNECT_TO, fuzz->connect_to_list)); |
288 | | |
289 | | /* Limit the protocols in use by this fuzzer. */ |
290 | 191k | FTRY(fuzz_set_allowed_protocols(fuzz)); |
291 | | |
292 | 191k | EXIT_LABEL: |
293 | | |
294 | 191k | return rc; |
295 | 186k | } fuzz_set_easy_options(fuzz_data*) Line | Count | Source | 215 | 171k | { | 216 | 171k | int rc = 0; | 217 | | | 218 | | /* Existing seeds and direct reproducers bypass the custom mutator. Close | 219 | | that path before any transfer can resolve a corpus-provided endpoint. */ | 220 | 171k | FTRY(fuzz_finalize_routing_options(fuzz)); | 221 | | | 222 | | /* Set some standard options on the CURL easy handle. We need to override the | 223 | | socket function so that we create our own sockets to present to CURL. */ | 224 | 171k | FTRY(curl_easy_setopt(fuzz->easy, | 225 | 171k | CURLOPT_OPENSOCKETFUNCTION, | 226 | 171k | fuzz_open_socket)); | 227 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_OPENSOCKETDATA, fuzz)); | 228 | | | 229 | | /* In case something tries to set a socket option, intercept this. */ | 230 | 171k | FTRY(curl_easy_setopt(fuzz->easy, | 231 | 171k | CURLOPT_SOCKOPTFUNCTION, | 232 | 171k | fuzz_sockopt_callback)); | 233 | | | 234 | | /* Set the standard read function callback. */ | 235 | 171k | FTRY(curl_easy_setopt(fuzz->easy, | 236 | 171k | CURLOPT_READFUNCTION, | 237 | 171k | fuzz_read_callback)); | 238 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_READDATA, fuzz)); | 239 | | | 240 | | /* Set the standard write function callback. */ | 241 | 171k | FTRY(curl_easy_setopt(fuzz->easy, | 242 | 171k | CURLOPT_WRITEFUNCTION, | 243 | 171k | fuzz_write_callback)); | 244 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_WRITEDATA, fuzz)); | 245 | | | 246 | | /* Set the writable cookie jar path so cookies are tested. */ | 247 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_COOKIEJAR, FUZZ_COOKIE_JAR_PATH)); | 248 | | | 249 | | /* Set the RO cookie file path so cookies are tested. */ | 250 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_COOKIEFILE, FUZZ_RO_COOKIE_FILE_PATH)); | 251 | | | 252 | | /* Set altsvc header cache filepath so that it can be fuzzed. */ | 253 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_ALTSVC, FUZZ_ALT_SVC_HEADER_CACHE_PATH)); | 254 | | | 255 | | /* Set the hsts header cache filepath so that it can be fuzzed. */ | 256 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_HSTS, FUZZ_HSTS_HEADER_CACHE_PATH)); | 257 | | | 258 | | /* Set the Certificate Revocation List file path so it can be fuzzed */ | 259 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CRLFILE, FUZZ_CRL_FILE_PATH)); | 260 | | | 261 | | /* Loading the host trust store for every WSS mutation dominates the | 262 | | WebSocket target even when the in-process mock immediately ends the TLS | 263 | | handshake. Keep this exception local to that target: the other legacy | 264 | | fuzzers should retain libcurl's verification default so their ordinary | 265 | | mutations continue to cover certificate setup. An explicit | 266 | | SSL_VERIFYPEER TLV still restores verification in the WebSocket target. */ | 267 | | #ifdef FUZZ_PROTOCOLS_WS | 268 | | if(!fuzz->options[CURLOPT_SSL_VERIFYPEER % 1000]) { | 269 | | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_SSL_VERIFYPEER, 0L)); | 270 | | } | 271 | | #endif | 272 | | | 273 | | /* Set the .netrc file path so it can be fuzzed */ | 274 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_NETRC_FILE, FUZZ_NETRC_FILE_PATH)); | 275 | | | 276 | | /* Time out requests quickly. */ | 277 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_TIMEOUT_MS, 200L)); | 278 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_SERVER_RESPONSE_TIMEOUT, 1L)); | 279 | | | 280 | | /* Can enable verbose mode by having the environment variable FUZZ_VERBOSE. */ | 281 | 171k | if(fuzz->verbose) { | 282 | 0 | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_VERBOSE, 1L)); | 283 | 0 | } | 284 | | | 285 | | /* Force resolution of all addresses to a specific IP address. */ | 286 | 171k | fuzz->connect_to_list = curl_slist_append(NULL, "::127.0.1.127:"); | 287 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CONNECT_TO, fuzz->connect_to_list)); | 288 | | | 289 | | /* Limit the protocols in use by this fuzzer. */ | 290 | 171k | FTRY(fuzz_set_allowed_protocols(fuzz)); | 291 | | | 292 | 171k | EXIT_LABEL: | 293 | | | 294 | 171k | return rc; | 295 | 166k | } |
fuzz_set_easy_options(fuzz_data*) Line | Count | Source | 215 | 20.0k | { | 216 | 20.0k | int rc = 0; | 217 | | | 218 | | /* Existing seeds and direct reproducers bypass the custom mutator. Close | 219 | | that path before any transfer can resolve a corpus-provided endpoint. */ | 220 | 20.0k | FTRY(fuzz_finalize_routing_options(fuzz)); | 221 | | | 222 | | /* Set some standard options on the CURL easy handle. We need to override the | 223 | | socket function so that we create our own sockets to present to CURL. */ | 224 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, | 225 | 20.0k | CURLOPT_OPENSOCKETFUNCTION, | 226 | 20.0k | fuzz_open_socket)); | 227 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_OPENSOCKETDATA, fuzz)); | 228 | | | 229 | | /* In case something tries to set a socket option, intercept this. */ | 230 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, | 231 | 20.0k | CURLOPT_SOCKOPTFUNCTION, | 232 | 20.0k | fuzz_sockopt_callback)); | 233 | | | 234 | | /* Set the standard read function callback. */ | 235 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, | 236 | 20.0k | CURLOPT_READFUNCTION, | 237 | 20.0k | fuzz_read_callback)); | 238 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_READDATA, fuzz)); | 239 | | | 240 | | /* Set the standard write function callback. */ | 241 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, | 242 | 20.0k | CURLOPT_WRITEFUNCTION, | 243 | 20.0k | fuzz_write_callback)); | 244 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_WRITEDATA, fuzz)); | 245 | | | 246 | | /* Set the writable cookie jar path so cookies are tested. */ | 247 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_COOKIEJAR, FUZZ_COOKIE_JAR_PATH)); | 248 | | | 249 | | /* Set the RO cookie file path so cookies are tested. */ | 250 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_COOKIEFILE, FUZZ_RO_COOKIE_FILE_PATH)); | 251 | | | 252 | | /* Set altsvc header cache filepath so that it can be fuzzed. */ | 253 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_ALTSVC, FUZZ_ALT_SVC_HEADER_CACHE_PATH)); | 254 | | | 255 | | /* Set the hsts header cache filepath so that it can be fuzzed. */ | 256 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_HSTS, FUZZ_HSTS_HEADER_CACHE_PATH)); | 257 | | | 258 | | /* Set the Certificate Revocation List file path so it can be fuzzed */ | 259 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CRLFILE, FUZZ_CRL_FILE_PATH)); | 260 | | | 261 | | /* Loading the host trust store for every WSS mutation dominates the | 262 | | WebSocket target even when the in-process mock immediately ends the TLS | 263 | | handshake. Keep this exception local to that target: the other legacy | 264 | | fuzzers should retain libcurl's verification default so their ordinary | 265 | | mutations continue to cover certificate setup. An explicit | 266 | | SSL_VERIFYPEER TLV still restores verification in the WebSocket target. */ | 267 | 20.0k | #ifdef FUZZ_PROTOCOLS_WS | 268 | 20.0k | if(!fuzz->options[CURLOPT_SSL_VERIFYPEER % 1000]) { | 269 | 19.8k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_SSL_VERIFYPEER, 0L)); | 270 | 19.8k | } | 271 | 20.0k | #endif | 272 | | | 273 | | /* Set the .netrc file path so it can be fuzzed */ | 274 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_NETRC_FILE, FUZZ_NETRC_FILE_PATH)); | 275 | | | 276 | | /* Time out requests quickly. */ | 277 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_TIMEOUT_MS, 200L)); | 278 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_SERVER_RESPONSE_TIMEOUT, 1L)); | 279 | | | 280 | | /* Can enable verbose mode by having the environment variable FUZZ_VERBOSE. */ | 281 | 20.0k | if(fuzz->verbose) { | 282 | 0 | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_VERBOSE, 1L)); | 283 | 0 | } | 284 | | | 285 | | /* Force resolution of all addresses to a specific IP address. */ | 286 | 20.0k | fuzz->connect_to_list = curl_slist_append(NULL, "::127.0.1.127:"); | 287 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CONNECT_TO, fuzz->connect_to_list)); | 288 | | | 289 | | /* Limit the protocols in use by this fuzzer. */ | 290 | 20.0k | FTRY(fuzz_set_allowed_protocols(fuzz)); | 291 | | | 292 | 20.0k | EXIT_LABEL: | 293 | | | 294 | 20.0k | return rc; | 295 | 20.0k | } |
|
296 | | |
297 | | /** |
298 | | * Terminate the fuzz data structure, including freeing any allocated memory. |
299 | | */ |
300 | | void fuzz_terminate_fuzz_data(FUZZ_DATA *fuzz) |
301 | 225k | { |
302 | 225k | int ii; |
303 | | |
304 | 225k | fuzz_free((void **)&fuzz->postfields); |
305 | | |
306 | 675k | for(ii = 0; ii < FUZZ_NUM_CONNECTIONS; ii++) { |
307 | 450k | if(fuzz->sockman[ii].fd_state != FUZZ_SOCK_CLOSED) { |
308 | 104k | close(fuzz->sockman[ii].fd); |
309 | 104k | fuzz->sockman[ii].fd_state = FUZZ_SOCK_CLOSED; |
310 | 104k | } |
311 | 450k | } |
312 | | |
313 | 225k | if(fuzz->connect_to_list != NULL) { |
314 | 191k | curl_slist_free_all(fuzz->connect_to_list); |
315 | 191k | fuzz->connect_to_list = NULL; |
316 | 191k | } |
317 | | |
318 | 225k | if(fuzz->header_list != NULL) { |
319 | 12.6k | curl_slist_free_all(fuzz->header_list); |
320 | 12.6k | fuzz->header_list = NULL; |
321 | 12.6k | } |
322 | | |
323 | 225k | if(fuzz->mail_recipients_list != NULL) { |
324 | 2.19k | curl_slist_free_all(fuzz->mail_recipients_list); |
325 | 2.19k | fuzz->mail_recipients_list = NULL; |
326 | 2.19k | } |
327 | | |
328 | 225k | if(fuzz->mime != NULL) { |
329 | 7.47k | curl_mime_free(fuzz->mime); |
330 | 7.47k | fuzz->mime = NULL; |
331 | 7.47k | } |
332 | | |
333 | 225k | if(fuzz->easy != NULL) { |
334 | 225k | curl_easy_cleanup(fuzz->easy); |
335 | 225k | fuzz->easy = NULL; |
336 | 225k | } |
337 | | |
338 | | /* When you have passed the struct curl_httppost pointer to curl_easy_setopt |
339 | | * (using the CURLOPT_HTTPPOST option), you must not free the list until after |
340 | | * you have called curl_easy_cleanup for the curl handle. |
341 | | * https://curl.se/libcurl/c/curl_formadd.html */ |
342 | 225k | if (fuzz->httppost != NULL) { |
343 | 1.77k | curl_formfree(fuzz->httppost); |
344 | 1.77k | fuzz->httppost = NULL; |
345 | 1.77k | } |
346 | | |
347 | | // free after httppost and last_post_part. |
348 | 225k | if (fuzz->post_body != NULL) { |
349 | 1.77k | fuzz_free((void **)&fuzz->post_body); |
350 | 1.77k | } |
351 | 225k | } |
352 | | |
353 | | /** |
354 | | * If a pointer has been allocated, free that pointer. |
355 | | */ |
356 | | void fuzz_free(void **ptr) |
357 | 7.33M | { |
358 | 7.33M | if(*ptr != NULL) { |
359 | 782k | free(*ptr); |
360 | 782k | *ptr = NULL; |
361 | 782k | } |
362 | 7.33M | } |
363 | | |
364 | | /** |
365 | | * Function for handling the fuzz transfer, including sending responses to |
366 | | * requests. |
367 | | */ |
368 | | int fuzz_handle_transfer(FUZZ_DATA *fuzz) |
369 | 186k | { |
370 | 186k | int rc = 0; |
371 | 186k | CURLM *multi_handle; |
372 | 186k | int still_running; /* keep number of running handles */ |
373 | 186k | CURLMsg *msg; /* for picking up messages with the transfer status */ |
374 | 186k | int msgs_left; /* how many messages are left */ |
375 | 186k | int double_timeout = 0; |
376 | 186k | fd_set fdread; |
377 | 186k | fd_set fdwrite; |
378 | 186k | fd_set fdexcep; |
379 | 186k | struct timeval timeout; |
380 | 186k | int select_rc; |
381 | 186k | CURLMcode mc; |
382 | 186k | int maxfd = -1; |
383 | 186k | long curl_timeo = -1; |
384 | 186k | int ii; |
385 | 186k | FUZZ_SOCKET_MANAGER *sman[FUZZ_NUM_CONNECTIONS]; |
386 | | |
387 | 559k | for(ii = 0; ii < FUZZ_NUM_CONNECTIONS; ii++) { |
388 | 373k | sman[ii] = &fuzz->sockman[ii]; |
389 | | |
390 | | /* Set up the starting index for responses. */ |
391 | 373k | sman[ii]->response_index = 1; |
392 | 373k | } |
393 | | |
394 | | /* init a multi stack */ |
395 | 186k | multi_handle = curl_multi_init(); |
396 | | |
397 | | /* add the individual transfers */ |
398 | 186k | curl_multi_add_handle(multi_handle, fuzz->easy); |
399 | | |
400 | | /* Do an initial process. This might end the transfer immediately. */ |
401 | 186k | curl_multi_perform(multi_handle, &still_running); |
402 | 186k | FV_PRINTF(fuzz, |
403 | 186k | "FUZZ: Initial perform; still running? %d \n", |
404 | 186k | still_running); |
405 | | |
406 | 220k | while(still_running) { |
407 | | /* Reset the sets of file descriptors. */ |
408 | 37.8k | FD_ZERO(&fdread); |
409 | 37.8k | FD_ZERO(&fdwrite); |
410 | 37.8k | FD_ZERO(&fdexcep); |
411 | | |
412 | | /* Set a timeout of 10ms. This is lower than recommended by the multi guide |
413 | | but we're not going to any remote servers, so everything should complete |
414 | | very quickly. */ |
415 | 37.8k | timeout.tv_sec = 0; |
416 | 37.8k | timeout.tv_usec = 10000; |
417 | | |
418 | | /* get file descriptors from the transfers */ |
419 | 37.8k | mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); |
420 | 37.8k | if(mc != CURLM_OK) { |
421 | 0 | fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); |
422 | 0 | rc = -1; |
423 | 0 | break; |
424 | 0 | } |
425 | | |
426 | 113k | for(ii = 0; ii < FUZZ_NUM_CONNECTIONS; ii++) { |
427 | | /* Add the socket FD into the readable set if connected. */ |
428 | 75.6k | if(sman[ii]->fd_state == FUZZ_SOCK_OPEN) { |
429 | 30.7k | FD_SET(sman[ii]->fd, &fdread); |
430 | | |
431 | | /* Work out the maximum FD between the cURL file descriptors and the |
432 | | server FD. */ |
433 | 30.7k | maxfd = FUZZ_MAX(sman[ii]->fd, maxfd); |
434 | 30.7k | } |
435 | 75.6k | } |
436 | | |
437 | | /* Work out what file descriptors need work. */ |
438 | 37.8k | rc = fuzz_select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); |
439 | | |
440 | 37.8k | if(rc == -1) { |
441 | | /* Had an issue while selecting a file descriptor. Let's just exit. */ |
442 | 0 | FV_PRINTF(fuzz, "FUZZ: select failed, exiting \n"); |
443 | 0 | break; |
444 | 0 | } |
445 | | |
446 | | /* Check to see if a server file descriptor is readable. If it is, |
447 | | then send the next response from the fuzzing data. */ |
448 | 37.8k | int server_data_sent = 0; |
449 | 113k | for(ii = 0; ii < FUZZ_NUM_CONNECTIONS; ii++) { |
450 | 75.5k | if(sman[ii]->fd_state == FUZZ_SOCK_OPEN && |
451 | 75.5k | FD_ISSET(sman[ii]->fd, &fdread)) { |
452 | 27.7k | rc = fuzz_send_next_response(fuzz, sman[ii]); |
453 | 27.7k | if(rc != 0) { |
454 | | /* Failed to send a response. Break out here. */ |
455 | 114 | break; |
456 | 114 | } |
457 | 27.6k | server_data_sent = 1; |
458 | 27.6k | } |
459 | 75.5k | } |
460 | | |
461 | | /* Stall detection: exit after two consecutive iterations where no new |
462 | | data was provided to curl. This handles both select() timeouts and |
463 | | cases where curl registers a writable fd but cannot make progress |
464 | | (e.g. HTTP/2 egress stuck with no real peer to drain to). */ |
465 | 37.8k | if(!server_data_sent) { |
466 | 10.2k | FV_PRINTF(fuzz, "FUZZ: No data sent; stall count %d \n", double_timeout); |
467 | 10.2k | if(double_timeout == 1) { |
468 | 3.40k | break; |
469 | 3.40k | } |
470 | 6.80k | double_timeout = 1; |
471 | 6.80k | } |
472 | 27.6k | else { |
473 | 27.6k | double_timeout = 0; |
474 | 27.6k | } |
475 | | |
476 | 34.4k | curl_multi_perform(multi_handle, &still_running); |
477 | 34.4k | } |
478 | | |
479 | | /* Remove the easy handle from the multi stack. */ |
480 | 186k | curl_multi_remove_handle(multi_handle, fuzz->easy); |
481 | | |
482 | | /* Clean up the multi handle - the top level function will handle the easy |
483 | | handle. */ |
484 | 186k | curl_multi_cleanup(multi_handle); |
485 | | |
486 | 186k | return rc; |
487 | 186k | } |
488 | | |
489 | | /** |
490 | | * Sends the next fuzzing response to the server file descriptor. |
491 | | */ |
492 | | int fuzz_send_next_response(FUZZ_DATA *fuzz, FUZZ_SOCKET_MANAGER *sman) |
493 | 27.7k | { |
494 | 27.7k | int rc = 0; |
495 | 27.7k | ssize_t ret_in; |
496 | 27.7k | ssize_t ret_out; |
497 | 27.7k | char buffer[8192]; |
498 | 27.7k | const uint8_t *data; |
499 | 27.7k | size_t data_len; |
500 | | |
501 | | /* Need to read all data sent by the client so the file descriptor becomes |
502 | | unreadable. Because the file descriptor is non-blocking we won't just |
503 | | hang here. */ |
504 | 77.1k | do { |
505 | 77.1k | ret_in = read(sman->fd, buffer, sizeof(buffer)); |
506 | 77.1k | if(fuzz->verbose && ret_in > 0) { |
507 | 0 | printf("FUZZ[%d]: Received %zu bytes \n==>\n", sman->index, ret_in); |
508 | 0 | fwrite(buffer, ret_in, 1, stdout); |
509 | 0 | printf("\n<==\n"); |
510 | 0 | } |
511 | 77.1k | } while (ret_in > 0); |
512 | | |
513 | | /* Now send a response to the request that the client just made. */ |
514 | 27.7k | FV_PRINTF(fuzz, |
515 | 27.7k | "FUZZ[%d]: Sending next response: %d \n", |
516 | 27.7k | sman->index, |
517 | 27.7k | sman->response_index); |
518 | 27.7k | data = sman->responses[sman->response_index].data; |
519 | 27.7k | data_len = sman->responses[sman->response_index].data_len; |
520 | | |
521 | 27.7k | if(data != NULL) { |
522 | 27.7k | if(write(sman->fd, data, data_len) != (ssize_t)data_len) { |
523 | | /* Failed to write the data back to the client. Prevent any further |
524 | | testing. */ |
525 | 114 | rc = -1; |
526 | 114 | } |
527 | 27.7k | } |
528 | | |
529 | | /* Work out if there are any more responses. If not, then shut down the |
530 | | server. */ |
531 | 27.7k | sman->response_index++; |
532 | | |
533 | 27.7k | if(sman->response_index >= TLV_MAX_NUM_RESPONSES || |
534 | 27.7k | sman->responses[sman->response_index].data == NULL) { |
535 | 22.1k | FV_PRINTF(fuzz, |
536 | 22.1k | "FUZZ[%d]: Shutting down server socket: %d \n", |
537 | 22.1k | sman->index, |
538 | 22.1k | sman->fd); |
539 | 22.1k | shutdown(sman->fd, SHUT_WR); |
540 | 22.1k | sman->fd_state = FUZZ_SOCK_SHUTDOWN; |
541 | 22.1k | } |
542 | | |
543 | 27.7k | return rc; |
544 | 27.7k | } |
545 | | |
546 | | /** |
547 | | * Wrapper for select() so profiling can track it. |
548 | | */ |
549 | | int fuzz_select(int nfds, |
550 | | fd_set *readfds, |
551 | | fd_set *writefds, |
552 | | fd_set *exceptfds, |
553 | 37.8k | struct timeval *timeout) { |
554 | 37.8k | return select(nfds, readfds, writefds, exceptfds, timeout); |
555 | 37.8k | } |
556 | | |
557 | | /** |
558 | | * Set allowed protocols based on the compile options. |
559 | | * |
560 | | * Note that it can only use ONE of the FUZZ_PROTOCOLS_* defines. |
561 | | */ |
562 | | int fuzz_set_allowed_protocols(FUZZ_DATA *fuzz) |
563 | 191k | { |
564 | 191k | int rc = 0; |
565 | 191k | const char *allowed_protocols = ""; |
566 | | |
567 | | #ifdef FUZZ_PROTOCOLS_ALL |
568 | | /* CURLOPT_PROTOCOLS_STR rejects the complete value if even one requested |
569 | | protocol was compiled out. Derive the generic target's stable safety |
570 | | policy from this libcurl build so optional RTMP and SSH backends cannot |
571 | | prevent every transfer from starting. */ |
572 | | allowed_protocols = legacy_protocol_allowlist::ForCurrentCurl().c_str(); |
573 | | #endif |
574 | | #ifdef FUZZ_PROTOCOLS_DICT |
575 | | allowed_protocols = "dict"; |
576 | | #endif |
577 | | #ifdef FUZZ_PROTOCOLS_FILE |
578 | | allowed_protocols = "file"; |
579 | | #endif |
580 | | #ifdef FUZZ_PROTOCOLS_FTP |
581 | | allowed_protocols = "ftp,ftps"; |
582 | | #endif |
583 | | #ifdef FUZZ_PROTOCOLS_GOPHER |
584 | | allowed_protocols = "gopher,gophers"; |
585 | | #endif |
586 | | #ifdef FUZZ_PROTOCOLS_HTTP |
587 | | allowed_protocols = "http"; |
588 | | #endif |
589 | | #ifdef FUZZ_PROTOCOLS_HTTPS |
590 | | allowed_protocols = "https"; |
591 | | #endif |
592 | | #ifdef FUZZ_PROTOCOLS_IMAP |
593 | | allowed_protocols = "imap,imaps"; |
594 | | #endif |
595 | | #ifdef FUZZ_PROTOCOLS_LDAP |
596 | | allowed_protocols = "ldap,ldaps"; |
597 | | #endif |
598 | | #ifdef FUZZ_PROTOCOLS_MQTT |
599 | | allowed_protocols = "mqtt"; |
600 | | #endif |
601 | | #ifdef FUZZ_PROTOCOLS_POP3 |
602 | | allowed_protocols = "pop3,pop3s"; |
603 | | #endif |
604 | | #ifdef FUZZ_PROTOCOLS_RTMP |
605 | | allowed_protocols = "rtmp,rtmpe,rtmps,rtmpt,rtmpte,rtmpts"; |
606 | | #endif |
607 | | #ifdef FUZZ_PROTOCOLS_RTSP |
608 | | allowed_protocols = "rtsp"; |
609 | | #endif |
610 | | #ifdef FUZZ_PROTOCOLS_SCP |
611 | | allowed_protocols = "scp"; |
612 | | #endif |
613 | | #ifdef FUZZ_PROTOCOLS_SFTP |
614 | | allowed_protocols = "sftp"; |
615 | | #endif |
616 | | #ifdef FUZZ_PROTOCOLS_SMB |
617 | | allowed_protocols = "smb,smbs"; |
618 | | #endif |
619 | | #ifdef FUZZ_PROTOCOLS_SMTP |
620 | | allowed_protocols = "smtp,smtps"; |
621 | | #endif |
622 | | #ifdef FUZZ_PROTOCOLS_TFTP |
623 | | allowed_protocols = "tftp"; |
624 | | #endif |
625 | | #ifdef FUZZ_PROTOCOLS_WS |
626 | | // http is required by websockets |
627 | | allowed_protocols = "http,ws,wss"; |
628 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CONNECT_ONLY, 2L)); |
629 | 20.0k | #endif |
630 | | |
631 | 191k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_PROTOCOLS_STR, allowed_protocols)); |
632 | | |
633 | 191k | EXIT_LABEL: |
634 | | |
635 | 191k | return rc; |
636 | 186k | } fuzz_set_allowed_protocols(fuzz_data*) Line | Count | Source | 563 | 171k | { | 564 | 171k | int rc = 0; | 565 | 171k | const char *allowed_protocols = ""; | 566 | | | 567 | | #ifdef FUZZ_PROTOCOLS_ALL | 568 | | /* CURLOPT_PROTOCOLS_STR rejects the complete value if even one requested | 569 | | protocol was compiled out. Derive the generic target's stable safety | 570 | | policy from this libcurl build so optional RTMP and SSH backends cannot | 571 | | prevent every transfer from starting. */ | 572 | | allowed_protocols = legacy_protocol_allowlist::ForCurrentCurl().c_str(); | 573 | | #endif | 574 | | #ifdef FUZZ_PROTOCOLS_DICT | 575 | | allowed_protocols = "dict"; | 576 | | #endif | 577 | | #ifdef FUZZ_PROTOCOLS_FILE | 578 | | allowed_protocols = "file"; | 579 | | #endif | 580 | | #ifdef FUZZ_PROTOCOLS_FTP | 581 | | allowed_protocols = "ftp,ftps"; | 582 | | #endif | 583 | | #ifdef FUZZ_PROTOCOLS_GOPHER | 584 | | allowed_protocols = "gopher,gophers"; | 585 | | #endif | 586 | | #ifdef FUZZ_PROTOCOLS_HTTP | 587 | | allowed_protocols = "http"; | 588 | | #endif | 589 | | #ifdef FUZZ_PROTOCOLS_HTTPS | 590 | | allowed_protocols = "https"; | 591 | | #endif | 592 | | #ifdef FUZZ_PROTOCOLS_IMAP | 593 | | allowed_protocols = "imap,imaps"; | 594 | | #endif | 595 | 171k | #ifdef FUZZ_PROTOCOLS_LDAP | 596 | 171k | allowed_protocols = "ldap,ldaps"; | 597 | 171k | #endif | 598 | | #ifdef FUZZ_PROTOCOLS_MQTT | 599 | | allowed_protocols = "mqtt"; | 600 | | #endif | 601 | | #ifdef FUZZ_PROTOCOLS_POP3 | 602 | | allowed_protocols = "pop3,pop3s"; | 603 | | #endif | 604 | | #ifdef FUZZ_PROTOCOLS_RTMP | 605 | | allowed_protocols = "rtmp,rtmpe,rtmps,rtmpt,rtmpte,rtmpts"; | 606 | | #endif | 607 | | #ifdef FUZZ_PROTOCOLS_RTSP | 608 | | allowed_protocols = "rtsp"; | 609 | | #endif | 610 | | #ifdef FUZZ_PROTOCOLS_SCP | 611 | | allowed_protocols = "scp"; | 612 | | #endif | 613 | | #ifdef FUZZ_PROTOCOLS_SFTP | 614 | | allowed_protocols = "sftp"; | 615 | | #endif | 616 | | #ifdef FUZZ_PROTOCOLS_SMB | 617 | | allowed_protocols = "smb,smbs"; | 618 | | #endif | 619 | | #ifdef FUZZ_PROTOCOLS_SMTP | 620 | | allowed_protocols = "smtp,smtps"; | 621 | | #endif | 622 | | #ifdef FUZZ_PROTOCOLS_TFTP | 623 | | allowed_protocols = "tftp"; | 624 | | #endif | 625 | | #ifdef FUZZ_PROTOCOLS_WS | 626 | | // http is required by websockets | 627 | | allowed_protocols = "http,ws,wss"; | 628 | | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CONNECT_ONLY, 2L)); | 629 | | #endif | 630 | | | 631 | 171k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_PROTOCOLS_STR, allowed_protocols)); | 632 | | | 633 | 171k | EXIT_LABEL: | 634 | | | 635 | 171k | return rc; | 636 | 166k | } |
fuzz_set_allowed_protocols(fuzz_data*) Line | Count | Source | 563 | 20.0k | { | 564 | 20.0k | int rc = 0; | 565 | 20.0k | const char *allowed_protocols = ""; | 566 | | | 567 | | #ifdef FUZZ_PROTOCOLS_ALL | 568 | | /* CURLOPT_PROTOCOLS_STR rejects the complete value if even one requested | 569 | | protocol was compiled out. Derive the generic target's stable safety | 570 | | policy from this libcurl build so optional RTMP and SSH backends cannot | 571 | | prevent every transfer from starting. */ | 572 | | allowed_protocols = legacy_protocol_allowlist::ForCurrentCurl().c_str(); | 573 | | #endif | 574 | | #ifdef FUZZ_PROTOCOLS_DICT | 575 | | allowed_protocols = "dict"; | 576 | | #endif | 577 | | #ifdef FUZZ_PROTOCOLS_FILE | 578 | | allowed_protocols = "file"; | 579 | | #endif | 580 | | #ifdef FUZZ_PROTOCOLS_FTP | 581 | | allowed_protocols = "ftp,ftps"; | 582 | | #endif | 583 | | #ifdef FUZZ_PROTOCOLS_GOPHER | 584 | | allowed_protocols = "gopher,gophers"; | 585 | | #endif | 586 | | #ifdef FUZZ_PROTOCOLS_HTTP | 587 | | allowed_protocols = "http"; | 588 | | #endif | 589 | | #ifdef FUZZ_PROTOCOLS_HTTPS | 590 | | allowed_protocols = "https"; | 591 | | #endif | 592 | | #ifdef FUZZ_PROTOCOLS_IMAP | 593 | | allowed_protocols = "imap,imaps"; | 594 | | #endif | 595 | | #ifdef FUZZ_PROTOCOLS_LDAP | 596 | | allowed_protocols = "ldap,ldaps"; | 597 | | #endif | 598 | | #ifdef FUZZ_PROTOCOLS_MQTT | 599 | | allowed_protocols = "mqtt"; | 600 | | #endif | 601 | | #ifdef FUZZ_PROTOCOLS_POP3 | 602 | | allowed_protocols = "pop3,pop3s"; | 603 | | #endif | 604 | | #ifdef FUZZ_PROTOCOLS_RTMP | 605 | | allowed_protocols = "rtmp,rtmpe,rtmps,rtmpt,rtmpte,rtmpts"; | 606 | | #endif | 607 | | #ifdef FUZZ_PROTOCOLS_RTSP | 608 | | allowed_protocols = "rtsp"; | 609 | | #endif | 610 | | #ifdef FUZZ_PROTOCOLS_SCP | 611 | | allowed_protocols = "scp"; | 612 | | #endif | 613 | | #ifdef FUZZ_PROTOCOLS_SFTP | 614 | | allowed_protocols = "sftp"; | 615 | | #endif | 616 | | #ifdef FUZZ_PROTOCOLS_SMB | 617 | | allowed_protocols = "smb,smbs"; | 618 | | #endif | 619 | | #ifdef FUZZ_PROTOCOLS_SMTP | 620 | | allowed_protocols = "smtp,smtps"; | 621 | | #endif | 622 | | #ifdef FUZZ_PROTOCOLS_TFTP | 623 | | allowed_protocols = "tftp"; | 624 | | #endif | 625 | 20.0k | #ifdef FUZZ_PROTOCOLS_WS | 626 | | // http is required by websockets | 627 | 20.0k | allowed_protocols = "http,ws,wss"; | 628 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CONNECT_ONLY, 2L)); | 629 | 20.0k | #endif | 630 | | | 631 | 20.0k | FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_PROTOCOLS_STR, allowed_protocols)); | 632 | | | 633 | 20.0k | EXIT_LABEL: | 634 | | | 635 | 20.0k | return rc; | 636 | 20.0k | } |
|