Capabilities allow the evaluation of some important system privileges in a separate thread different from the current process. This way, you don’t need to run a program as root for it to access certain parts of the system.
As a solution arising from needs, section 25 of POSIX.1e is about this issue. The development of the privileges defined in that section and more has been completed with the release of Linux kernel version 2.6.26. Here’s everything you need to know about capabilities in the Linux kernel.
Understanding the Capabilities API Logic
Authorization control in Unix-based systems consists of two steps:
- If the current owner (effective user ID, EUID) of the running application is zero, then the system doesn’t check for authorization
- If the EUID value is different from zero, the system performs the control process in line with the authorizations of the effective user and group of the relevant application
Some applications need to have wider privileges (SUID, SGIT bits) while running. As the most typical example, you can think of the passwd application. With this, users in a system can change their passwords. However, to write to the /etc/shadow file, where the encrypted passwords are kept, it is necessary to work with root user rights (i.e. user ID = 0).
To solve this problem, the passwd application has a SUID bit. Whichever user runs this application, the active owner (EUID) will always be root:
ls -l /usr/bin/passwd
-rwsr-xr-x. 1 root root 32552 Jul 23 2021 /usr/bin/passwd
The ability to run SUID applications in the traditional Unix authentication model seems to have solved the problem. However, critical errors in applications with SUID bits open the door to running unwanted codes for users with full authority in the system. An ideal application should be able to run without needing root user rights if possible.
The problem does not end with just the SUID bit. You must also have root user rights when you want to listen on a privileged TCP or UDP port less than 1024 on Unix-based systems. For example, to be able to listen to the TCP 80 port of a web server, you must run the application as the root user.
Over the years, it has been understood how devastating it is to run software that provide service to the network environment with a fully authorized user account. As an interim solution, it was adopted that only a certain and smaller part of the program listens on the privileged port as root, and then changes the active user ID to another user for subsequent processes (for example, the nobody user with restricted rights).
This system, which has been used for years, has worked well with its simplicity and is still used efficiently. However, nowadays, it is possible to get some additional capabilities, specific to the application, via the Linux capabilities API, without the need for root rights, apart from the above-mentioned system.
The Linux Capability Model, Explained!
You can find the most comprehensive implementation of the capabilities API in the Linux kernel. Modern Linux distributions also try to use this new model system-wide as much as possible.
For example, for the ping application to work, it must be able to open RAW sockets, which are generally reserved for root users only. In old Linux distributions, the problem is to give the SUID bit to the application so that normal users can use it. In these versions, when you remove the SUID bit from the application and try to run the application as a normal user, you get the following error:
ping: icmp open socket: Operation not permitted
Whereas on modern Linux distributions, the ping application probably does not have the SUID bit:
ls -l /bin/ping
-rwxr-xr-x. 1 root root 95232 Jul 25 2021 /bin/ping
Nevertheless, you can run the application successfully as a normal user. The mechanism that makes this possible is that the ping application has the special ability CAP_NET_RAW.
You can learn the additional capabilities of the application with the getcap command as follows:
sudo getcap /bin/ping
If the getcap command returns an empty response, you can manually set this value with:
sudo setcap cap_net_raw+ep /bin/ping
The Process Capability Model
In Linux implementation, the capabilities of each process are grouped under three headings:
|permitted||In this cluster, there is a list of allowed additional capabilities for the relevant process. Granting permission doesn’t mean that it can be used actively at that time. It is possible to include the authorizations here in the effective capability set with an additional action.|
|effective||It shows the currently active capability list of the related process. With the auxiliary functions that regulate the skill system, it is possible to give up or regain a skill. In any case, however, this can only be done among those already authorized in the permitted group.|
|inheritable||When an application starts a new process, the newly started process displays the list of capabilities it will inherit from the allowed list.|
The list of permitted, effective, and inheritable capabilities for running processes at any time is displayed as bitmask on the lines CapPrm, CapEff, and CapInh in the file /proc/<PID>/status. In addition, the CapBnd line contains the bitmask used in the capability boundary control operation.
For example, try reading the values of your running shell application from the /proc/self/status file:
cat /proc/self/status | grep Cap
The File Capability Model in Linux
The operation of the capability system for files depends on the prerequisite that these properties can be stored in the virtual file system (VFS) layer. Similar to the process model, capabilities for files fall under three headings:
The system determines the permitted capabilities of the process when the corresponding executable runs in this cluster.
Unlike the process capability model, this header stores one bit only: active or inactive. If the bit is active, the capabilities defined in the permitted list of the file are automatically transferred to the effective capability list of the relevant process when this file is run and a process is created. If the bit is not active, the automatic transfer of the permitted capabilities on the file to the running process is not performed.
However, if the code of the relevant application is integrated with the capability system, it can activate the permissions in the permitted set of the file with system calls. The main purpose of this behavior is to ensure that old applications that do not include capability system-specific code, development at the software code level can work with the capability system without the need for any source code changes.
You might think that better-written applications will only use capabilities when needed. If the bit is active, all capabilities in the allowed list become active when the application starts.
As in the process model, the relevant file runs and a process occurs. If another application runs from within the process after that, it is included in the allowed list of the new process. To sum up, it indicates a list of capabilities to inherit.
The Role of Capabilities in a Linux System
When you run a certain process as a normal user, you do not have any privileges. As a result, you can only access the partitions that the system allows for normal users. The main reason behind this is to tighten system security and implement such measures.
Allowing all users to access all resources can create a serious security vulnerability. It will be very easy for people who use the system for malicious purposes to exploit system vulnerabilities. Linux capabilities come in handy in such matters. You can easily strengthen the security of your applications with capabilities API powered by the kernel.
Linux capabilities are just one of the issues that need to be thought about to do very powerful methods such as dividing the root user’s permissions, assigning various permissions to non-privileged users, and taking various precautions about open ports in internet services with Linux servers.
Improve Your Linux Server Security With These 7 Hardening Steps