From 11422cc5720c8d73a87600de8fe8abb156db80dc Mon Sep 17 00:00:00 2001 From: pablomartin4btc Date: Fri, 14 Apr 2023 19:03:08 -0300 Subject: bugfix: rest: avoid segfault for invalid URI `evhttp_uri_parse` can return a nullptr, for example when the URI contains invalid characters (e.g. "%"). `GetQueryParameterFromUri` passes the output of `evhttp_uri_parse` straight into `evhttp_uri_get_query`, which means that anyone calling a REST endpoint in which query parameters are used (e.g. `rest_headers`) can cause a segfault. This bugfix is designed to be minimal and without additional behaviour change. Follow-up work should be done to resolve this in a more general and robust way, so not every endpoint has to handle it individually. --- src/rest.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src/rest.cpp') diff --git a/src/rest.cpp b/src/rest.cpp index fa119ddfb7..e46406f1ad 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -200,7 +200,11 @@ static bool rest_headers(const std::any& context, } else if (path.size() == 1) { // new path with query parameter: /rest/headers/?count= hashStr = path[0]; - raw_count = req->GetQueryParameter("count").value_or("5"); + try { + raw_count = req->GetQueryParameter("count").value_or("5"); + } catch (const std::runtime_error& e) { + return RESTERR(req, HTTP_BAD_REQUEST, e.what()); + } } else { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/headers/.?count="); } @@ -371,7 +375,11 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const } else if (uri_parts.size() == 2) { // new path with query parameter: /rest/blockfilterheaders//?count= raw_blockhash = uri_parts[1]; - raw_count = req->GetQueryParameter("count").value_or("5"); + try { + raw_count = req->GetQueryParameter("count").value_or("5"); + } catch (const std::runtime_error& e) { + return RESTERR(req, HTTP_BAD_REQUEST, e.what()); + } } else { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilterheaders//.?count="); } @@ -652,11 +660,21 @@ static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::s case RESTResponseFormat::JSON: { std::string str_json; if (param == "contents") { - const std::string raw_verbose{req->GetQueryParameter("verbose").value_or("true")}; + std::string raw_verbose; + try { + raw_verbose = req->GetQueryParameter("verbose").value_or("true"); + } catch (const std::runtime_error& e) { + return RESTERR(req, HTTP_BAD_REQUEST, e.what()); + } if (raw_verbose != "true" && raw_verbose != "false") { return RESTERR(req, HTTP_BAD_REQUEST, "The \"verbose\" query parameter must be either \"true\" or \"false\"."); } - const std::string raw_mempool_sequence{req->GetQueryParameter("mempool_sequence").value_or("false")}; + std::string raw_mempool_sequence; + try { + raw_mempool_sequence = req->GetQueryParameter("mempool_sequence").value_or("false"); + } catch (const std::runtime_error& e) { + return RESTERR(req, HTTP_BAD_REQUEST, e.what()); + } if (raw_mempool_sequence != "true" && raw_mempool_sequence != "false") { return RESTERR(req, HTTP_BAD_REQUEST, "The \"mempool_sequence\" query parameter must be either \"true\" or \"false\"."); } -- cgit v1.2.3