fuzz: switch http_libevent::HTTPRequest to http_bitcoin::HTTPRequest

This commit is contained in:
Matthew Zipkin 2025-03-18 13:10:53 -04:00
parent be97857d14
commit 7856f20fec
No known key found for this signature in database
GPG key ID: E7E2984B6289C93A

View file

@ -10,48 +10,35 @@
#include <util/signalinterrupt.h> #include <util/signalinterrupt.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <event2/buffer.h>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <vector> #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_view RequestMethodString(HTTPRequestMethod m); std::string_view RequestMethodString(HTTPRequestMethod m);
FUZZ_TARGET(http_request) FUZZ_TARGET(http_request)
{ {
using http_libevent::HTTPRequest; using http_bitcoin::HTTPRequest;
using http_bitcoin::MAX_HEADERS_SIZE;
using util::LineReader;
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; 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); const std::vector<uint8_t> http_buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, 4096);
evbuffer_add(evbuf, http_buffer.data(), http_buffer.size()); const std::vector<std::byte> http_bytes_buffer(reinterpret_cast<const std::byte*>(http_buffer.data()),
// Avoid constructing requests that will be interpreted by libevent as PROXY requests to avoid triggering reinterpret_cast<const std::byte*>(http_buffer.data()) + http_buffer.size());
// a nullptr dereference. The dereference (req->evcon->http_server) takes place in evhttp_parse_request_line
// and is a consequence of our hacky but necessary use of the internal function evhttp_parse_firstline_ in HTTPRequest http_request;
// this fuzzing harness. The workaround is not aesthetically pleasing, but it successfully avoids the troublesome LineReader reader(http_bytes_buffer, MAX_HEADERS_SIZE);
// code path. " http:// HTTP/1.1\n" was a crashing input prior to this workaround. try {
const std::string http_buffer_str = ToLower(std::string{http_buffer.begin(), http_buffer.end()}); if (!http_request.LoadControlData(reader)) return;
if (http_buffer_str.find(" http://") != std::string::npos || http_buffer_str.find(" https://") != std::string::npos || if (!http_request.LoadHeaders(reader)) return;
evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) { if (!http_request.LoadBody(reader)) return;
evbuffer_free(evbuf); } catch (const std::runtime_error&) {
evhttp_request_free(evreq);
return; return;
} }
util::SignalInterrupt interrupt;
HTTPRequest http_request{evreq, interrupt, true};
const HTTPRequestMethod request_method = http_request.GetRequestMethod(); const HTTPRequestMethod request_method = http_request.GetRequestMethod();
(void)RequestMethodString(request_method); (void)RequestMethodString(request_method);
(void)http_request.GetURI(); (void)http_request.GetURI();
@ -62,9 +49,4 @@ FUZZ_TARGET(http_request)
(void)http_request.GetHeader(header); (void)http_request.GetHeader(header);
const std::string body = http_request.ReadBody(); const std::string body = http_request.ReadBody();
assert(body.empty()); assert(body.empty());
const CService service = http_request.GetPeer();
assert(service.ToStringAddrPort() == "[::]:0");
evbuffer_free(evbuf);
evhttp_request_free(evreq);
} }