From 6d3abd38fa9908475381b00406c788683f7fa642 Mon Sep 17 00:00:00 2001 From: selsta Date: Sat, 8 Aug 2026 15:54:40 +0200 Subject: [PATCH] epee: validate Levin response command before buffering --- .../net/levin_protocol_handler_async.h | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index 4a0e56514..4dc68af83 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -193,6 +193,7 @@ public: struct invoke_response_handler_base { virtual ~invoke_response_handler_base() {} + virtual int command() const noexcept=0; virtual bool handle(int res, const epee::span buff, connection_context& context)=0; virtual void cancel()=0; virtual bool cancel_timer()=0; @@ -241,6 +242,11 @@ public: { failure(LEVIN_ERROR_CONNECTION_DESTROYED); } + + virtual int command() const noexcept override final + { + return m_command; + } virtual bool handle(int res, const epee::span buff, typename async_protocol_handler::connection_context& context) override final { @@ -285,6 +291,29 @@ public: }; critical_section m_invoke_response_handlers_lock; std::list> m_invoke_response_handlers; + + bool validate_response_command() + { + if (m_oponent_protocol_ver != LEVIN_PROTOCOL_VER_1 || !(m_current_head.m_flags & LEVIN_PACKET_RESPONSE)) + return true; + + CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock); + if (m_invoke_response_handlers.empty()) + { + MERROR(m_connection_context << "Received levin response but have no invoke handlers"); + return false; + } + + const std::shared_ptr response_handler = m_invoke_response_handlers.front().lock(); + if (!response_handler || m_current_head.m_command != static_cast(response_handler->command())) + { + MERROR(m_connection_context << "Received levin response command " << m_current_head.m_command + << " while waiting for " << (response_handler ? response_handler->command() : -1)); + return false; + } + + return true; + } template bool add_invoke_response_handler(const callback_t &cb, const std::chrono::milliseconds timeout, std::shared_ptr> con, int command) @@ -466,6 +495,9 @@ public: buff_to_invoke = {buff_to_invoke.data(), std::size_t(inner_size)}; + if (!validate_response_command()) + return false; + const size_t max_bytes = m_connection_context.get_max_bytes(m_current_head.m_command); if(buff_to_invoke.size() > std::min(max_packet_size, max_bytes)) { @@ -571,9 +603,12 @@ public: return false; } + m_oponent_protocol_ver = m_current_head.m_protocol_version; + if (!validate_response_command()) + return false; + m_cache_in_buffer.erase(sizeof(bucket_head2)); m_state = stream_state_body; - m_oponent_protocol_ver = m_current_head.m_protocol_version; const size_t max_bytes = m_connection_context.get_max_bytes(m_current_head.m_command); if(m_current_head.m_cb > std::min(max_packet_size, max_bytes)) {