From bf6c15e1e00571c199f333d2a27c07dc1b912ec3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 13 Oct 2016 11:58:43 +0200 Subject: [PATCH] add curl fuzzer (#18) --- curl/Dockerfile | 23 +++++++++ curl/Jenkinsfile | 22 +++++++++ curl/build.sh | 22 +++++++++ curl/fuzzer.cc | 117 ++++++++++++++++++++++++++++++++++++++++++++++ curl/http.dict | 41 ++++++++++++++++ curl/http.options | 3 ++ 6 files changed, 228 insertions(+) create mode 100644 curl/Dockerfile create mode 100644 curl/Jenkinsfile create mode 100755 curl/build.sh create mode 100644 curl/fuzzer.cc create mode 100644 curl/http.dict create mode 100644 curl/http.options diff --git a/curl/Dockerfile b/curl/Dockerfile new file mode 100644 index 000000000..cb9ebd57a --- /dev/null +++ b/curl/Dockerfile @@ -0,0 +1,23 @@ +# 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. +# +################################################################################ + +FROM ossfuzz/base-libfuzzer +MAINTAINER dvyukov@google.com +RUN apt-get install -y make autoconf automake libtool libssl-dev zlib1g-dev + +COPY build.sh fuzzer.cc /src/ + +ENV GIT_URL "" diff --git a/curl/Jenkinsfile b/curl/Jenkinsfile new file mode 100644 index 000000000..ce011c57e --- /dev/null +++ b/curl/Jenkinsfile @@ -0,0 +1,22 @@ +// 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. +// +//////////////////////////////////////////////////////////////////////////////// + +def libfuzzerBuild = fileLoader.fromGit('infra/libfuzzer-pipeline.groovy', + 'https://github.com/google/oss-fuzz.git') + +libfuzzerBuild { + git = "https://github.com/curl/curl.git" +} diff --git a/curl/build.sh b/curl/build.sh new file mode 100755 index 000000000..476322b57 --- /dev/null +++ b/curl/build.sh @@ -0,0 +1,22 @@ +#!/bin/bash -eu +# 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. +# +################################################################################ + +cd /src/curl +./buildconf +./configure --disable-shared --enable-debug --enable-maintainer-mode --disable-symbol-hiding --disable-threaded-resolver --enable-ipv6 --with-random=/dev/null +make -j4 +$CXX $CXXFLAGS /src/fuzzer.cc -Iinclude lib/.libs/libcurl.a -lssl -lcrypto -lz /work/libfuzzer/*.o -o /out/curl_fuzzer $LDFLAGS diff --git a/curl/fuzzer.cc b/curl/fuzzer.cc new file mode 100644 index 000000000..b292e346e --- /dev/null +++ b/curl/fuzzer.cc @@ -0,0 +1,117 @@ +/* +# 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 bool wrote = false; + +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 = true; + buf[0] = 'a'; + return 1; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + cur_data = Data; + cur_size = Size; + wrote = false; + 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/"); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 0L); +#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; +} diff --git a/curl/http.dict b/curl/http.dict new file mode 100644 index 000000000..57b7b4372 --- /dev/null +++ b/curl/http.dict @@ -0,0 +1,41 @@ +"\x0a\x0d" +"HTTP/1.0" +"HTTP/1.1" +"100" +"200" +"301" +"400" +"Server:" +"Last-Modified:" +"Content-Type:" +"text/html" +"charset=UTF-8" +"Accept-Ranges:" +"bytes" +"Content-Length:" +"Transfer-Encoding:" +"compress" +"exi" +"gzip" +"identity" +"pack200-gzip" +"br" +"deflate" +"bzip2" +"lzma" +"xz" +"Content-Encoding:" +"chunked" +"Connection:" +"close" +"Date:" +"Expires:" +"Fri, 31 Dec 1999 23:59:59 GMT" +"Cache-Control:" +"no-cache" +"no-store" +"must-revalidate" +"Pragma:" +"no-cache" +"Host:" + diff --git a/curl/http.options b/curl/http.options new file mode 100644 index 000000000..e8e815189 --- /dev/null +++ b/curl/http.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 1000 +dict = http.dict