Add fields to REDIRECTSTREAM and ATTACHSTREAM for matching fields of associated stream
Summary
Currently, the REDIRECTSTREAM
and ATTACHSTREAM
commands accept a StreamID
parameter, which Tor uses to figure out which stream is affected by those commands. Both of these commands are unreasonably powerful if run without any kind of containment, i.e. being able to affect arbitrary StreamID
's. (For example, Namecoin only needs to be able to redirect streams that currently have a target within Namecoin's eTLD; letting Namecoin redirect arbitrary streams violates the principle of least privilege.) Unfortunately, it is nontrivial to sandbox these commands effectively with a control port filter, because the control port filter only has access to the StreamID
field, when what it really needs is the fields of the underlying stream that is associated with that StreamID
. It is theoretically possible for the control port filter to maintain its own copy of this state (by watching for STREAM
events), but such a solution would be messy and risk-prone. I propose adding optional fields to REDIRECTSTREAM
and ATTACHSTREAM
that act as a must-match rule for the fields of the underlying stream, thus making it easy to sandbox these commands via a control port filter that drops such commands if their must-match rules do not match the control port filter's configured whitelist.
What is the expected behavior?
The following optional fields would be added to both REDIRECTSTREAM
and ATTACHSTREAM
:
-
MUST_TARGET=Target
: The command is a NOP if theTarget
field of the stream associated with the givenStreamID
is not exactly equal to the providedTarget
. -
MUST_SOURCE_ADDR=SOURCE_ADDR
: The command is a NOP if theSOURCE_ADDR
field of the stream associated with the givenStreamID
is not exactly equal to the providedSOURCE_ADDR
. -
MUST_STATUS=StreamStatus
: The command is a NOP if theStreamStatus
field of the stream associated with the givenStreamID
is not exactly equal to the providedStreamStatus
. -
MUST_SOCKS_USERNAME=EscapedUsername
: The command is a NOP if theSOCKS_USERNAME
field of the stream associated with the givenStreamID
is not exactly equal to the providedEscapedUsername
. -
MUST_SOCKS_PASSWORD=EscapedPassword
: The command is a NOP if theSOCKS_PASSWORD
field of the stream associated with the givenStreamID
is not exactly equal to the providedEscapedPassword
.
Practical example reasons for sandboxing based on these:
- Namecoin has no legitimate business redirecting a stream whose
Target
is not currently in a Namecoin eTLD. Violating this rule could allow a compromised Namecoin to metastasize to compromise non-Namecoin traffic. - If a single Tor instance is serving applications on two machines, the user's security model may dictate that a Namecoin instance on one machine has no legitimate business redirecting a stream that was created by the other machine. Violating this rule could allow a compromised machine to metastasize to compromise traffic on the other machine.
- Namecoin has no legitimate business attaching a stream whose status is not currently equal to
CONTROLLER_WAIT
. Violating this rule could allow a compromised or buggy Namecoin to disconnect streams that were already attached to a circuit. - If using an application in which the SOCKS username indicates first-party origin (such as Tor Browser), the user's security model may dictate that Namecoin has no legitimate business redirecting a stream whose first-party origin (i.e. the SOCKS username) is not in a Namecoin eTLD. Violating this rule could allow a malicious non-Namecoin website to learn 1 highly skewed bit of fingerprinting data regarding whether the user has Namecoin installed.
Open question: should we support some kind of partial match mechanism, e.g. wildcards or regex? I feel like this would add too much attack surface, but on the other hand maybe it would enable the control port filter to hide potentially sensitive data (e.g. parts of the SOCKS username) from the controller. I lean toward not supporting this, but I am open to being convinced otherwise.
Open question: are there other fields that we should support matching? The above 5 fields are the only ones that I can picture mattering, but maybe I'm insufficiently imaginative.
If there are better ways to support this use case, I am open to suggestions of alternate approaches too.
Note that this proposal would require a spec change too.
I am probably willing to try my hand at implementing this if you're okay with the approach.