Skip to content

Latest commit

 

History

History
75 lines (59 loc) · 2.67 KB

File metadata and controls

75 lines (59 loc) · 2.67 KB

01 - tor-browser-mode drops all STREAM events on PID-based connections

  • Severity: major (for any loopback client using tor-browser-mode)
  • Location: onion-grater, function handle() around the tor_browser_mode and remote_connection check (Tails master ~line 922), and is_my_stream() (~line 396).

Description

tor-browser-mode is meant to restrict a client to seeing only its own STREAM and CIRC events, by matching the stream's source address against the client's address. Stream ownership is decided in is_my_stream():

def is_my_stream(self, stream):
    if self.client_pid is not None:
        # PID-based matching is racy and inherently insecure,
        # so we don't restrict-stream-events for it
        return False
    if self.client_address[0] == stream.source_address:
        return True
    return False

For a PID-based (loopback) connection, client_pid is set, so is_my_stream() always returns False -- no stream is ever "owned".

The option is only auto-disabled for remote connections:

if self.tor_browser_mode and remote_connection:
    ...
    self.tor_browser_mode = False

There is no equivalent disable for PID-based connections. So if a client that is matched by apparmor-profiles/users (i.e. a loopback, PID-based connection) uses a profile with tor-browser-mode: true, the mode stays enabled but is_my_stream() always returns False. Result: every STREAM event is dropped and getinfo circuit-status returns no circuits.

Impact

  • Any loopback client using a tor-browser-mode profile gets a non-functional control port for stream/circuit visibility.
  • In Tails, Tor Browser is the intended consumer; whether it is reached via the PID-based path depends on how it connects.
  • Whonix: inert (no Whonix profile enables tor-browser-mode). It does block enabling stream isolation for a loopback-matched app (e.g. wahay), which would hit exactly this bug.

Proposed fix

Disable tor-browser-mode for PID-based connections as well, since they cannot be source-address matched:

unsupported = remote_connection or pid_based_connection
if self.tor_browser_mode and unsupported:
    self.debug_log(
        f"filter '{self.filter_name}' has `tor-browser-mode` set "
        "but this connection cannot be source-address matched, "
        "so the option was disabled"
    )
    self.tor_browser_mode = False

(Or, better, implement PID-based stream ownership so the feature can work for loopback clients -- but the safe minimum is to disable rather than silently drop everything.)

Provenance

Found by CodeRabbit during an AI-review pass of the Whonix onion-grater resync to Tails, 2026-06.