merge bitcoin#18363: Add fuzzing harness for HTTPRequest, libevent's evhttp and related functions

This commit is contained in:
Kittywhiskers Van Gogh 2022-06-14 12:00:15 +05:30
parent 01367c944e
commit 93d3c26063
4 changed files with 67 additions and 4 deletions

View File

@ -48,6 +48,7 @@ FUZZ_TARGETS = \
test/fuzz/flatfile \ test/fuzz/flatfile \
test/fuzz/float \ test/fuzz/float \
test/fuzz/hex \ test/fuzz/hex \
test/fuzz/http_request \
test/fuzz/integer \ test/fuzz/integer \
test/fuzz/inv_deserialize \ test/fuzz/inv_deserialize \
test/fuzz/key \ test/fuzz/key \
@ -559,6 +560,12 @@ test_fuzz_hex_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_hex_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(LDFLAGS_WRAP_EXCEPTIONS) test_fuzz_hex_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(LDFLAGS_WRAP_EXCEPTIONS)
test_fuzz_hex_SOURCES = $(FUZZ_SUITE) test/fuzz/hex.cpp test_fuzz_hex_SOURCES = $(FUZZ_SUITE) 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) $(LDFLAGS_WRAP_EXCEPTIONS)
test_fuzz_http_request_SOURCES = $(FUZZ_SUITE) test/fuzz/http_request.cpp
test_fuzz_integer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_integer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_integer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_integer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_integer_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_integer_LDADD = $(FUZZ_SUITE_LD_COMMON)

View File

@ -188,7 +188,7 @@ static bool InitHTTPAllowList()
} }
/** HTTP request method as string - use for logging only */ /** HTTP request method as string - use for logging only */
static std::string RequestMethodString(HTTPRequest::RequestMethod m) std::string RequestMethodString(HTTPRequest::RequestMethod m)
{ {
switch (m) { switch (m) {
case HTTPRequest::GET: case HTTPRequest::GET:
@ -513,10 +513,10 @@ void HTTPEvent::trigger(struct timeval* tv)
else else
evtimer_add(ev, tv); // trigger after timeval passed evtimer_add(ev, tv); // trigger after timeval passed
} }
HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req), HTTPRequest::HTTPRequest(struct evhttp_request* _req, bool _replySent) : req(_req), replySent(_replySent)
replySent(false)
{ {
} }
HTTPRequest::~HTTPRequest() HTTPRequest::~HTTPRequest()
{ {
if (!replySent) { if (!replySent) {

View File

@ -60,7 +60,7 @@ private:
bool replySent; bool replySent;
public: public:
explicit HTTPRequest(struct evhttp_request* req); explicit HTTPRequest(struct evhttp_request* req, bool replySent = false);
~HTTPRequest(); ~HTTPRequest();
enum RequestMethod { enum RequestMethod {

View File

@ -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 <httpserver.h>
#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <event2/buffer.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <cassert>
#include <cstdint>
#include <string>
#include <vector>
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<uint8_t>& 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<uint8_t> 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);
}