From cdfb8e7afa7648405dd6b957f47b1c7ab566a076 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Tue, 17 Mar 2020 02:03:16 +0000 Subject: tests: Add fuzzing harness for HTTPRequest, libevent's evhttp and related functions --- src/Makefile.test.include | 7 ++++++ src/httpserver.cpp | 6 ++--- src/httpserver.h | 2 +- src/test/fuzz/http_request.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/test/fuzz/http_request.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c3021743f4..cbce32429d 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -38,6 +38,7 @@ FUZZ_TARGETS = \ test/fuzz/flatfile \ test/fuzz/float \ test/fuzz/hex \ + test/fuzz/http_request \ test/fuzz/integer \ test/fuzz/inv_deserialize \ test/fuzz/key \ @@ -489,6 +490,12 @@ test_fuzz_hex_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_hex_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_hex_SOURCES = test/fuzz/hex.cpp +test_fuzz_http_request_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_http_request_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_http_request_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_http_request_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_http_request_SOURCES = test/fuzz/http_request.cpp + test_fuzz_integer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_integer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_integer_LDADD = $(FUZZ_SUITE_LD_COMMON) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 11d73b7c9a..7282b517f4 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -189,7 +189,7 @@ static bool InitHTTPAllowList() } /** HTTP request method as string - use for logging only */ -static std::string RequestMethodString(HTTPRequest::RequestMethod m) +std::string RequestMethodString(HTTPRequest::RequestMethod m) { switch (m) { case HTTPRequest::GET: @@ -510,10 +510,10 @@ void HTTPEvent::trigger(struct timeval* tv) else evtimer_add(ev, tv); // trigger after timeval passed } -HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req), - replySent(false) +HTTPRequest::HTTPRequest(struct evhttp_request* _req, bool _replySent) : req(_req), replySent(_replySent) { } + HTTPRequest::~HTTPRequest() { if (!replySent) { diff --git a/src/httpserver.h b/src/httpserver.h index 46820e6aee..c25ea7a8fb 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -60,7 +60,7 @@ private: bool replySent; public: - explicit HTTPRequest(struct evhttp_request* req); + explicit HTTPRequest(struct evhttp_request* req, bool replySent = false); ~HTTPRequest(); enum RequestMethod { diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp new file mode 100644 index 0000000000..4104c5574d --- /dev/null +++ b/src/test/fuzz/http_request.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +extern "C" int evhttp_parse_firstline_(struct evhttp_request*, struct evbuffer*); +extern "C" int evhttp_parse_headers_(struct evhttp_request*, struct evbuffer*); +std::string RequestMethodString(HTTPRequest::RequestMethod m); + +void test_one_input(const std::vector& buffer) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + evhttp_request* evreq = evhttp_request_new(nullptr, nullptr); + assert(evreq != nullptr); + evreq->kind = EVHTTP_REQUEST; + evbuffer* evbuf = evbuffer_new(); + assert(evbuf != nullptr); + const std::vector http_buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, 4096); + evbuffer_add(evbuf, http_buffer.data(), http_buffer.size()); + if (evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) { + evbuffer_free(evbuf); + evhttp_request_free(evreq); + return; + } + + HTTPRequest http_request{evreq, true}; + const HTTPRequest::RequestMethod request_method = http_request.GetRequestMethod(); + (void)RequestMethodString(request_method); + (void)http_request.GetURI(); + (void)http_request.GetHeader("Host"); + const std::string header = fuzzed_data_provider.ConsumeRandomLengthString(16); + (void)http_request.GetHeader(header); + (void)http_request.WriteHeader(header, fuzzed_data_provider.ConsumeRandomLengthString(16)); + (void)http_request.GetHeader(header); + const std::string body = http_request.ReadBody(); + assert(body.empty()); + const CService service = http_request.GetPeer(); + assert(service.ToString() == "[::]:0"); + + evbuffer_free(evbuf); + evhttp_request_free(evreq); +} -- cgit v1.2.3