Run Your Applications with Necessary Privileges: Linux Capabilities

I’ve realized that setuid is still a common approach to allow normal users to run a process with the root privileges. However, setuid comes with a lot of security issues.

There are a couple of different security modules in the Linux Kernel: SELinux, AppArmor, Seccomp, Tomoyo, Smack, Capabilities etc.

In this post, I’d like to talk about the Capabilities module of the Linux Kernel.

The root user (the effective user ID is zero) has no restrictions in the Linux Kernel. That user can do anything in Linux. However, we may need to allow a normal user to do some things that only the root user can.

You probably know, normal users can not listen to port numbers below 1024. They are privileged ports. You should have root privileges to listen to a port that is below 1024.

Let’s assume you have an application on the port 80. You run your application with the root user to allow your application to run on the port 80.

If your application is compromised you may face unintended consequences, because your application is running with the root user.

So, we need something that allows us to use some privileges of the root user not all of the privileges. That’s what the Capabilites module does.

Image for post
Image for post
Photo by Dimitri Houtteman on Unsplash

The POSIX Capabilites defined in POSIX 1003.1e Draft 17 (October 1997). Although it is withdrawn, Linux implements some parts of POSIX 1003.1e in the Capabilities module.

You can see implemented capabilities here.

The Linux Kernel checks your privilege with if (capable(…))

The Linux Kernel checks the user’s privileges before executing a syscall. The Linux Kernel does something like this:

The Linux Kernel doesn’t check the user’s privileges before executing some syscalls, which are part of vDSO. Everyone can execute gettimeofday :)
However, settimeofday is not a part of vDSO. Therefore, you must have CAP_SYS_TIME privilege.

How to Run Netcat (on the Port 80) and iftop Without Switching to Root User?

My console output is:

The nc command must have CAP_NET_BIND_SERVICE privilege. The iftop command must have CAP_NET_RAW. The details are here.

Let’s do it:

The example user can run the nc command on the port 80. The example user can also run iftop.

Let’s assume the nc command has a security flaw. An attacker can’t access the privileged parts of the server since the nc command doesn’t run with the root user.

What does +ep stand for?

Things get complicated. Please fasten your seatbelts.

Each thread, process, task (whatever you say) can have a few different capability sets: Permitted (P), Inheritable (I), Effective (E), Bounding, Ambient.

Each file can have a few different capability sets: Permitted (P), Inheritable (I), Effective (E).

Permitted: The capabilities that the task (thread, process) can have.
Inheritable: The capabilities that are going to be preserved in the child processes.
Effective: The capabilities that are checked by the Linux Kernel whether they are ‘effective’ or not.
Bounding: The capabilities that are available to be using.

Let’s make some analogies

Analogy #1

You have dual citizenship: US/UK. You are living in the US now.
So, you are permitted to enter the US and the UK. You are effectively living in the US now.

Analogy #2

You are a citizen of Turkey. Your dad has dual citizenship: Turkey/Australia. So, you can be a citizen of Australia (inheritable) since your dad is a citizen of Australia. You can effectively live in Australia since your citizenship was inherited from your dad.

Analogy #3

Let’s say there are 3 countries in the world: A, B and C. Your boundaries are A, B and C. If another country is discovered, then you can expand your boundary. (bounding). It is like adding new privilege to the Linux Kernel.

Let’s go back to the beginning

We set the capability. So, the normal users are permitted to run the iftop command effectively with the cap_net_raw privilege.

Hey, all users can run iftop now. I want to allow only the test1 user run the iftop command.

There is a PAM module, which is called pam_cap. You can set the capabilities per user.

The pam_cap module is loaded by default in the latest Linux distros. You can check if it is loaded: grep pam_cap /etc/pam.d/*

If it is not loaded in your current operating system:

You should install libcap

Then, load the pam_cap module manually. Add auth required pam_cap.so to /etc/pam.d/login

Your pam_cap module is loaded.

Then, you should edit your /etc/security/capability.conf

Add cap_net_raw test1 to /etc/security/capability.conf. That line must be above none *

Then run this command:

Please notice that we used +ie not +ep.
So, the test1 user will inherit the cap_net_raw privilege to run the iftop command effectively.

Let’s test it:

Some additional commands that are related to the Capabilities module:

capsh —-print : You can check the current privileges of the user. You should see something like Current: = cap_net_raw+i when you run this command while logged in the test1 user.

getpcaps $PID : Get the privileges of the process.
E.g.: getpcaps $(pgrep iftop)
getpcaps $$
-> $$ returns the PID of current shell.

pscap: List all processes with their privileges.

grep Cap /proc/PID/status : You can see the process’ capabilities in hexadecimal format.

Sample output:

Let’s decode it:

getcap -r / 2>/dev/null : You can find the executable files that have special privileges in your operating system. It is good for the security checks.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store