On Linux, traditionally, a process could either run as root, and so have limitless access to the system, or as a non-root user, subject to a set of restrictions. Since version 2.2 of the kernel, capabilities were introduced as a way to grant permissions in a more granular way.
In this tutorial we learn what are the three main capabilities sets which can be associated to executables on Linux, and how to list, add and remove capabilities using the getpcap and setcap utilities.
In this tutorial you will learn:
- What are the capability sets which can be associated to files
- How to list the capabilities assigned to an executable or a process
- How to set and remove capabilities from an executable
|Category||Requirements, Conventions or Software Version Used|
|Other||Root privileges to change the capabilities of an executable|
|Conventions||# – requires given linux-commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux-commands to be executed as a regular non-privileged user
Capabilities were introduced on Linux to allow assigning privileges to processes in a granular way, overcoming the traditional binary root/non-root distinction. Just as by using sudo we can run specific commands as another user (even root), without permanently becoming that user, by using capabilities, we can grant a process only certain privileges without having to run it as root.
We saw a real-world example of what capabilities can be used for in a recent tutorial about allowing rootless docker containers bind to privileged system ports: one of the solutions proposed in the article, consisted into assigning the CAP_NET_BIND_SERVICE capability to the rootlesskit binary. CAP_NET_BIND_SERVICE is just one of the capabilities which can be used on Linux: the complete list can be found in the dedicated manual page.
Capability sets: Permitted, Effective and Inheritable
On Linux, there are five capability sets: Permitted, Inheritable, Effective, Bounding and Ambient. Of those, however, only the first three can be assigned to executable files. The Permitted capability set includes the capabilities assigned to a certain executable; the Effective set is a subset of the Permitted one and includes the capabilities which are effectively used. Finally, the Inheritable set, includes capabilities which can be inherited by child processes.
Checking the capabilities of an executable or a process
To check the capabilities assigned to an executable, we use
getcap, which comes installed by default in all the major Linux distributions. This utility, together with its companion
setcap is part of the “libcap2-bin” package on Debian-based distributions, and of the “libcap-2” package on Fedora-based systems.
Let’s see an example of how to check the capabilities assigned to an executable. Clockdiff is a program used to measure clock differences between hosts. To list the capabilities assigned to it, we run:
$ getcap /usr/bin/clockdiff
On the latest version of Fedora, the command above returns:
The Permitted, Effective and Inheritable capability sets, are referenced by the “p”, “e”, and “i” flags, respectively. As we can see above, the
/usr/bin/clockdiff executable has the CAP_NET_RAW capability in the Permitted set.
If we don’t know what executables have special capabilities assigned, we can invoke the
getcap utility with the
-r option, which enables recursive search on the path passed as argument. The command below checks the entire system:
$ sudo getcap -r /
To list the capabilities assigned to a running process, we use another utility:
getpcaps. We simply pass the PIDs of the processes we want to examine as argument:
$ getpcaps 44448
To assign capabilities to an executable we use the
setcap utility. We provide the comma-separated list of the capabilities we want to assign, and we associate them to the flags which reference the capability sets, via one of the available operators:
Let’s see an example. Suppose we want to add the CAP_NET_BIND_SERVICE capability to the
/usr/bin/rootlesskit binary, both in the permitted and effective set. We run:
$ sudo setcap cap_net_bind_service=pe /usr/bin/rootlesskit
In the example above, we assigned the CAP_NET_BIND_SERVICE capability to the Permitted (p) and Effective (e) sets, by using the
= operator. This operator first removes the listed capabilities from all the capability sets, then adds them to those we specify in the command.
Multiple space-separated “clauses” can be specified in a single command, to add different capabilities in different sets. Just as an example, to specify we want to add the CAP_NET_BIND_SERVICE capability to the Permitted, Effective and Inheritable sets, and the CAP_NET_RAW capability only to the Permitted and Effective sets of the rootlesskit binary, we would run:
$ sudo setcap "cap_net_bind_service=pei cap_net_raw=ep" /usr/bin/rootlesskit
If we use the
= operator but don’t explicitly specify any capability, the command affects all of them. So, to add all capabilities to the Permitted and Effective sets of an executable, we would run:
$ sudo setcap =pe /path/to/executable
By the same logic, to empty all the capabilities sets of an executable, we would run:
$ sudo setcap = /path/to/executable
- operators explicitly require both a capability list and one or more capability sets flags to be provided. The former is used to include the specified capabilities in the provided capability sets, the latter is used to remove them. In the example below, we add the CAP_NET_BIND_SERVICE capability to the permitted and effective sets of an executable, and we explicitly ensure it is not present in the Inheritable set:
$ sudo setcap cap_net_bind_service+ep-i /path/to/executable
Here is another example. This time we add all capabilities in the Permitted and Effective sets of an executable, except for the CAP_CHOWN capability:
$ sudo setcap "all+pe cap_chown-pe" /path/to/executable
To remove all the capabilities assigned to an executable, we launch
setcap with the
-r option, and pass the path of the file as argument:
$ sudo setcap -r /path/to/executable
Each time we use the
setcap utility on an executable, its current capabilities set are “destroyed” and the new one processed, therefore we cannot, for example, just add certain capabilities in addition to the ones currently set. We should always specify the entire list of capabilities of the executable each time we invoke the utility.
In this tutorial we talked about Linux capabilities, which can be used to grant fine-grained permissions to Linux processes. We saw what are the three main sets a capability can be assigned to and how to list and modify the capabilities assigned to an executable. To know more about capabilities, you can take a look at the capabilities(7) manual page.