Skip to content

Commit cdfb8e7

Browse files
tests: Add fuzzing harness for HTTPRequest, libevent's evhttp and related functions
1 parent 299544f commit cdfb8e7

File tree

4 files changed

+67
-4
lines changed

4 files changed

+67
-4
lines changed

src/Makefile.test.include

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ FUZZ_TARGETS = \
3838
test/fuzz/flatfile \
3939
test/fuzz/float \
4040
test/fuzz/hex \
41+
test/fuzz/http_request \
4142
test/fuzz/integer \
4243
test/fuzz/inv_deserialize \
4344
test/fuzz/key \
@@ -489,6 +490,12 @@ test_fuzz_hex_LDADD = $(FUZZ_SUITE_LD_COMMON)
489490
test_fuzz_hex_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
490491
test_fuzz_hex_SOURCES = test/fuzz/hex.cpp
491492

493+
test_fuzz_http_request_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
494+
test_fuzz_http_request_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
495+
test_fuzz_http_request_LDADD = $(FUZZ_SUITE_LD_COMMON)
496+
test_fuzz_http_request_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
497+
test_fuzz_http_request_SOURCES = test/fuzz/http_request.cpp
498+
492499
test_fuzz_integer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
493500
test_fuzz_integer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
494501
test_fuzz_integer_LDADD = $(FUZZ_SUITE_LD_COMMON)

src/httpserver.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ static bool InitHTTPAllowList()
189189
}
190190

191191
/** HTTP request method as string - use for logging only */
192-
static std::string RequestMethodString(HTTPRequest::RequestMethod m)
192+
std::string RequestMethodString(HTTPRequest::RequestMethod m)
193193
{
194194
switch (m) {
195195
case HTTPRequest::GET:
@@ -510,10 +510,10 @@ void HTTPEvent::trigger(struct timeval* tv)
510510
else
511511
evtimer_add(ev, tv); // trigger after timeval passed
512512
}
513-
HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
514-
replySent(false)
513+
HTTPRequest::HTTPRequest(struct evhttp_request* _req, bool _replySent) : req(_req), replySent(_replySent)
515514
{
516515
}
516+
517517
HTTPRequest::~HTTPRequest()
518518
{
519519
if (!replySent) {

src/httpserver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class HTTPRequest
6060
bool replySent;
6161

6262
public:
63-
explicit HTTPRequest(struct evhttp_request* req);
63+
explicit HTTPRequest(struct evhttp_request* req, bool replySent = false);
6464
~HTTPRequest();
6565

6666
enum RequestMethod {

src/test/fuzz/http_request.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2020 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <httpserver.h>
6+
#include <netaddress.h>
7+
#include <test/fuzz/FuzzedDataProvider.h>
8+
#include <test/fuzz/fuzz.h>
9+
#include <test/fuzz/util.h>
10+
11+
#include <event2/buffer.h>
12+
#include <event2/http.h>
13+
#include <event2/http_struct.h>
14+
15+
#include <cassert>
16+
#include <cstdint>
17+
#include <string>
18+
#include <vector>
19+
20+
extern "C" int evhttp_parse_firstline_(struct evhttp_request*, struct evbuffer*);
21+
extern "C" int evhttp_parse_headers_(struct evhttp_request*, struct evbuffer*);
22+
std::string RequestMethodString(HTTPRequest::RequestMethod m);
23+
24+
void test_one_input(const std::vector<uint8_t>& buffer)
25+
{
26+
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
27+
evhttp_request* evreq = evhttp_request_new(nullptr, nullptr);
28+
assert(evreq != nullptr);
29+
evreq->kind = EVHTTP_REQUEST;
30+
evbuffer* evbuf = evbuffer_new();
31+
assert(evbuf != nullptr);
32+
const std::vector<uint8_t> http_buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, 4096);
33+
evbuffer_add(evbuf, http_buffer.data(), http_buffer.size());
34+
if (evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) {
35+
evbuffer_free(evbuf);
36+
evhttp_request_free(evreq);
37+
return;
38+
}
39+
40+
HTTPRequest http_request{evreq, true};
41+
const HTTPRequest::RequestMethod request_method = http_request.GetRequestMethod();
42+
(void)RequestMethodString(request_method);
43+
(void)http_request.GetURI();
44+
(void)http_request.GetHeader("Host");
45+
const std::string header = fuzzed_data_provider.ConsumeRandomLengthString(16);
46+
(void)http_request.GetHeader(header);
47+
(void)http_request.WriteHeader(header, fuzzed_data_provider.ConsumeRandomLengthString(16));
48+
(void)http_request.GetHeader(header);
49+
const std::string body = http_request.ReadBody();
50+
assert(body.empty());
51+
const CService service = http_request.GetPeer();
52+
assert(service.ToString() == "[::]:0");
53+
54+
evbuffer_free(evbuf);
55+
evhttp_request_free(evreq);
56+
}

0 commit comments

Comments
 (0)