tor reads PT protocol messages from stderr
Create a fake server transport plugin that writes PT protocol strings to stderr, not stdout:
#!/bin/sh
(
echo "VERSION 1"
echo "SMETHOD testpt 127.0.0.1:9999"
echo "SMETHODS DONE"
) 2>&1
Verify that it writes nothing to stdout:
$ ./testpt.stderr.sh >/dev/null | wc
0 0 0
Run tor with this torrc:
PublishServerDescriptor 0
AssumeReachable
SOCKSPort 0
ORPort auto
ServerTransportPlugin testpt exec ./testpt.stderr.sh
Bridge testpt 127.0.0.1:9999
A log line shows that tor has interpreted PT protocol messages from stderr, when it should only be looking for them on stdout.
Oct 10 16:21:11.000 [notice] Registered server transport 'testpt' at '127.0.0.1:9999'
I think this is a bug. pt-spec says "All Pluggable Transport Proxies communicate to the parent process via writing NL-terminated lines to stdout." It does not say that tor should inspect stderr and interpret any lines that happen to be a well-formed PT protocol message that it finds there, as if they had been sent on stdout.
The only mention of stderr in the spec is in the context of LOG and STATUS, and that is a fairly recent addition with legacy/trac#28179 (moved)/legacy/trac#28181 (moved). I always thought that the intention was to copy anything seen on stderr to tor's log, as if it had been part of a LOG message on stdout. The mention of stderr in relation to STATUS is something I missed during review of that part of the spec, because I don't think it makes sense there.
What I expected to see was this, treating verbatim stderr lines as things to be logged:
[notice] Unknown line received by managed proxy (VERSION 1)
[notice] Unknown line received by managed proxy (SMETHOD testpt 127.0.0.1:9999)
[notice] Unknown line received by managed proxy (SMETHODS DONE)
Otherwise, tor is essentially holding transport plugins to a contract that is unstated in the spec: transport plugins cannot safely write anything to stderr at all, because there is always a danger that a future version of tor will recognize it as a PT message and interpret it, instead of just logging it.