views:

5477

answers:

9

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 none of them do exactly what I want:

  1. authbind (The version in Debian testing, 1.0, only supports IPv4)
  2. Using the iptables REDIRECT target to redirect a low port to a high port (the "nat" table is not yet implemented for ip6tables, the IPv6 version of iptables)
  3. sudo (Running as root is what I'm trying to avoid)
  4. SELinux (or similar). (This is just my dev box, I don't want to introduce a lot of extra complexity.)

So is there some simple sysctl variable for this, or am I just out of luck?

EDIT: In some cases, you can use capabilities to do this.

+11  A: 

The standard way is to make them "setuid" so that they start up as root, and then they throw away that root privilege as soon as they've bound to the port but before they start accepting connections to it. You can see good examples of that in the source code for Apache and INN. I'm told that Lighttpd is another good example.

Another example is Postfix, which uses multiple daemons that communicate through pipes, and only one or two of them (which do very little except accept or emit bytes) run as root and the rest run at a lower privilege.

Paul Tomblin
A: 

Or patch your kernel and remove the check.

(Option of last resort, not recommended).

Joshua
A Very Bad Idea for a multitude of reasons.
Adam Lassek
+2  A: 

Linux supports capabilities to support more fine-grained permissions than just "this application is run as root". One of those capabilities is CAP_NET_BIND_SERVICE which is about binding to a privileged port (<1024).

Unfortunately I don't know how to exploit that to run an application as non-root while still giving it CAP_NET_BIND_SERVICE (probably using setcap, but there's bound to be an existing solution for this).

Joachim Sauer
+17  A: 

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:

  1. You will need at least a 2.6.24 kernel
  2. This won't work if your file is a script. (ie, uses a #! line to launch an interpreter). In this case, as far I as understand, you'd have to apply the capability to the interpreter executable itself, which of course is a security nightmare, since any program using that interpreter will have the capability. I wasn't able to find any clean, easy way to work around this problem.

Resources:

Jason Creighton
I think you should add a bit of discussion of the setuid and inetd/xinetd options, and make this the accepted answer.
Paul Tomblin
As for #2, I did find a way to deal with it. The interperter is a CAP-loader that is suid-root and interprets the CAP-flags on its target file. Clean, effective, but hard.
Joshua
Partial workaround for scripts: create a copy of the interpreter (e.g. bash), give it the capablities but restrict access to the copy to those users who need it. Of course, those users must be trusted, but they could change the script anyway.
ammoQ
Aside from the aforementioned debian (binary) package, the developer's site is http://www.friedhoff.org/posixfilecaps.html associated papers/presentations/etc...
RandomNickName42
+4  A: 

Two other simple possibilities:

There is an old (unfashionable) solution to the "a daemon that binds on a low port and hands control to your daemon". It's called inetd (or xinetd). The cons are:

  • your daemon needs to talk on stdin/stdout (if you don't control the daemon -- if you don't have the source -- then this is perhaps a showstopper, although some services may have an inetd-compatibility flag)
  • a new daemon process is forked for every connection
  • it's one extra link in the chain

Pros:

  • available on any old UNIX
  • once your sysadmin has set up the config, you're good to go about your development (when you re-build your daemon, might you lose setcap capabilities? And then you'll have to go back to your admin "please sir...")
  • daemon doesn't have to worry about that networking stuff, just has to talk on stdin/stdout
  • can configure to execute your daemon as a non-root user, as requested

Another alternative: a hacked-up proxy (netcat or even something more robust) from the privileged port to some arbitrary high-numbered port where you can run your target daemon. (Netcat is obviously not a production solution, but "just my dev box", right?). This way you could continue to use a network-capable version of your server, would only need root/sudo to start proxy (at boot), wouldn't be relying on complex/potentially fragile capabilities.

Martin Carpenter
Good suggestion. For some reason I didn't even think of using inetd. Except that the service in question is UDP-based, so it's slightly more complicated than TCP services. I have a solution working right now with setcap, but I'll have to give this some thought.
Jason Creighton
A: 

tried to use setcap for java executable (Ubuntu Jaunty 9.04 kernel 2.6.28-11-generic). After setting capability on java executable (does nto work on symbolic links, only on real binary) started java process, but it failed with the following error:

/usr/bin/java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directory

With sudo java process works just fine. To see what gives I ran java process with strace to see the difference between sudo and plain case. Here is the difference I located:

without sudo: open("$ORIGIN/../jre/lib/i386/jli/libjli.so", O_RDONLY) = -1 ENOENT (No such file or directory)

with sudo: open("/usr/lib/jvm/java-6-sun-1.6.0.13/jre/bin/../lib/i386/jli/libjli.so", O_RDONLY) = 3

Did not find $ORIGIN environment variable defined anywhere. Googgled for 3 hours - no luck. Can anybody help?

Gene Vayngrib
A: 

My "standard workaround" uses socat as the user-space redirector:

socat tcp6-listen:80,fork tcp6:8080

Beware that this won't scale, forking is expensive but it's the way socat works.

Astro
+1  A: 

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
FlappySocks
A: 

@Gene Vayngrib: See this page about the potential cause of the libjli.so linker complaint: http://osdir.com/ml/debian-bugs-rc/2009-10/msg00054.html I'm seeing the problem on Fedora 11, with the Sun JDK 1.6.0_18, where /proc is mounted just fine, so it doesn't look like that's the problem on my box. I have not tried other JDKs in that installation yet.

jasonbrittain
The reason that capabilities don't seem to work with Java is that the Sun JDK apparently does not support Linux capabilities. I just filed a new JDK bug report on this, here:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6919633
jasonbrittain