From efe258a1377cf10478883722b41c00eada8da32a Mon Sep 17 00:00:00 2001 From: Xirvik Date: Thu, 4 Jun 2026 23:15:50 +0000 Subject: [PATCH] fix(rpc): preserve c_str() stability of stored XMLRPC method names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6488131 ("Fix RPC/SCGI security and crash bugs by @sirus20x6") replaced std::vector> storage with std::vector and returned back().c_str() to the xmlrpc-c registry as the per-method server_info pointer. This is unsafe for any method name short enough to be SSO-stored (<= 15 chars on libstdc++): such a string keeps its buffer inside the std::string object itself. When a later push_back reallocates the vector and move-constructs the existing elements into a new buffer, the previously returned c_str() pointers — captured by xmlrpc-c at registration time — dangle into freed memory. Because xmlrpc-c does not dereference server_info until a call dispatches, the failure surfaces later as nondeterministic garbage in fault strings, e.g. faultString: Command "thod." does not exist. (load.start, log.xmlrpc, log.execute) faultString: Command "in_rate" does not exist. (log.add_output) faultString: Command "" does not exist. (log.open_file) faultString: Command "+U" does not exist. (method.set_key) Long-named methods (e.g. system.client_version at 21 chars) are heap-allocated above the SSO threshold and escape the bug because the heap buffer's address is preserved across the vector move. Switch the storage to std::deque: per [deque.modifiers] push_back does not invalidate references to existing elements, so the std::string objects do not move and the c_str() pointers handed to xmlrpc-c remain valid for the program's lifetime. The body of store_command_name is unchanged. Fixes the use-after-free; preserves the std::string-based storage the original commit aimed for. --- src/rpc/xmlrpc.cc | 3 ++- src/rpc/xmlrpc.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rpc/xmlrpc.cc b/src/rpc/xmlrpc.cc index 25fd751c..48f8aadd 100644 --- a/src/rpc/xmlrpc.cc +++ b/src/rpc/xmlrpc.cc @@ -1,3 +1,4 @@ +#include #include "config.h" #include "xmlrpc.h" @@ -9,7 +10,7 @@ namespace rpc { -std::vector XmlRpc::m_command_names; +std::deque XmlRpc::m_command_names; const char* XmlRpc::store_command_name(const char* name) { diff --git a/src/rpc/xmlrpc.h b/src/rpc/xmlrpc.h index 9d853744..3cbfe822 100644 --- a/src/rpc/xmlrpc.h +++ b/src/rpc/xmlrpc.h @@ -1,6 +1,7 @@ #ifndef RTORRENT_RPC_XMLRPC_H #define RTORRENT_RPC_XMLRPC_H +#include #include #include #include @@ -61,7 +62,7 @@ public: private: static const char* store_command_name(const char* name); - static std::vector m_command_names; + static std::deque m_command_names; slot_download m_slotFindDownload; slot_file m_slotFindFile;