1.1 Linux server: http://icculus.org/news/news.php?id=3392
Mac OS X version: http://icculus.org/news/news.php?id=3365
Someone has to explain this to me, because I really don't get it.
Someone tell me again why I can't bind a port below 1024 on Unix if
I'm not root? Is there a good reason in this day and age?
These are the reasons why I suspect the 1024 limit was imposed:
- Don't let users run system-level services on the mainframe.
- Don't let the users hog ports for important services on the mainframe.
- Don't let the users run a bogus service to steal logins on the mainframe.
...and here's why I think these aren't relevant anymore:
- The mainframe is now the desktop. Users can and do run Unix single-user
now. GNU/Linux's popularity has made Unix a viable desktop system, where
anyone can have root. TCP/IP's widespread success means that non-Unix
systems like Windows get full superuser port binding for the desktop
user, too. The original assumption behind the 1024 limit was that you
couldn't have root on any available system, even if you wanted it, since
you didn't own the machine or have physical access to it: the University,
which paid a mortgage for the system, did. This made it an optimistic,
albeit immediately practical, security measure.
- The mainframe isn't even the server any more. Most people aren't using
a shell account on a big Unix system any more. I grant they still exist;
I'm typing this in the nano editor on a ssh connection to icculus.org,
where about 100 other people also have logins...but the fact that this
is a .plan file should demonstrate that I dig anachronism. :) Most
servers are not shell providers. Most people think providing shell
accounts is really crazy in 2006. Most servers have a handful of admins
at most, if they use shell accounts at all instead of a "control panel"
via their web browsers.
- As for preventing the hogging service ports: my thought is that this was
never a good idea. The important services started when the server
started, so if Joe Normal User tried to listen on port 23, the existing
telnet daemon would already have it bound. Furthermore, you're root, you
treat this like someone abusing any system resource you need: if you find
that there's someone using all the system CPU, you kill his process;
similarly, if you want to run an FTP server, and there's already an FTP
server bound by a user, you kill it and start your own.
- As for stealing logins, I refer you again to ubiquitous root access for
everyone, and root access for no one on the servers that matter. Also,
the protocols that matter today have had thought put into locking them
down. Ask anyone that's sent me a panicked email when they see that the
SSL certificate for https://icculus.org/
is owned by the icculus.org
"Ninja Hack Squad" or got OpenSSH's warnings about man-in-the-middle
...and here's why it's a problem:
- There are services that could fall under the arguments protecting ports
less than 1024 that are on higher ports. MySQL and Subversion pop out at
me immediately by scrolling through /etc/services. It's a failed policy,
since there're already more interesting things than there are ports, and
only more things we haven't dreamed of yet to arrive.
- There are services you want to run as an end user on your desktop system
that you don't want to run as root! If I want to use ssh forwarding on
my desktop Linux box, I can't, unless I bounce off a high port first,
and hope everything in the system handles that well. If I want to run
Apache for something on localhost, I have to pick a non-standard port
and explicitly specify it in Firefox (and hope the web server generates
links with the non-standard port!). My other option may be to run
something not-well-trusted under "sudo" when it otherwise didn't need
root access and doesn't behave well about dropping privs after binding
a low port.
- The world has chosen the web. Lots of stuff spits out HTML instead of
targeting a GUI widget toolkit. Lots of stuff found PHP and Perl and
Ruby to be clean ways to get cross-platform, multi-user apps written
quickly, and lots of stuff found that running in one place but being
accessible to many places made a lot of sense, even if they aren't
Apache proper. A good example is Unreal Tournament's WebAdmin...you
can control the game remotely from a web interface. I don't want to
run a closed source binary as root just to bind port 80 (and heck, I
even have the source code to this one!)...there's no other reason to
run the app as root.
Fortunately, it's easy enough to fix. Just chop these lines out of
linux-22.214.171.124/net/ipv4/af_inet.c, around line 433:
err = -EACCES;
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
...now someone send Linus flowers and chocolates and get that changed in
the mainline kernel. :)
(ok, there's a capability bit, as you might notice with the capable()
call up there. I just think it's not worth having at all. Also, you're
out of luck on other Unixes, I imagine, such as Mac OS X. Also,
OpenSSH has binding of low ports as non-root disabled always. It's
hardcoded in the source for most platforms. It's just flatly forbidden
instead of simply testing if bind() failed.)