diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt new file mode 100644 index 000000000..aefedf26f --- /dev/null +++ b/tests/fuzz/CMakeLists.txt @@ -0,0 +1 @@ +# FIXME, probably adapt from file in ../unit diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am new file mode 100644 index 000000000..487deff41 --- /dev/null +++ b/tests/fuzz/Makefile.am @@ -0,0 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + + +# FIXME, probably adapt from file in ../unit diff --git a/tests/fuzz/Makefile.inc b/tests/fuzz/Makefile.inc new file mode 100644 index 000000000..fa4ae1c7d --- /dev/null +++ b/tests/fuzz/Makefile.inc @@ -0,0 +1,19 @@ +FUZZER_HTTP11 = curl_fuzzer.c +FUZZER_HTTP11_CPPFLAGS = $(AM_CPPFLAGS) + + +FUZZER_FTP = curl_fuzzer.c +FUZZER_FTP_CPPFLAGS = -DFUZZER_FTP $(AM_CPPFLAGS) + +FUZZER_IMAP = curl_fuzzer.c +FUZZER_IMAP_CPPFLAGS = -DFUZZER_IMAP $(AM_CPPFLAGS) + +FUZZER_POP3 = curl_fuzzer.c +FUZZER_POP3_CPPFLAGS = -DFUZZER_POP3 $(AM_CPPFLAGS) + +FUZZER_HTTP_UPLOAD = curl_fuzzer.c +FUZZER_HTTP_UPLOAD_CPPFLAGS = -DFUZZER_HTTP_UPLOAD $(AM_CPPFLAGS) + + +FUZZER_HTTP2 = curl_fuzzer.c +FUZZER_HTTP2_CPPFLAGS = -DFUZZER_HTTP2 $(AM_CPPFLAGS) diff --git a/tests/fuzz/README b/tests/fuzz/README new file mode 100644 index 000000000..106d1098a --- /dev/null +++ b/tests/fuzz/README @@ -0,0 +1,10 @@ +Fuzz tests +========== + +The goal is to add tests for *ALL* protocols supported in libcurl. +We will need some additional patches in the future, to increase coverage. + +Building the fuzz target +======================== + +FIXME fill out once the makefiles are in order. \ No newline at end of file diff --git a/tests/fuzz/curl_fuzzer.c b/tests/fuzz/curl_fuzzer.c new file mode 100644 index 000000000..2c3d57991 --- /dev/null +++ b/tests/fuzz/curl_fuzzer.c @@ -0,0 +1,128 @@ +/* +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static const void *cur_data; +static int cur_size = -1; +static int server_fd = -1; +static int client_fd = -1; +static int wrote = 0; + +static void fail(const char *why) { + perror(why); + exit(1); +} + +static curl_socket_t open_sock(void *ctx, curlsocktype purpose, + struct curl_sockaddr *address) { + if(cur_size == -1) { + fail("not fuzzing"); + } + if(server_fd != -1 || client_fd != -1) { + fail("already connected"); + } + int fds[2]; + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { + fail("socketpair"); + } + server_fd = fds[0]; + client_fd = fds[1]; + if(write(server_fd, cur_data, cur_size) != cur_size) { + fail("write"); + } + if(shutdown(server_fd, SHUT_WR)) { + fail("shutdown"); + } + return client_fd; +} + +static int set_opt(void *ctx, curl_socket_t curlfd, curlsocktype purpose) { + return CURL_SOCKOPT_ALREADY_CONNECTED; +} + +static size_t write_callback(char *ptr, size_t size, size_t n, void *ctx) { + return size * n; +} + +static size_t read_callback(char *buf, size_t size, size_t n, void *ctx) { + if(wrote || size * n == 0) { + return 0; + } + wrote = 1; + buf[0] = 'a'; + return 1; +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + cur_data = Data; + cur_size = Size; + wrote = 0; + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, open_sock); + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, set_opt); +#if defined(FUZZER_FTP) + curl_easy_setopt(curl, CURLOPT_URL, "ftp://user@localhost/file.txt"); +#elif defined(FUZZER_IMAP) + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + curl_easy_setopt(curl, CURLOPT_URL, "imap://localhost"); +#elif defined(FUZZER_POP3) + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + curl_easy_setopt(curl, CURLOPT_URL, "pop3://localhost"); +#elif defined(FUZZER_HTTP_UPLOAD) + curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/"); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); +#elif defined(FUZZER_HTTP2) + curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/"); + /* use non-TLS HTTP/2 without HTTP/1.1 Upgrade: */ + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); +#else + curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/"); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); +#endif + curl_easy_perform(curl); + curl_easy_cleanup(curl); + close(server_fd); + close(client_fd); + server_fd = -1; + client_fd = -1; + cur_data = NULL; + cur_size = -1; + return 0; +}