mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 15:48:49 -05:00
ossfuzz: add some more handled CURL options
Add support for HEADER, COOKIE, RANGE, CUSTOMREQUEST, MAIL_RECIPIENT, MAIL_FROM and uploading data.
This commit is contained in:
parent
1ae2704d6e
commit
261da2a668
@ -50,7 +50,7 @@ LDADD = $(top_builddir)/lib/libcurl.la \
|
||||
include Makefile.inc
|
||||
|
||||
checksrc:
|
||||
@PERL@ $(top_srcdir)/lib/checksrc.pl $(srcdir)/*.c
|
||||
@PERL@ $(top_srcdir)/lib/checksrc.pl $(srcdir)/*.cc
|
||||
|
||||
noinst_PROGRAMS = $(FUZZPROGS)
|
||||
noinst_LIBRARIES = $(FUZZLIBS)
|
||||
|
BIN
tests/fuzz/curl_fuzz_data/test10
Normal file
BIN
tests/fuzz/curl_fuzz_data/test10
Normal file
Binary file not shown.
BIN
tests/fuzz/curl_fuzz_data/test12
Normal file
BIN
tests/fuzz/curl_fuzz_data/test12
Normal file
Binary file not shown.
BIN
tests/fuzz/curl_fuzz_data/test13
Normal file
BIN
tests/fuzz/curl_fuzz_data/test13
Normal file
Binary file not shown.
BIN
tests/fuzz/curl_fuzz_data/test4
Normal file
BIN
tests/fuzz/curl_fuzz_data/test4
Normal file
Binary file not shown.
BIN
tests/fuzz/curl_fuzz_data/test5
Normal file
BIN
tests/fuzz/curl_fuzz_data/test5
Normal file
Binary file not shown.
BIN
tests/fuzz/curl_fuzz_data/test6
Normal file
BIN
tests/fuzz/curl_fuzz_data/test6
Normal file
Binary file not shown.
BIN
tests/fuzz/curl_fuzz_data/test900
Normal file
BIN
tests/fuzz/curl_fuzz_data/test900
Normal file
Binary file not shown.
@ -63,6 +63,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
}
|
||||
|
||||
/* Do the CURL stuff! */
|
||||
if(fuzz.header_list != NULL) {
|
||||
curl_easy_setopt(fuzz.easy, CURLOPT_HTTPHEADER, fuzz.header_list);
|
||||
}
|
||||
|
||||
if(fuzz.mail_recipients_list != NULL) {
|
||||
curl_easy_setopt(fuzz.easy, CURLOPT_MAIL_RCPT, fuzz.mail_recipients_list);
|
||||
}
|
||||
|
||||
curl_easy_perform(fuzz.easy);
|
||||
|
||||
EXIT_LABEL:
|
||||
@ -122,8 +130,14 @@ int fuzz_initialize_fuzz_data(FUZZ_DATA *fuzz,
|
||||
CURLOPT_SOCKOPTFUNCTION,
|
||||
fuzz_sockopt_callback));
|
||||
|
||||
/* Can enable verbose mode */
|
||||
/* FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_VERBOSE, 1L)); */
|
||||
/* Set the standard read function callback. */
|
||||
FTRY(curl_easy_setopt(fuzz->easy,
|
||||
CURLOPT_READFUNCTION,
|
||||
fuzz_read_callback));
|
||||
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_READDATA, fuzz));
|
||||
|
||||
/* Can enable verbose mode by changing 0L to 1L */
|
||||
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_VERBOSE, 0L));
|
||||
|
||||
/* Set up the state parser */
|
||||
fuzz->state.data = data;
|
||||
@ -143,6 +157,20 @@ void fuzz_terminate_fuzz_data(FUZZ_DATA *fuzz)
|
||||
fuzz_free((void **)&fuzz->username);
|
||||
fuzz_free((void **)&fuzz->password);
|
||||
fuzz_free((void **)&fuzz->postfields);
|
||||
fuzz_free((void **)&fuzz->cookie);
|
||||
fuzz_free((void **)&fuzz->range);
|
||||
fuzz_free((void **)&fuzz->customrequest);
|
||||
fuzz_free((void **)&fuzz->mail_from);
|
||||
|
||||
if(fuzz->header_list != NULL) {
|
||||
curl_slist_free_all(fuzz->header_list);
|
||||
fuzz->header_list = NULL;
|
||||
}
|
||||
|
||||
if(fuzz->mail_recipients_list != NULL) {
|
||||
curl_slist_free_all(fuzz->mail_recipients_list);
|
||||
fuzz->mail_recipients_list = NULL;
|
||||
}
|
||||
|
||||
if(fuzz->easy != NULL) {
|
||||
curl_easy_cleanup(fuzz->easy);
|
||||
@ -216,6 +244,31 @@ static int fuzz_sockopt_callback(void *ptr,
|
||||
return CURL_SOCKOPT_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for doing data uploads.
|
||||
*/
|
||||
static size_t fuzz_read_callback(char *buffer,
|
||||
size_t size,
|
||||
size_t nitems,
|
||||
void *ptr)
|
||||
{
|
||||
FUZZ_DATA *fuzz = (FUZZ_DATA *)ptr;
|
||||
curl_off_t nread;
|
||||
|
||||
/* If no upload data has been specified, then return an error code. */
|
||||
if(fuzz->upload1_data_len == 0) {
|
||||
/* No data to upload */
|
||||
return CURL_READFUNC_ABORT;
|
||||
}
|
||||
|
||||
/* Send the upload data. */
|
||||
memcpy(buffer,
|
||||
fuzz->upload1_data,
|
||||
fuzz->upload1_data_len);
|
||||
|
||||
return fuzz->upload1_data_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* TLV access function - gets the first TLV from a data stream.
|
||||
*/
|
||||
@ -278,14 +331,9 @@ int fuzz_get_tlv_comn(FUZZ_DATA *fuzz,
|
||||
int fuzz_parse_tlv(FUZZ_DATA *fuzz, TLV *tlv)
|
||||
{
|
||||
int rc;
|
||||
char *tmp;
|
||||
|
||||
switch(tlv->type) {
|
||||
case TLV_TYPE_URL:
|
||||
FCHECK(fuzz->url == NULL);
|
||||
fuzz->url = fuzz_tlv_to_string(tlv);
|
||||
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_URL, fuzz->url));
|
||||
break;
|
||||
|
||||
case TLV_TYPE_RESPONSE1:
|
||||
/* The pointers in the TLV will always be valid as long as the fuzz data
|
||||
is in scope, which is the entirety of this file. */
|
||||
@ -293,24 +341,42 @@ int fuzz_parse_tlv(FUZZ_DATA *fuzz, TLV *tlv)
|
||||
fuzz->rsp1_data_len = tlv->length;
|
||||
break;
|
||||
|
||||
case TLV_TYPE_USERNAME:
|
||||
FCHECK(fuzz->username == NULL);
|
||||
fuzz->username = fuzz_tlv_to_string(tlv);
|
||||
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_USERNAME, fuzz->username));
|
||||
case TLV_TYPE_UPLOAD1:
|
||||
/* The pointers in the TLV will always be valid as long as the fuzz data
|
||||
is in scope, which is the entirety of this file. */
|
||||
fuzz->upload1_data = tlv->value;
|
||||
fuzz->upload1_data_len = tlv->length;
|
||||
|
||||
curl_easy_setopt(fuzz->easy, CURLOPT_UPLOAD, 1L);
|
||||
curl_easy_setopt(fuzz->easy,
|
||||
CURLOPT_INFILESIZE_LARGE,
|
||||
(curl_off_t)fuzz->upload1_data_len);
|
||||
break;
|
||||
|
||||
case TLV_TYPE_PASSWORD:
|
||||
FCHECK(fuzz->password == NULL);
|
||||
fuzz->password = fuzz_tlv_to_string(tlv);
|
||||
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_PASSWORD, fuzz->password));
|
||||
case TLV_TYPE_HEADER:
|
||||
tmp = fuzz_tlv_to_string(tlv);
|
||||
fuzz->header_list = curl_slist_append(fuzz->header_list, tmp);
|
||||
fuzz_free((void **)&tmp);
|
||||
break;
|
||||
|
||||
case TLV_TYPE_POSTFIELDS:
|
||||
FCHECK(fuzz->postfields == NULL);
|
||||
fuzz->postfields = fuzz_tlv_to_string(tlv);
|
||||
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_POSTFIELDS, fuzz->postfields));
|
||||
case TLV_TYPE_MAIL_RECIPIENT:
|
||||
tmp = fuzz_tlv_to_string(tlv);
|
||||
fuzz->mail_recipients_list =
|
||||
curl_slist_append(fuzz->mail_recipients_list, tmp);
|
||||
fuzz_free((void **)&tmp);
|
||||
break;
|
||||
|
||||
/* Define a set of singleton TLVs - they can only have their value set once
|
||||
and all follow the same pattern. */
|
||||
FSINGLETONTLV(TLV_TYPE_URL, url, CURLOPT_URL);
|
||||
FSINGLETONTLV(TLV_TYPE_USERNAME, username, CURLOPT_USERNAME);
|
||||
FSINGLETONTLV(TLV_TYPE_PASSWORD, password, CURLOPT_PASSWORD);
|
||||
FSINGLETONTLV(TLV_TYPE_POSTFIELDS, postfields, CURLOPT_POSTFIELDS);
|
||||
FSINGLETONTLV(TLV_TYPE_COOKIE, cookie, CURLOPT_COOKIE);
|
||||
FSINGLETONTLV(TLV_TYPE_RANGE, range, CURLOPT_RANGE);
|
||||
FSINGLETONTLV(TLV_TYPE_CUSTOMREQUEST, customrequest, CURLOPT_CUSTOMREQUEST);
|
||||
FSINGLETONTLV(TLV_TYPE_MAIL_FROM, mail_from, CURLOPT_MAIL_FROM);
|
||||
|
||||
default:
|
||||
/* The fuzzer generates lots of unknown TLVs, so don't do anything if
|
||||
the TLV isn't known. */
|
||||
|
@ -31,6 +31,13 @@
|
||||
#define TLV_TYPE_USERNAME 3
|
||||
#define TLV_TYPE_PASSWORD 4
|
||||
#define TLV_TYPE_POSTFIELDS 5
|
||||
#define TLV_TYPE_HEADER 6
|
||||
#define TLV_TYPE_COOKIE 7
|
||||
#define TLV_TYPE_UPLOAD1 8
|
||||
#define TLV_TYPE_RANGE 9
|
||||
#define TLV_TYPE_CUSTOMREQUEST 10
|
||||
#define TLV_TYPE_MAIL_RECIPIENT 11
|
||||
#define TLV_TYPE_MAIL_FROM 12
|
||||
|
||||
/**
|
||||
* TLV function return codes.
|
||||
@ -91,19 +98,29 @@ typedef struct fuzz_data
|
||||
/* Parser state */
|
||||
FUZZ_PARSE_STATE state;
|
||||
|
||||
/* Current URL. */
|
||||
char *url;
|
||||
|
||||
/* Response data and length */
|
||||
const uint8_t *rsp1_data;
|
||||
size_t rsp1_data_len;
|
||||
|
||||
/* Username and password */
|
||||
/* Upload data and length; */
|
||||
const uint8_t *upload1_data;
|
||||
size_t upload1_data_len;
|
||||
|
||||
/* Singleton string fields. */
|
||||
char *url;
|
||||
char *username;
|
||||
char *password;
|
||||
|
||||
/* Postfields */
|
||||
char *postfields;
|
||||
char *cookie;
|
||||
char *range;
|
||||
char *customrequest;
|
||||
char *mail_from;
|
||||
|
||||
/* List of headers */
|
||||
struct curl_slist *header_list;
|
||||
|
||||
/* List of mail recipients */
|
||||
struct curl_slist *mail_recipients_list;
|
||||
|
||||
} FUZZ_DATA;
|
||||
|
||||
@ -121,6 +138,10 @@ static curl_socket_t fuzz_open_socket(void *ptr,
|
||||
static int fuzz_sockopt_callback(void *ptr,
|
||||
curl_socket_t curlfd,
|
||||
curlsocktype purpose);
|
||||
static size_t fuzz_read_callback(char *buffer,
|
||||
size_t size,
|
||||
size_t nitems,
|
||||
void *ptr);
|
||||
int fuzz_get_first_tlv(FUZZ_DATA *fuzz, TLV *tlv);
|
||||
int fuzz_get_next_tlv(FUZZ_DATA *fuzz, TLV *tlv);
|
||||
int fuzz_get_tlv_comn(FUZZ_DATA *fuzz, TLV *tlv);
|
||||
@ -146,3 +167,10 @@ char *fuzz_tlv_to_string(TLV *tlv);
|
||||
goto EXIT_LABEL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FSINGLETONTLV(TLVNAME, FIELDNAME, OPTNAME) \
|
||||
case TLVNAME: \
|
||||
FCHECK(fuzz->FIELDNAME == NULL); \
|
||||
fuzz->FIELDNAME = fuzz_tlv_to_string(tlv); \
|
||||
FTRY(curl_easy_setopt(fuzz->easy, OPTNAME, fuzz->FIELDNAME)); \
|
||||
break
|
@ -36,6 +36,27 @@ def generate_corpus(options):
|
||||
enc.maybe_write_string(enc.TYPE_USERNAME, options.username)
|
||||
enc.maybe_write_string(enc.TYPE_PASSWORD, options.password)
|
||||
enc.maybe_write_string(enc.TYPE_POSTFIELDS, options.postfields)
|
||||
enc.maybe_write_string(enc.TYPE_COOKIE, options.cookie)
|
||||
enc.maybe_write_string(enc.TYPE_RANGE, options.range)
|
||||
enc.maybe_write_string(enc.TYPE_CUSTOMREQUEST, options.customrequest)
|
||||
enc.maybe_write_string(enc.TYPE_MAIL_FROM, options.mailfrom)
|
||||
|
||||
# Write the first upload to the file.
|
||||
if options.upload1:
|
||||
enc.write_bytes(enc.TYPE_UPLOAD1, options.upload1.encode("utf-8"))
|
||||
elif options.upload1file:
|
||||
with open(options.upload1file, "rb") as g:
|
||||
enc.write_bytes(enc.TYPE_UPLOAD1, g.read())
|
||||
|
||||
# Write an array of headers to the file.
|
||||
if options.header:
|
||||
for header in options.header:
|
||||
enc.write_string(enc.TYPE_HEADER, header)
|
||||
|
||||
# Write an array of headers to the file.
|
||||
if options.mailrecipient:
|
||||
for mailrecipient in options.mailrecipient:
|
||||
enc.write_string(enc.TYPE_MAIL_RECIPIENT, mailrecipient)
|
||||
|
||||
return ScriptRC.SUCCESS
|
||||
|
||||
@ -46,6 +67,13 @@ class TLVEncoder(object):
|
||||
TYPE_USERNAME = 3
|
||||
TYPE_PASSWORD = 4
|
||||
TYPE_POSTFIELDS = 5
|
||||
TYPE_HEADER = 6
|
||||
TYPE_COOKIE = 7
|
||||
TYPE_UPLOAD1 = 8
|
||||
TYPE_RANGE = 9
|
||||
TYPE_CUSTOMREQUEST = 10
|
||||
TYPE_MAIL_RECIPIENT = 11
|
||||
TYPE_MAIL_FROM = 12
|
||||
|
||||
def __init__(self, output):
|
||||
self.output = output
|
||||
@ -58,7 +86,7 @@ class TLVEncoder(object):
|
||||
self.write_tlv(tlv_type, len(bytedata), bytedata)
|
||||
|
||||
def maybe_write_string(self, tlv_type, wstring):
|
||||
if wstring:
|
||||
if wstring is not None:
|
||||
self.write_string(tlv_type, wstring)
|
||||
|
||||
def write_tlv(self, tlv_type, tlv_length, tlv_data=None):
|
||||
@ -84,12 +112,22 @@ def get_options():
|
||||
parser.add_argument("--username")
|
||||
parser.add_argument("--password")
|
||||
parser.add_argument("--postfields")
|
||||
parser.add_argument("--header", action="append")
|
||||
parser.add_argument("--cookie")
|
||||
parser.add_argument("--range")
|
||||
parser.add_argument("--customrequest")
|
||||
parser.add_argument("--mailfrom")
|
||||
parser.add_argument("--mailrecipient", action="append")
|
||||
|
||||
rsp1 = parser.add_mutually_exclusive_group(required=True)
|
||||
rsp1.add_argument("--rsp1")
|
||||
rsp1.add_argument("--rsp1file")
|
||||
rsp1.add_argument("--rsp1test", type=int)
|
||||
|
||||
upload1 = parser.add_mutually_exclusive_group()
|
||||
upload1.add_argument("--upload1")
|
||||
upload1.add_argument("--upload1file")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user