epee: prevent log injection from malformed HTTP headers

(cherry picked from commit 281c1d41aae7b579fa1307d82622e18abcd038ff)
This commit is contained in:
selsta
2026-10-04 18:50:23 -04:00
committed by such-gitea
parent fb0d7b2318
commit 01a7c14a82
2 changed files with 23 additions and 23 deletions
+16 -16
View File
@@ -594,7 +594,7 @@ namespace net_utils
}
if(!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched))
{
LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache);
LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head (" << m_chunked_cache.size() << " bytes)");
m_state = reciev_machine_state_error;
return false;
}
@@ -660,7 +660,7 @@ namespace net_utils
while(cur < m_cache_to_process.size())
{
const size_t line_end = m_cache_to_process.find('\n', cur);
CHECK_AND_ASSERT_MES(line_end != std::string::npos, false, "http_stream_filter::parse_cached_header() invalid header in: " << m_cache_to_process);
CHECK_AND_ASSERT_MES(line_end != std::string::npos, false, "http_stream_filter::parse_cached_header() invalid header (" << m_cache_to_process.size() << " bytes)");
boost::string_view line(m_cache_to_process.data() + cur, line_end - cur);
cur = line_end + 1;
@@ -670,7 +670,7 @@ namespace net_utils
boost::string_view name;
boost::string_view value;
CHECK_AND_ASSERT_MES(detail::parse_header_line(line, name, value), false, "http_stream_filter::parse_cached_header() invalid header in: " << m_cache_to_process);
CHECK_AND_ASSERT_MES(detail::parse_header_line(line, name, value), false, "http_stream_filter::parse_cached_header() invalid header (" << m_cache_to_process.size() << " bytes)");
std::string key(name.data(), name.size());
std::string val(value.data(), value.size());
@@ -704,25 +704,25 @@ namespace net_utils
{
//First line response, look like this: "HTTP/1.1 200 OK"
const char *ptr = m_header_cache.c_str();
CHECK_AND_ASSERT_MES(!memcmp(ptr, "HTTP/", 5), false, "Invalid first response line: " + m_header_cache);
CHECK_AND_ASSERT_MES(!memcmp(ptr, "HTTP/", 5), false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
ptr += 5;
CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
unsigned long ul;
char *end;
ul = strtoul(ptr, &end, 10);
CHECK_AND_ASSERT_MES(ul <= INT_MAX && *end =='.', false, "Invalid first response line: " + m_header_cache);
CHECK_AND_ASSERT_MES(ul <= INT_MAX && *end =='.', false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
m_response_info.m_http_ver_hi = ul;
ptr = end + 1;
CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
ul = strtoul(ptr, &end, 10);
CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
m_response_info.m_http_ver_lo = ul;
ptr = end + 1;
while (isblank(*ptr))
++ptr;
CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
ul = strtoul(ptr, &end, 10);
CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line: " + m_header_cache);
CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
m_response_info.m_response_code = ul;
ptr = end;
// ignore the optional text, till the end
@@ -730,7 +730,7 @@ namespace net_utils
++ptr;
if (*ptr == '\r')
++ptr;
CHECK_AND_ASSERT_MES(*ptr == '\n', false, "Invalid first response line: " << m_header_cache);
CHECK_AND_ASSERT_MES(*ptr == '\n', false, "Invalid first response line (" << m_header_cache.size() << " header bytes)");
++ptr;
m_header_cache.erase(0, ptr - m_header_cache.c_str());
@@ -762,7 +762,7 @@ namespace net_utils
std::string fake_str; //gcc error workaround
bool res = parse_header(m_response_info.m_header_info, m_header_cache);
CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache);
CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header (" << m_header_cache.size() << " bytes)");
set_reply_content_encoder();
@@ -784,7 +784,7 @@ namespace net_utils
string_tools::trim(m_response_info.m_header_info.m_transfer_encoding);
if(string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked"))
{
LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding);
LOG_ERROR("Wrong Transfer-Encoding (" << m_response_info.m_header_info.m_transfer_encoding.size() << " bytes)");
m_state = reciev_machine_state_error;
return false;
}
@@ -797,7 +797,7 @@ namespace net_utils
//In the response header the length was specified
if(!content_len_valid)
{
LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_response_info.m_header_info.m_content_length);
LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght() (" << m_response_info.m_header_info.m_content_length.size() << " bytes)");
m_state = reciev_machine_state_error;
return false;
}
@@ -823,7 +823,7 @@ namespace net_utils
}else
{ //Apparently there are no signs of the form of transfer, will receive data until the connection is closed
m_state = reciev_machine_state_error;
MERROR("Undefined transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache);
MERROR("Undefined transfer type, consider http_body_transfer_connection_close method (" << m_header_cache.size() << " header bytes)");
return false;
}
return false;
@@ -854,7 +854,7 @@ namespace net_utils
boundary = result[7];
else
{
LOG_ERROR("Failed to match boundary in content-type=" << head_info.m_content_type);
LOG_ERROR("Failed to match boundary in content-type (" << head_info.m_content_type.size() << " bytes)");
return false;
}
return true;
@@ -101,7 +101,7 @@ namespace net_utils
entry.m_etc_header_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
else
{
LOG_ERROR("simple_http_connection_handler::parse_header() not matched last entry in:"<<std::string(it_current_bound, it_end));
LOG_ERROR("simple_http_connection_handler::parse_header() not matched last entry (" << std::distance(it_current_bound, it_end) << " bytes)");
}
it_current_bound = result[(int)result.size()-1].first;
@@ -122,7 +122,7 @@ namespace net_utils
if(!parse_header(it_begin, end_header_it+4, entry))
{
LOG_ERROR("Failed to parse header:" << std::string(it_begin, end_header_it+2));
LOG_ERROR("Failed to parse header (" << std::distance(it_begin, end_header_it + 2) << " bytes)");
return false;
}
@@ -139,7 +139,7 @@ namespace net_utils
std::string boundary;
if(!match_boundary(content_type, boundary))
{
MERROR("Failed to match boundary in content type: " << content_type);
MERROR("Failed to match boundary in content type (" << content_type.size() << " bytes)");
return false;
}
@@ -430,7 +430,7 @@ namespace net_utils
}else
{
m_state = http_state_error;
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache);
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line (" << m_cache.size() << " bytes)");
return false;
}
@@ -454,14 +454,14 @@ namespace net_utils
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(size_t pos)
{
LOG_PRINT_L3("HTTP HEAD:\r\n" << m_cache.substr(0, pos));
LOG_PRINT_L3("HTTP HEAD: " << pos << " bytes");
m_query_info.m_full_request_buf_size = pos;
m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos);
if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos))
{
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache);
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header (" << pos << " bytes)");
m_state = http_state_error;
return false;
}
@@ -477,7 +477,7 @@ namespace net_utils
m_body_transfer_type = http_body_transfer_measure;
if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary))
{
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_query_info.m_header_info.m_content_length);
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght() (" << m_query_info.m_header_info.m_content_length.size() << " bytes)");
m_state = http_state_error;
return false;
}