Opened 5 years ago

Last modified 7 months ago

#18356 new defect

obfs4proxy cannot bind to <1024 port with systemd hardened service unit

Reported by: irregulator Owned by: asn
Priority: Low Milestone: Tor: unspecified
Component: Core Tor/Tor Version: Tor: 0.2.7.4-rc
Severity: Normal Keywords: obfs4proxy, systemd, jessie, tor-pt
Cc: intrigeri, dcf, phw Actual Points:
Parent ID: Points: 15
Reviewer: Sponsor:

Description

Hi,

I was running an obfs4proxy Debian Wheezy bridge with such configuration in torrc:

ServerTransportListenAddr obfs4 0.0.0.0:443

When I dist-upgraded to Debian Jessie, obfs4proxy could not bind to :443 any more, while tor logs had such messages:

Feb 21 22:51:09.000 [warn] Server managed proxy encountered a method error. (obfs4 listen tcp 0.0.0.0:443: bind: permission denied)
Feb 21 22:51:09.000 [warn] Managed proxy at '/usr/bin/obfs4proxy' failed the configuration protocol and will be destroyed.

Mind that I have already set the appropriate capability to the obfs4proxy binary:

getcap /usr/bin/obfs4proxy                
/usr/bin/obfs4proxy = cap_net_bind_service+ep

I took some time moving things around and I think the problem resides on the systemd service unit: https://gitweb.torproject.org/tor.git/tree/contrib/dist/tor.service.in and specifically the option introduced in b4170421cc58d8c57254f4224ba259e817f48869 .

NoNewPrivileges=yes

I assume so because flipping 'NoNewPrivileges=no' results in obfs4proxy binding to 443. Also, 'PR_SET_NO_NEW_PRIVS' section in 'man 2 prctl' implies so:

PR_SET_NO_NEW_PRIVS (since Linux 3.5)
              Set  the  calling  process's  no_new_privs  bit to the value in arg2.  With
              no_new_privs set to 1, execve(2) promises not to  grant  privileges  to  do
              anything  that  could  not  have  been done without the execve(2) call (for
              example, rendering the set-user-ID and set-group-ID  permission  bits,  and
              file  capabilities  non-functional).   Once  set, this bit cannot be unset.
              The setting of this bit is inherited by children  created  by  fork(2)  and
              clone(2), and preserved across execve(2).

              For   more   information,   see   the   kernel   source   file   Documenta‐
              tion/prctl/no_new_privs.txt.

I understand that 'NoNewPrivileges=no' is a system security drawback but I also consider a regression to not be able to bind obfs4proxy to ports <1024. Could we find a middle ground?

If that helps, I'm running:

tor: 0.2.7.6-1~d80.jessie+1                                                         
deb.torproject.org/torproject.org/ jessie/main amd64 Packages 

obfs4proxy: 0.0.4-1~tpo1
deb.torproject.org/torproject.org/ obfs4proxy/main amd64 Packages

Also:

cat /etc/debian_version 
8.3
cat /proc/version 
Linux version 3.16.0-4-amd64 (debian-kernel@lists.debian.org) (gcc version 4.8.4 (Debian 4.8.4-1) ) #1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17)

Thanks for your work.

Child Tickets

Change History (12)

comment:1 Changed 5 years ago by yawning

Component: ObfsproxyTor
Keywords: tor-pt added
Milestone: Tor: unspecified
Priority: MediumLow

Yes, the root cause is indeed how systemd is spawning tor, and the config option. There is absolutely nothing I can do from within obfs4proxy to work around this, because it is a security feature enforced by the kernel.

Something like the tor daemon opening the socket bound to a privileged port would be possible, but that requires patching tor, modifying the PT configuration/spawn process, and then modifying obfs4proxy.

Since "fixing" this requires modifying the service file at a minimum, and a large list of tor changes and spec changes to do correctly, I am re-categorizing this.

comment:2 Changed 3 years ago by nickm

Points: 15

comment:3 Changed 3 years ago by dcf

Cc: dcf added

I didn't know about this ticket when I filed a Debian bug yesterday:

tor >= 0.2.7.4-rc-1 renders CAP_NET_BIND_SERVICE on server transport plugins ineffective

I tried various versions of the Debian package and found that the first version that doesn't allow server transport plugins to bind to low ports is 0.2.7.4-rc-1.

