From ea16276773cfe85a6ae37aca1913ed45722772b2 Mon Sep 17 00:00:00 2001 From: Xirvik Date: Sun, 1 Mar 2026 18:24:24 +0000 Subject: [PATCH] Fix crash on untrusted XMLRPC connections Root cause: network.rpc.use_xmlrpc and network.rpc.use_jsonrpc were not marked as untrusted-safe, but RpcManager::process() calls them before dispatching to the protocol handler. When an untrusted request arrived, call_command() threw untrusted_error for these gatekeepers, which escaped the callback_interrupt_pollling callback and crashed rtorrent. Fix: Mark network.rpc.use_xmlrpc/jsonrpc as safe (CMD2_VAR_BOOL_U). Also harden exception safety: - SCGI callback catch-all now sends a generic error response instead of re-throwing, since the callback infrastructure may not support exception propagation. - xmlrpc_c.cc now has catch(std::exception&) and catch(...) safety nets after the specific exception handlers. --- src/command_network.cc | 4 ++-- src/rpc/scgi_task.cc | 13 ++++++++++++- src/rpc/xmlrpc_c.cc | 8 ++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/command_network.cc b/src/command_network.cc index 7fdf54d2..b07d9d14 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -248,8 +248,8 @@ initialize_command_network() { CMD2_ANY_U ("network.xmlrpc.size_limit", [](const auto&, const auto&) { return rpc::rpc.size_limit(); }); CMD2_ANY_VALUE_V_U ("network.xmlrpc.size_limit.set", [](const auto&, const auto& arg) { return rpc::rpc.set_size_limit(arg); }); - CMD2_VAR_BOOL ("network.rpc.use_xmlrpc", true); - CMD2_VAR_BOOL ("network.rpc.use_jsonrpc", true); + CMD2_VAR_BOOL_U ("network.rpc.use_xmlrpc", true); + CMD2_VAR_BOOL_U ("network.rpc.use_jsonrpc", true); CMD2_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); }); CMD2_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); }); diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index 3046e9d5..25afa912 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -3,6 +3,7 @@ #include "rpc/scgi_task.h" #include +#include #include #include #include @@ -315,7 +316,17 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) { }); } catch (...) { rpc::RpcManager::set_trusted(true); - throw; + + // Send a generic error response instead of re-throwing, as the + // callback infrastructure may not support exception propagation. + const char* err_xml = "" + "faultCode-500" + "faultStringInternal error" + ""; + const char* err_json = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"Internal error\"},\"id\":null}"; + const char* err = (rpc_type == RpcManager::RPCType::JSON) ? err_json : err_xml; + result_callback(err, std::strlen(err)); + return; } rpc::RpcManager::set_trusted(true); diff --git a/src/rpc/xmlrpc_c.cc b/src/rpc/xmlrpc_c.cc index cf80b83a..cf05dde2 100644 --- a/src/rpc/xmlrpc_c.cc +++ b/src/rpc/xmlrpc_c.cc @@ -396,6 +396,14 @@ xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) { } catch (torrent::local_error& e) { xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, e.what()); return NULL; + + } catch (std::exception& e) { + xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, e.what()); + return NULL; + + } catch (...) { + xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, "Unknown exception in command execution."); + return NULL; } }