Debugging why ping was Broken in Docker Images
cyphar.com> 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.
> ...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])
> 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).
Then as user:# apt-get install authbind # echo '0.0.0.0,8080-8081' >> /etc/authbind/byuid/$(id -u $TARGETUSER)$ 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.
I see this all the time when dist-upgrading a root-on-NFS debian machine; there's always an error message about how setcap'ing the ping binary fails and then it falls back to setting the suid bit.
Oh no thats not all... Linux also has had a way to allow non root users to do ping, using `socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP)`, which would get around the whole suid/capabilities approach to ping. That was the whole reason why it was introduced, and it can just do ICMP not generic raw sockets like CAP_NET_RAW (which lets you spoof any traffic), and avoids suid root binaries. Unfortunately you have to explicitly enable it (and there was at least one security issue in that implementation too), with net.ipv4.ping_group_range (or ipv6).
I didn't know that. But I guess the reason why it's not just implemented that way by default is so it can be easily ported (even if all kernels supported it, relying on the kernel implementation of ICMP packets might cause inconsistencies you wouldn't see in raw sockets).
It is the same interface, and I believe all the implementations are compatible with it, it just filters the types of raw packets you are allowed to create.
>One of these historical warts is that the creation of raw sockets, which is how ping sends ICMP packets, requires root.
It's a good thing raw sockets require root. Raw sockets are incredibly powerful tools that can be used for all sorts of mischief (including source address spoofing in case of udp, so perfect for various dos attacks)
It's a feature if some clueless user that just downloaded some Trojan flash player update can't fire off a DNS reflection attack against a third party
> In May 2001, a well-known CEO of a security and consulting company, Steve Gibson, released the Raw Socket's warning. According to his Web site, Raw Sockets was a "seriously dumb idea...from Microsoft" that "...spells catastrophe for the integrity of the Internet."
I'd argue that that is much worse to allow writing to any file, reading any file, reading raw memory, etc. These are also things you can do with root. Raw sockets (in comparison) are much less bad. Binding to low ports I think post people agree is a much more obvious wart.