The workaround of setting NoNewPrivileges=no in /lib/systemd/system/tor@default.service and /lib/systemd/system/tor@.service also worked in my case. This is on Debian 9 (stretch) with tor 0.2.9.11-1~deb9u1. After modifying the .service files, I had to run:

systemctl daemon-reload
service tor restart

EDIT 2020-02-10: See comment:10 for a better alternative to editing /lib/systemd files.

Last edited 9 months ago by dcf (previous) (diff)

comment:4 Changed 3 years ago by tom

I also got bit by this, and found this ticket primarily by luck. It would be good to document a recommended workaround somewhere.

comment:5 Changed 3 years ago by dcf

Cross-referencing #7875, which is more about transport plugins not being able to listen on a port different than they advertise (like if you had port forwarding set up to forward port 443 to some high-numbered port).

comment:6 Changed 3 years ago by dcf

Version: Tor: 0.2.7.6Tor: 0.2.7.4-rc

comment:7 Changed 17 months ago by arma

Cc: phw added

cc'ing phw because we might want to work on this ticket as part of the obfs4 operator ux work (at least, say, documenting the workaround).

comment:8 Changed 15 months ago by quite

The workarounds are documented in the "canonical":

https://trac.torproject.org/projects/tor/wiki/doc/PluggableTransports/obfs4proxy

And as well at:

https://community.torproject.org/relay/setup/bridge/debian-ubuntu/

But since this issue (and #7875) still lingers years later, I'm thinking that what we're after is a solution that allows setting up a bridge by simply installing the tor package, the obfs4proxy binary (by some means), and editing torrc? And not a documented, post-package-installation workaround/tweak.

comment:9 in reply to:  8 Changed 15 months ago by phw

Replying to quite:

But since this issue (and #7875) still lingers years later, I'm thinking that what we're after is a solution that allows setting up a bridge by simply installing the tor package, the obfs4proxy binary (by some means), and editing torrc? And not a documented, post-package-installation workaround/tweak.


We are working on this over at #31153.

comment:10 Changed 9 months ago by dcf

At https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=865495#32, weasel provided a hint about using an override or "drop-in" file to do the NoNewPrivileges=no configuration change. This is better than editing /lib/systemd/system/tor@default.service and /lib/systemd/system/tor@.service because it will persist across upgrades of the tor package.

Run the command

systemctl edit tor@.service tor@default.service

In the editor, enter the following text, then save and quit.

[Service]
NoNewPrivileges=no

In the second editor that appears, enter the same text, then save and quit.

[Service]
NoNewPrivileges=no

If everything worked correctly, you will now have two files /etc/systemd/system/tor@.service.d/override.conf and /etc/systemd/system/tor@default.service.d/override.conf containing the text you entered. Now run

service tor restart

There is no need to run systemctl daemon-reload because systemctl edit does it automatically.

comment:11 Changed 9 months ago by phw

I recently had a chat with weasel about the same topic. He would be happy to mention the above in README.Debian if we can provide a patch. Weasel also finds setcap scary and considers a NAT/firewall rule from a low to a high port more reasonable. The problem is that ServerTransportListenAddr has no equivalent for ORPort's NoListen directive, and is generally due for an overhaul.

Our bridge setup guides still advise to overwrite the original systemd config file, which is bad because it gets overwritten when the obfs4proxy package is updated. In fact, I think we are having the same problem with the obfs4proxy binary, which may lose its CAP_NET_BIND_SERVICE capability once the package is updated and the file overwritten. We should fix this.

comment:12 Changed 7 months ago by dcf

I found an obfs4 setup guide by Sindastra that invents another way to work around the problem, using chattr +i to prevent apt from upgrading the systemd files. Some official guidance would help in preventing people from inventing suboptimal workarounds like this, I think.

Now edit the files /lib/systemd/system/tor@default.service and /lib/systemd/system/tor@.service and in both files change NoNewPrivileges=yes to NoNewPrivileges=no and then execute systemctl daemon-reload to apply the changes.

It can happen, that during an update, the Tor service files will be overwritten and the modifications thus removed. This will result in the proxy not functioning on the desired port anymore (if below 1024). This can be fixed by marking the service files as immutable after modification, like this:

sudo chattr +i /lib/systemd/system/tor@default.service
sudo chattr +i /lib/systemd/system/tor@.service
Note: See TracTickets for help on using tickets.