Hacker News new | ask | show | jobs
by simoncion 3752 days ago
> Most people agree that the Unix privilege model is a hold-over from an older time. Concepts like “binding to a lower port requires root” are warts of the original design of Unix.

...no. Privileged ports are a way to prevent an unprivileged user from turning a service crash into a service takeover.

Windows Firewall seems to sort of mitigate this by only permitting a given program to communicate on a port, but -from what my testing revealed- it does not prevent other programs from _binding_ to that port. So, I strongly suspect that on Windows systems, an unprivileged user can turn a service crash into a service DoS by racing to bind to the service's port.

4 comments

> ...no. Privileged ports are a way to prevent an unprivileged user from turning a service crash into a service takeover.

Whilst privileged ports are indeed used for that purpose, that doesn't mean they aren't a wart.

There's no necessary technical reason why unprivileged users can't bind to port 80, except that the designers of the network API decided to equate successfully binding to a port with having permission to receive connection requests for that port.

This leads to unpleasant situations like a web server having to run as root, even if (usually) only temporarily, solely because it needs to bind port 80.

This makes less sense especially with Docker, since even if a containerized web server binds to port 80, it won't receive connections from the outside world unless the container is configured to forward the "real" port 80 to it.

This leads to unpleasant situations like a web server having to run as root, even if (usually) only temporarily, solely because it needs to bind port 80.

not on modern linux. see CAP_NET_BIND_SERVICE in `man 7 capabilities`.

To add to that: privileged ports are hugely useful from a security point of view for outside observers, especially with regards to setting up a trust relationship. letsencrypt would not work if it could not rely on this.
But privileged ports are too course -- I might want to let a program onto port 80, but give it no other access above 'nobody'. Alternatively, I might want to promise a particular user they can have port 3000, and if their program crashes, no-one else can sneak in and grab it off them.
> But privileged ports are too course...

I agree that there are situations that not-infrequently arise that require additional IP port access restrictions. However, do you agree that removing the notion of privileged ports [0] would

1) Not give you the more-fine grained access restrictions that you're looking for

2) Actually weaken security on Linux systems

? (Additionally, GRSecurity, SELinux, and -apparently- AppArmor all appear to provide the finer-grained control that you're looking for. There is also this [1] which lets you do something like what Windows Firewall does and use iptables to restrict which uid/gids can do certain types of IP communication.)

[0] That is to say, remove the restriction that one must run as root to bind to ports < 1024.

[1] https://www.debian-administration.org/article/120/Applicatio... [2]

[2] Even though the kconfig option has changed names, it appears to serve the same function (see the Owner section of [3])

[3] http://ipset.netfilter.org/iptables-extensions.man.html

> I agree that there are situations that not-infrequently arise that require additional IP port access restrictions.

They arise quite frequently if you're running non-standard network services.

I have a service that I don't want to run as a root user, even temporarily, and therefore it needs to bind to a non-privileged port. In principle, another service could bind to the same port if it goes down.

> However, do you agree that removing the notion of privileged ports...

I'm not convinced people are suggesting only removing the privileged port restriction, but rather replacing it with something more flexible.

Just being able to lock ports down to a uid would suffice for many use cases and could work the same way as the legacy system by default, with ports <1024 reserved for root and other ports not reserved. Then, e.g.

# echo "8080 <MYUID>" > /proc/sys/net/ipv4/conf/all/portsec/register

and no-one but me can bind to 8080 on any interface.

Of course there are more extensive proposed solutions, but this would solve every problem I've ever had with binding to a privileged (or not) port.

> There is also this which lets you do something like what Windows Firewall does and use iptables to restrict which uid/gids can do certain types of IP communication

That's only a solution if I can bind to the port in the first place, and in a way that doesn't open me up to having my port hijacked by some other process, like on Windows.

>Just being able to lock ports down to a uid would suffice for many use cases and could work the same way as the legacy system by default, with ports <1024 reserved for root and other ports not reserved. Then, e.g. # echo "8080 <MYUID>" > /proc/sys/net/ipv4/conf/all/portsec/register

It can be done in userspace with `authbind` (based on some LD_PRELOAD magic).

    # apt-get install authbind
    # echo '0.0.0.0,8080-8081' >> /etc/authbind/byuid/$(id -u $TARGETUSER)
Then as user:

    $ authbind my-daemon
To be clear, what I meant was that the binary privilege model of Unix is a wart when you consider that it groups vastly different operations together. Capabilities are a step in the right direction, but you still have CAP_SYS_ADMIN.