Linux capabilities 101
Even seasoned Linux administrators may not be very aware of Linux capabilities. Still, they are used a lot and apply to most systems. This feature was added to Linux 2.2 kernel and gave us new possibilities regarding security. In this guide, we have an in-depth look how can leverage them.
What are Linux capabilities?
Linux capabilities divide the privileges of the superuser into smaller and distinctive units. These units can then be independently be applied to processes, to give them a subset of the available privileges. This way the number of privileges is reduced, helping to make services more secure.
To better understand how Linux capabilities work, let’s have a look at the problem they solve.
Let’s assume we are running a process as a normal user. This means we are non-privileged and can only access data owned by us, our group, or can be accessed by all users.
At some point in time, our process needs a little bit more permissions to fulfill its duties, like opening a network socket. The problem is that normal users can not open a socket, as this require root permissions.
One of the solutions is to allow some permissions (by default) to all users. There is a serious flaw in this approach. Allowing this kind of permissions, for all users, would open up the system for a flood of system abuse. The reason is that every small opportunity is being used for good, but also for bad. Giving away too many privileges by default will result in unauthorized changes of data, backdoors and circumventing access controls, just to name a few.
So the kernel developers had to come up with another solution and they named it capabilities.
Capabilities can be compared with privileges. Normally the root user (or any ID with uid of 0) gets an exceptional treatment when running processes. The kernel and applications are usually programmed to skip the restriction of some activities when seeing this user ID. In other words, this user is allowed to do (almost) anything.
Capabilities are created to drop (some) permissions of root
With capabilities, we have the access to distinct small units with specific rights. This way we don’t have to hand out full root permissions to some processes.
For example, a web server normally runs at port 80. To start listening on one of the lower ports (<1024), you need root permissions. Now this web server daemon needs to be able to listen to port 80, however it does not need access to kernel modules (that would be a serious threat to the integrity of the system!). Instead of giving this daemon all root permissions, we can set a capability on the related binary, like CAP_NET_BIND_SERVICE. With this specific capability, it can open up port 80 (and 443 for HTTPS) and listen to it, as intended.
“Capabilities is a way of splitting up root permissions”
Linux capabilities are defined in a header file with the non-surprising name capability.h.
If you ever changed the owner of a file, you will be familiar with the chown command. This capability provides the privilege to do this. It allows changing both the owner as the group. Good to know is that this only applies when _POSIX_CHOWN_RESTRICTED is active, which is true on most Linux systems. By using the getconf command we can validate this.
getconf -a | grep _POSIX_CHOWN_RESTRICTED
Binaries with setuid bit
Capabilities are a great way to replace binaries with the setuid bit set. This special bit gives users full root permissions under the context of that process. As you can imagine, if the program contains a flaw, the non-privileged user can “break out” and become the equivalent of the root user.
Still many Linux distributions use the setuid on several binaries, while capabilities can replace the bit.
Capabilities are a great way to split up root permissions and hand out some permissions to non-privileged users. Unfortunately, still many binaries have the setuid bit set, while they should be replaced with capabilities instead.
Related article: Linux Capabilities: Hardening Linux binaries by removing setuid