Reset SCgiTask m_trusted on connection reuse

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).
This commit is contained in:
Xirvik
2026-05-03 23:50:43 +00:00
committed by Jari Sundell
parent 2700b3141f
commit 981184574d
+6 -1
View File
@@ -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;
}