FreeBSD jails or some OpenVZ virtual machines do not have a lo interace (no 127.0.0.1 or localhost address), they only have an interface with either a public IP address either a NAT address routed upstream on the host.
In this case, if ControlPort 9051 is set, it will open the control port on the public IP address without even a warning which is not funny. This applies also to SocksPort, but that's less scary than ControlPort.
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Child items ...
Show closed items
Linked items 0
Link issues together to show that they're related.
Learn more.
One way of resolving this issue is to check that we're actually binding to 127.0.0.1 or ::1 for the (default/no IP address) ControlPort and SOCKSPort, and complain loudly and fail to launch if we're not.
We can require the user to configure an explicit IP address (or access rules? does the ControlPort have those?) to silence the warning and start tor.
One way of resolving this issue is to check that we're actually binding to 127.0.0.1 or ::1 for the (default/no IP address) ControlPort and SOCKSPort, and complain loudly and fail to launch if we're not.
I'm ok with this. We already have code for enumerating interfaces, so we could warn earlier as well.
We can require the user to configure an explicit IP address (or access rules? does the ControlPort have those?) to silence the warning and start tor.
There's flags for all the Ports, so adding another is easy-ish (to allow unsafe behavior). Even if they explicitly configure something I'd vote that we warn anyway, because it's still a horrific idea, just actually start up instead of terminating on the warning.
For future reference, if something that will never work correctly when jailed comes up in the future, there's a sysctl MIB (security.jail.jailed which will be set to 1) that can be queried via sysctl(3).
While bind to whatever/default is good and wanted for DirPort and ORPort it's very not wanted for SocksPort, ControlPort, ExtORPort and other ports opened by Tor which are not meant to be open publicly.
teor I think if ControlPort : is manually and explicitly set we should assume that the user knows what he is doing and proceed, or be very protective and decide he'd rather not?
While bind to whatever/default is good and wanted for DirPort and ORPort it's very not wanted for SocksPort, ControlPort, ExtORPort and other ports opened by Tor which are not meant to be open publicly.
ExtOR being open to the world is... odd but won't be game breaking since it doesn't allow anything apart from serving as a sink for PT traffic (and it's authenticated similar to ControlPort with cookie auth).
teor I think if ControlPort : is manually and explicitly set we should assume that the user knows what he is doing and proceed, or be very protective and decide he'd rather not?
The former, but warn loudly that it's a bad idea, probably?
In an ideal world, we'd deprecate binding the ControlPort to non-AF_UNIX sockets where AF_UNIX is available (because it is that big of a foot + gun hazzard), but I expect that to be a non-starter just for legacy reasons, unfortunately.
While we are looking at this, isn't #13953 (moved) somehow related? It appears to be related to the same IP address binding / selection part. Hopefully with not too much extra work we can fix both.
In #13953 (moved), the address that the ORPort binds to is correct, but the reachability test uses the wrong address. Therefore, #13953 (moved) would be best resolved with #17782 (moved), which also deals with reachability self-testing.
I think we should automatically disable ControlPort, ExtORPort, TransPort and DNSPort if we have no lo interface (127.0.0.1 localhost address) and they are set with just the port number or auto. If the setting for them is <pulic IP / NAT IP>: we assume it's wanted and expected to be open there and proceed, but with loud warnings that it's a terrible idea. Maybe we should require authentication for ControlPort if opened on public / nat IP or quit otherwise? Not entirely sure if it's worth it.
For ORPort and DirPort binding to whatever IP address it sees is fine, we shouldn't change the behavior for these two, so whatever fixes we apply should be related to ControlPortTransPortDNSPortExtORPort and SocksPort. Hope I didn't miss anything.
I think we should have Tor exit if we have no loopback interface.
Doesn't that totally break OpenVZ and FreeBSD jails? I think that's a bit extreme. We certainly should fail closed if the user automatically configures certain ports that have no business of being public, but Tor should continue to function jammed into a jail assuming it uses an AF_UNIX ControlPort for example...
If there is no 127.0.0.0/8 on the server, reject the *Port with a warning that tells the user to supply an explicit IP address if they really want their *Port listening on a non-local address.
Bind all *Ports to:
The first IPv4 address that "localhost" resolves to, as long as it is in 127.0.0.0/8, or 127.0.0.1 by default
This ensures that configurations that have localhost on an alternate address in 127.0.0.0/8 continue to work (this is another common BSD jail config)
This issue may also affect HiddenServicePort, which defaults to connecting to 127.0.0.1. We should check that it fails if there is no 127.0.0.1, and the warning is helpful, if so, the current behaviour is fine.
If there is no 127.0.0.0/8 on the server, reject the *Port with a warning that tells the user to supply an explicit IP address if they really want their *Port listening on a non-local address.
Bind all *Ports to:
The first IPv4 address that "localhost" resolves to, as long as it is in 127.0.0.0/8, or 127.0.0.1 by default
This ensures that configurations that have localhost on an alternate address in 127.0.0.0/8 continue to work (this is another common BSD jail config)
This issue may also affect HiddenServicePort, which defaults to connecting to 127.0.0.1. We should check that it fails if there is no 127.0.0.1, and the warning is helpful, if so, the current behaviour is fine.
These seem ok. I'd suggest allowing localhost to also be [::1] for the far future. I'm vaguely inclined to also add an extra config option which needs to be enabled to allow non-localhost/AF_UNIX ControlPort, because it really is that bad of an idea, but that may be overly hand-holding.
(I've also split off #17948 (moved) for the hidden service IPv4/IPv6 localhost changes, as it's in a different area of the code, and not security related.)
I'm vaguely inclined to also add an extra config option which needs to be enabled to allow non-localhost/AF_UNIX ControlPort, because it really is that bad of an idea, but that may be overly hand-holding.
Instead of resolving localhost, we could look through all the interfaces and find the first address present on the system that:
is 127.0.0.1, or
is in 127/8.
For stability, it would make sense to choose the numerically lowest valid 127/8 address.
(That is, exclude 127.0.0.0, and choose the address that is closest to 127.0.0.1.)
If a system doesn't allow tor to use those APIs, we could try to resolve localhost, but we have no guarantee that would work on a locked-down system either. For simplicity, I prefer to only use a single method to choose addresses, and leave the operator to sort it out otherwise.
If there is no 127.0.0.0/8 on the server, reject the *Port with a warning that tells the user to supply an explicit IP address if they really want their *Port listening on a non-local address.
If there is no 127.0.0.0/8 on the server, reject the *Port with a warning that tells the user to use AF_UNIX (if their system supports it), or supply an explicit IP address if they really want their *Port listening on a non-local address.
Instead of resolving localhost, we could look through all the interfaces and find the first address present on the system that:
is 127.0.0.1, or
is in 127/8.
For stability, it would make sense to choose the numerically lowest valid 127/8 address.
(That is, exclude 127.0.0.0, and choose the address that is closest to 127.0.0.1.)
On Linux, when you query the interfaces, you can check the per-interface flags for IFF_LOOPBACK. On systems where this information is readily available (I think we even already have code that uses the relevant ioctl), we should use that to restrict the set of candidate addresses.
Edit: Yeah, get_interface_addresses_ioctl() issues the query we want, we just need to save the flags we care about somewhere.