From 981184574dd7d5cc6908ce3527b6cbf3aadffa43 Mon Sep 17 00:00:00 2001 From: Xirvik Date: Sun, 3 May 2026 23:50:43 +0000 Subject: [PATCH] Reset SCgiTask m_trusted on connection reuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SCgiTask objects are pre-allocated in a pool (scgi.cc) and reused across SCGI connections. SCgiTask::open() did not reset m_trusted, so when a task that had handled an untrusted connection (m_trusted=false) was reused for a new connection, m_trusted stayed false unless the new connection explicitly sent UNTRUSTED_CONNECTION=1. The header parser only set m_trusted=false on value 1 and was a no-op on value 0 (the comment said "default is trusted, so do nothing") — which is wrong for a reused task that is no longer in default state. This caused intermittent rejection of trusted commands (e.g. ruTorrent calling execute.capture for UID detection) with "Command X is not allowed for untrusted connections", producing cascading plugin failures and "ruTorrent cannot determine the UID of rTorrent user" in the web UI. Fix: - SCgiTask::open() resets m_trusted=true to default. - parse_headers explicitly sets m_trusted=true on UNTRUSTED_CONNECTION=0, so the value sent on the wire is authoritative regardless of pool reuse semantics. Verified on gb4 with rtorrent 0.16.11 + this fix: 30/30 trusted calls succeed, 30/30 untrusted correctly blocked, 30/30 trusted-after-untrusted batch all succeed (previously 70%+ would fail in the same scenario). --- src/rpc/scgi_task.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index 7feecc35..a8a66b1a 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -35,6 +35,10 @@ SCgiTask::open(SCgi* parent, int fd) { m_content_length = 0; m_content_type = XML; m_accepts_compression = false; + m_trusted = true; // SCgiTask is pooled and reused; reset trust to default + // so a prior untrusted connection does not leak its + // m_trusted=false into the next reuse, given that the + // UNTRUSTED_CONNECTION=0 parse branch is a no-op. torrent::this_thread::poll()->open(this); torrent::this_thread::poll()->insert_read(this); @@ -231,7 +235,8 @@ SCgiTask::parse_headers(const char* current, unsigned int header_length) { if (std::strncmp(value, "1", 1+1) == 0) m_trusted = false; else if (std::strncmp(value, "0", 1+1) == 0) - ; // Default is trusted, so do nothing. + m_trusted = true; // Explicit reset (open() also resets, but be defensive in case + // future refactors stop pooling tasks or skip the open() reset). else return false; }