-   Linux - Networking (
-   -   Allowing non-root to bind to ports < 1024? (

MWTJ 08-05-2005 08:07 PM

Allowing non-root to bind to ports < 1024?

Is there a kernel option that would allow any user (not just root) to bind processes to ports < 1024? I know that I can recompile the kernel and change PROT_SOCK in include/net/sock.h, but I'm wondering if there is a way to remove this constraint by changing something in /proc or an IOCTL or any other run-time thing. Suggestions?

I realize that i can use iptables to map port 80 to port 8080, for example, but that doesn't work on the localhost interface.

This is on Suse 9.3, btw.


Matir 08-05-2005 09:07 PM

As far as I know, that's hardcoded. :) Might be possible with some selinux hack, but I'm not aware of that either. Any particular reason the app can't start as root, drop privs, and (if neccessary) fork to a child?

MWTJ 08-05-2005 09:25 PM


Originally posted by Matir
As far as I know, that's hardcoded.
That's what I feared. This has been Unix/Linux's #1 security mis-design for the past twenty years. Someday it will be fixed, I hope.

Might be possible with some selinux hack, but I'm not aware of that either.
I'm almost certain SELinux can do it. It's exactly the kind of thing capabilites are for. You have a capability for each port, and then you take an unprivileged process, and give it just the capability it needs to bind to its port. Then if that process gets OWN3RD the worst thing the intruder can do is take over the website, but the rest of the machine is protected. Regular Linux could do almost the same thing if it would finally get rid of this privileged ports stupidity.

Any particular reason the app can't start as root, drop privs, and (if neccessary) fork to a child?
Yes, there's no setuid() or fork() in Java!

I'm trying to get all this to run from my Ant script. One thing I could do is write a three-line C program which would simply do the fork, etc, and make that C program setuid. But it would be nice to just have a way of turning off this nonsense.

I guess on production machines I could have a home-made secure kernel where I just make the one-line patch to the include/net/sock.h to remove this. From /usr/src/linux-

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK      1024

Changing that one line to

#define PROT_SOCK 0
would do the trick and be the Linux security triumph of the year, I think.

Due to this "security feature" (privileged ports) it means that instead of running my application 100% in a sandbox (the JVM) as an untrusted user (nobody) 100% of the time, I have to start messing around with a less-safe language (C), using "risky" calls (setuid) and running as the system's most privileged user (root) to handle the most dangerous data (raw connections from anyone on the net). If the privileged ports thing weren't so well-established I'm sure it would make a good posting on

Matir 08-05-2005 09:49 PM

Sorry, I didn't know it was in Java. That does pose an interesting set of problems... I agree some sort of capabilities need to be added, but I don't like the full set of SELinux. I wish we could just associate a group with ports<1024 and have it run setgid for that group. So, the worst it could do would be to bind to those ports... big deal. :)

pquiring 08-11-2011 08:56 AM

custom kernel
There is one way of doing this which I'm trying now: build a custom kernel.

You need to edit /include/net/sock.h find and change PROT_SOCK from 1024 to 0.
Then compile and install your own kernel.

Ubuntu has some helpful pages on doing this:


pquiring 08-11-2011 09:40 AM

It works!
Yup, built my own custom kernel, installed it and now tomcat is running on port 80, without using jsvc.
This means other java apps can use port < 1024 (like webapps - you can't start webapps with jsvc).

Here is how I did it:


#install the source and what ever else you need
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

#edit /include/net/sock.h find PROT_SOCK and change from 1024 to 0

#copy config that you are using now
cp -vi /boot/config-`uname -r` .config

#if you want to run menuconfig you need libncurses
apt-get install libncurses5 libncurses5-dev

#run menuconfig if you want (optional)
make menuconfig

#define number threads to use when compiling (should be +1 number cpu cores)
#compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

#wait a long time

cd ..

#install your new images and reboot

dpkg -i linux-image<version>custom.deb
dpkg -i linux-headers<version>custom.deb



Nominal Animal 08-12-2011 10:24 AM

You do not need to rebuild your kernels to achieve this. All you need to do is to add the cap_net_bind capability to both the permitted and effective sets for the actual program file, in your case the Java interpreter. (Actual program file means the final binary, not a symlink or a shell script.)

On say Ubuntu 10.10 using OpenJDK 6 runtime, the command to do that (once) is

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-6-openjdk/jre/bin/java
but obviously any Java program can then bind to any port. I have not tested if using binfmt_misc and marking a specific .jar file works, but it should. Even if it does, everything running in that runtime environment will be able to bind to any port, though.

You will need to have libcap-bin (Debian/Ubuntu) or libcap-progs (OpenSUSE) or libcap (RHEL/Fedora/CentOS) package installed. On some distributions the program is /sbin/setcap but /usr/sbin/setcap in others.

Finally, do note that you have to run the command after updates have been applied, because the capability flags are stored in the file (inode). When rewritten, the capabilities are lost. If you use a service script to run the Java program, you can add the setcap command to the start sequence, before dropping privileges. (Since the service scripts are run with superuser privileges, no sudo is needed, and the script can unconditionally set the capability flag before running the binary.)

pquiring 08-12-2011 10:35 AM

Thanks for that info.

I was trying to understand those CAP_... flags but didn't understand them.

Nominal Animal 08-12-2011 07:06 PM

Well, Linux capability flags describe what a thread or a process is allowed to do. Each flag is pretty well described in man 7 capabilities.

The basic principles are pretty simple:
  • Capabilities are reset whenever a new binary is exec'd.
    Capabilities do not change when a new process is forked or a new thread is started.
  • When a process/thread acquires privileges (changes to root successfully), it gets all capabilities.
  • When a process/thread drops privileges (changes to a non-root user and group), it drops all capabilities.
    (This happens when a real, effective, or filesystem user or group ID changes from zero to non-zero, with all others either set or being set non-zero. In other words, when the "last trace" of superuser privileges is dropped.)
    A process can set the PR_SET_KEEPCAPS control using prctl() to keep capabilities when dropping privileges. It does not affect exec'ing a binary, though, and the control is always unset at exec.

The exact definition of reset (i.e. what happens to capabilities at exec time) is described in the capabilities man page. The rules may be confusing, so only worry about the rules if the typical use case below does not fit your needs.

The main thing to note is that by default, reset means all capabilities are dropped for unprivileged users, i.e. everybody except root; and that you can give unprivileged users exec'ing some binary extra capabilities by adding them to the permitted and effective sets for that binary.

So, the typical use case -- when run as an unprivileged user (non-root), allow the program to do these additional things -- is simple. Just add the desired capability flags to both the effective and permitted sets for that binary, by running either

setcap cap_something=pe binary-file
or, if you want to set multiple capabilities,

setcap "cap_first=pe cap_second=pe cap_third=pe" binary-file
You'll obviously need superuser privileges, so run the command as root or via sudo. Afterwards, whenever that binary-file is exec'd by an unprivileged user, it will have those capabilities and those capabilities only. (If it is exec'd by superuser/root, it will of course have all capabilities.)

This does not work for symbolic links or scripts, however; it only works for actual program binaries. I recommend using first which program to locate the program file, then file /path/to/program to trace the symlink chain and detect possible scripts. You may need to read the scripts to find out where the actual program binary is located.

Note that when upgrading a package, the package manager may replace a binary with a new file. This means that the capability flags are lost. I am not sure which package managers, if any, retain the capability flags. They are rarely used, after all.

You can limit the groups that can a binary with extra capabilities, by copying the binary to a new directory, limiting access to that directory to the desired group only, and then setting the file capabilities as above. This also means you don't need to worry about updates breaking the file capabilities. (If you want to limit access to a specific user, you'd better use POSIX ACLs, with the directory owned by root, and grant access to the user via an ACL. If you let the user own the directory, the user can always replace the binary with something else.)

Hope this helps,

All times are GMT -5. The time now is 03:15 PM.