It\'s very annoying to have this limitation on my development box, when there won\'t ever be any users other than me.
I\'m aware of the standard workarounds, but non
I know this is an old question, but now with recent (>= 4.3) kernels there is finally a good answer to this - ambient capabilities.
The quick answer is to grab a copy of the latest (as-yet-unreleased) version of libcap from git and compile it. Copy the resulting progs/capsh
binary somewhere (/usr/local/bin
is a good choice). Then, as root, start your program with
/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
--inh='cap_net_bind_service' --addamb='cap_net_bind_service' \
-- -c 'your-program'
In order, we are
cap_net_bind_service
capability to the inherited & ambient setsbash -c 'your-command'
(since capsh
automatically starts bash with the arguments after --
)There's a lot going on under the hood here.
Firstly, we are running as root, so by default, we get a full set of capabilities. Included in this is the ability to switch uid & gid with the setuid
and setgid
syscalls. However, ordinarily when a program does this, it loses its set of capabilities - this is so that the old way of dropping root with setuid
still works. The --keep=1
flag tells capsh
to issue the prctl(PR_SET_KEEPCAPS)
syscall, which disables the dropping of capabilities when changing user. The actual changing of users by capsh
happens with the --user
flag, which runs setuid
and setgid
.
The next problem we need to solve is how to set capabilities in a way that carries on after we exec
our children. The capabilities system has always had an 'inherited' set of capabilities, which is " a set of capabilities preserved across an execve(2)" [capabilities(7)]. Whilst this sounds like it solves our problem (just set the cap_net_bind_service
capability to inherited, right?), this actually only applies for privileged processes - and our process is not privileged anymore, because we already changed user (with the --user
flag).
The new ambient capability set works around this problem - it is "a set of capabilities that are preserved across an execve(2) of a program that is not privileged." By putting cap_net_bind_service
in the ambient set, when capsh
exec's our server program, our program will inherit this capability and be able to bind listeners to low ports.
If you're interested to learn more, the capabilities manual page explains this in great detail. Running capsh
through strace
is also very informative!
Okay, thanks to the people who pointed out the capabilities system and CAP_NET_BIND_SERVICE
capability. If you have a recent kernel, it is indeed possible to use this to start a service as non-root but bind low ports. The short answer is that you do:
setcap 'cap_net_bind_service=+ep' /path/to/program
And then anytime program
is executed thereafter it will have the CAP_NET_BIND_SERVICE
capability. setcap
is in the debian package libcap2-bin
.
Now for the caveats:
program
that has elevated privileges like setcap
or suid
. So if your program
uses its own .../lib/
, you might have to look into another option like port forwarding.Resources:
setcap
.Note: RHEL first added this in v6.
Answer at 2015/Sep:
ip6tables now supports IPV6 NAT: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt
You will need kernel 3.7+
Proof:
[09:09:23] root@X:~ ip6tables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 REDIRECT tcp eth0 * ::/0 ::/0 tcp dpt:80 redir ports 8080
0 0 REDIRECT tcp eth0 * ::/0 ::/0 tcp dpt:443 redir ports 1443
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 6148 packets, 534K bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 6148 packets, 534K bytes)
pkts bytes target prot opt in out source destination
File capabilities are not ideal, because they can break after a package update.
The ideal solution, IMHO, should be an ability to create a shell with inheritable CAP_NET_BIND_SERVICE
set.
Here's a somewhat convoluted way to do this:
sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
--caps='cap_net_bind_service+pei' -- \
YOUR_COMMAND_GOES_HERE"
capsh
utility can be found in libcap2-bin package in Debian/Ubuntu distributions. Here's what goes on:
sg
changes effective group ID to that of the daemon user. This is necessary because capsh
leaves GID unchanged and we definitely do not want it.$DAEMONUSER
--keep=1
), except inheritable cap_net_bind_service
The result is a process with specified user and group, and cap_net_bind_service
privileges.
As an example, a line from ejabberd
startup script:
sg $EJABBERDUSER "capsh --keep=1 --uid=`id -u $EJABBERDUSER` --caps='cap_net_bind_service+pei' -- $EJABBERD --noshell -detached"
systemd is a sysvinit replacement which has an option to launch a daemon with specific capabilities. Options Capabilities=, CapabilityBoundingSet= in systemd.exec(5) manpage.
You can do a port redirect. This is what I do for a Silverlight policy server running on a Linux box
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300