Fine-tuning security with File POSIX Capabilities

Very Capable


If you don't want to give away root access to any program that needs an extra privilege, use POSIX Capabilities instead of "s" bits.

By Ralf Spenneberg

Aleksei Vasileika, Fotolia

Linux always runs processes under the user account that launches the program. This means that the user's privileges apply for all of the program's actions. This tried-and-trusted model has stood the test of time for 35 years; Linux simply adopted it from Unix. However, this simple model does not work in all cases - for example, if a user needs to change a password. The password is stored in /etc/passwd or /etc/shadow; neither file is writable for normal users, and only /etc/passwd is readable. Global write permissions for these files would be fatal because they would allow any user and any application to change any password.

To resolve the dilemma, Dennis Ritchie, one of the fathers of Unix, invented the SUID bit. Bell Laboratories applied for a patent back in 1973, and it was granted as 4135240 in 1979 [1] before being released to the public domain. The SUID bit lets a user spawn a process that exercises the privileges of the file owner (i.e., of another user; see the "Understanding SUID" box).

A Linux system will not work without SUID programs. As long as every single s-bit program is designed and programmed in a secure way, s bits are a blessing. At the same time, the s bit constitutes a considerable risk: A single error in an s-bit program can be all it takes for normal users to escalate their privileges and gain root. As privileged processes, SUID root programs will pass any authorization check. But in fact, most applications do not need all the privileges the root account gives them.

For many years, Unix vendors have looked into alternatives to blindly trusting programs. This quest has resulted in capabilities that individually define the privileges a process is permitted to have. Even draft standards, such as POSIX.6 and later POSIX 1003.1e, have been forwarded. After 13 years of committee work, IEEE ditched the draft in 1998 [2]. This episode in history lives on today in Access Control Lists (ACLs) and another arguably more powerful technique known as POSIX Capabilities (PCaps).

Although ACLs have been available to Linux users for some time, a practical approach to working with PCaps has proved illusive until recently. New tools and some renewed attention to old tools have put PCaps back in the spotlight.

Understanding SUID

For an example of the SUID bit at work, consider Fedora 8's password program, which has the following permissions:

-rwsr-xr-x 1 root root 25604 5. Apr 2007 /usr/bin/passwd

The program file is owned by root and the SUID bit is set, as you can see from the s instead of the x in the fourth position. Thanks to the s bit, the resulting passwd process has the effective permissions (effective UID) of the root user (i.e., of the program file's owner). At the same time, the permissions of the actual user (real UID) are kept. A saved UID lets the process switch between these privileges at any time. If the user ralf calls the passwd command, you can view the permissions by calling ps -o cmd,pid,ppid,euser,ruser, -U ralf:

CMD     PID   PPID  USER  RUSER
-bash    2851  2848  ralf  ralf
passwd  2912  2851  root  ralf

This output reveals that the user ralf is logged in and that this user owns the -bash login shell and issued the passwd command. The command is running with the real UID (ruser) ralf and the effective UID (euser) root. The passwd tool could theoretically use any of root's privileges to change other people's passwords or to shut down the firewall, but assuming the programming is okay, passwd wouldn't dream of doing anything apart from changing the calling user'`s password. To mitigate the risk, Linux distributors have reduced the use of SUID bits in recent years.

Split Root

Ever since kernel 2.2 or - to be more precise - the 2.1 developer cycle, Linux has split root privileges into discrete capabilities that a process can exercise. Linux refers to these as Linux POSIX Capabilities, or PCaps, whereas Solaris simply calls them privileges. On Linux, a process can even enable PCaps for individual sections of code (by flagging them as effective) or disabling them as required. This means that bugs in other parts of the code can't use them. Table 1, the capabilities(7) man page, and the comments in the /usr/include/sys/capability.h header or in the kernel sources in /usr/src/linux/include/linux/capability.h list capabilities on Linux.

Setting Limits

From an administrative point of view, PCaps used to be available globally via the /proc/sys/kernel/cap-bound interface. This allowed the administrator to withdraw capabilities globally on a running system, and it took a reboot to restore them. Without CAP_SYS_MODULE, for example, it is impossible to load kernel modules, and without CAP_SYS_BOOT, a graceful reboot is disabled.

Programs from the libcap1 package [3] allowed the administrator to set capabilities for running processes. Complex MAC systems such as App Armor and SELinux provide a means of changing the capabilities of processes. But if you are looking to assign just the required capabilities, rather than full root privileges, to programs such as ping, passwd, and mount, you would probably prefer a far simpler tool than something that drops a completely new access control model into your system. What Linux has lacked thus far was a practical approach to assigning the required privileges (in the form of PCaps) to a program up front, in a similarly easy way as setting the s bit on the filesystem. Unfortunately, the kernel lacked the infrastructure to handle this.

Many previous patches for the Linux kernel have introduced this functionality ([4] [5] [6]). A patch by Serge E. Hallyn [4] has now finally removed all the obstacles and made the Linux 2.6.24 kernel. Userspace tools for displaying and setting PCaps were also missing, but now Andrew Morgan and KaiGai Kohei have stepped in to fill this gap.

Userspace Controls

Many years ago, Andrew Morgan developed the libcap1 [3] package, which was incompatible with patches by Serge E. Hallyn.

KaiGai Kohei addressed this problem during a Google Summer of Code; to do so, he added a couple of his own patches to Morgan's package. At the end of 2007, Andrew started to work on libcap again and integrated Kohei's version.

The result of this work was libcap2 [7]. The package contains the tools getcap and setcap for reading and setting PCaps. Currently, it is not necessary to install the userspace tools from the source code.

Chris Friedhoff has put together very comprehensive documentation on this topic [8] (see the "The Resurrection of PCaps" section).

The Resurrection of PCaps

Kernel version 2.6.18 introduced the requirement that a program must have the CAP_NET_ADMIN capability to create a Tun/Tap interface. I was working with Qemu (www.qemu.org) at the time, and interacting with a virtual machine required LAN connectivity through a Tun/Tap interface. Because I was uneasy having a not-so-trusty OS running in an SUID-0 container, I patched the three lines out of the kernel, and I was back where I was before 2.6.18. However, this solution lacked elegance. In the process of understanding capabilities, I found Serges Hallyn's fscaps patch and applied it, then I followed up with tests and documentation. The patch made it into 2.6.19-rc5-mm2 and stayed for one year in the -mm tree to mature. With 2.6.24- rc2, the patch was named posix file capabilities to form the option File POSIX Capabilities under security. KaiGai Kohei provided the userspace tools by adding different patches to the libcap1 package. At the end of 2007, Andrew Morgan was again taking care of his libcap packages, and, with the changes from KaiGai, the result was the libcap2 package.

The initial reaction to the first version in the summer of 2006 was friendly but reserved. The second version in October 2006 still hadn't gained much attention. It was like asking "who needs this for what?" I was the one who had a real use of this patch and was happy about it. Again, I started the discussion on the Linux Kernel Mailing List (LKML), gave test comments, and wrote documentation to help others use the patch. Slowly, the train started to move. When the pactch entered -mm, it got more attention, but this has taken one year. After File POSIX Capabilities went mainline, I thought everyone would be happy to substitute SUID-0 binaries through File POSIX Capabilities, but the response has been cautious. So I do my part in spreading the news of this technique by writing documentation, giving talks, and coding conversion tools. (Chris Friedhoff)

Use on Linux

For PCaps filesystem support, you need a Linux kernel with the File POSIX Capabilities enabled. For current distributions, this typically means loading Linux from Kernel.org, building the kernel yourself, and then checking the File POSIX Capabilities box in the security options (see Figure 1).

Figure 1: Enabling File PCaps in the kernel configuration.

While you are doing so, it also makes good sense to enable the Kprobes interface (Figure 2). Kprobes will be a big help later when you need to identify the capabilities a program needs. At the same time, the file system you use must support extended attributes.

Figure 2: The Kprobes interface lets you identify capabilities later.

Once the new kernel is running, you still need userspace tools to match. Theses tools are available as part of the libcap2 library at Kernel.org [7]. As usual, you need to download, build, and install the source code. The normal make && make install step handles this with no need to configure.

After doing so, the setcap and getcap commands and their man pages should be available on your system. For a quick capability test, you can use the ping and traceroute commands or the quicktest.sh script.

Ping requires privileges to transmit special ICMP packets over the LAN. Normally, the SUID root bit enables this. The chmod u-s /bin/ping command removes the privileges, and a non-privileged user calling the command will not be able to run it.

ping localhost:
ping: icmp open socket: The operation is not permitted

To restore the ability to run ping to normal users, the tool needs PCaps.

Normally, to discover which capabilities are required, you would need to investigate the way the tool works and then set the required capabilities to reflect this - too many capabilities would be unnecessarily risky and not enough would break the tool. This sounds tricky, but the simpler approach is use of the Capable_Probe module by Serge E. Hallyn [9], which uses Syslog to report processes and the PCaps they need.

Ascertaining Needs

The messages are normally written to the /var/log/messages logfile or to /var/log/kern.log. It is not a good idea to have the module loaded permanently because it will flood your logs with a bunch of unnecessary messages.

For POSIX Capability diagnostics, just load the verbose module; when you are done, issue modprobe -r capable_probe to remove it again.

Listing 1 shows the messages that Ping causes. The clear text for the capability numbers is listed in /usr/include/linux/capability.h; Table 1 has an overview.

Listing 1: PCaps for Ping
01 Feb 14 12:34:49 station1 kernel: cr_capable: asking for capability 13 for ping
02 Feb 14 12:34:49 station1 kernel: cr_capable: asking for capability 7 for ping
03 Feb 14 12:34:49 station1 kernel: cr_capable: asking for capability 21 for ping

Too Greedy

Ping tries to exercise capabilities 13 (CAP_NET_RAW), 7 (CAP_SETUID), and 21 (CAP_SYS_ADMIN).

SUID manipulation (7) is not necessary, and the powerful 21 is an unlikely candidate.

CAP_NET_RAW (13) sounds more promising; the following command gives Ping this capability:

setcap cap_net_raw=ep /bin/ping

After issuing the command, any non-privileged user can Ping, and this is obviously the only capability that Ping needs. If the utility is unable to open the requested socket, it attempts other steps, as the Capable_Probe module reveals. Because of this fairly frequent phenomenon, it makes sense to assign the privileges that Ping complains about one after another and to think about how plausible it is that a program requires the capability you are assigning to it. Chris Friedhoff [8] has lists of required PCaps for many programs.

POSIX Capability Sets

To allow for controlled inheritance, as well as dynamic enabling and disabling of PCaps, programs and processes have three PCap sets. What the sets do differs depending on whether the object they are applied to is a process or a file. Table 2 gives details of the Permitted p, Effective e, and Inheritable i privileges. For File PCaps, only capabilities in the fP or fI set can be part of the fE set; similarly, for Process PCaps, only capabilities from the pP set can be in the pE or pI set.

If an application is PCaps-aware, it will only work with a Permitted set. PCaps will only enable the privileges the program needs, when it needs them. The application itself defines which capabilities belong to its Inheritable set and which it will potentially pass on to new processes. Programs that are not PCaps-aware need an Effective set on top of the Permitted set.

The File Effective set gives a file required privileges from the outset:

setcap cap_net_raw=ep /bin/ping

Three operators are available for setting File POSIX Capabilities: =, +, and -. These operators work like the operators used by the chmod command, although the order is unusual: cap_net_raw=ep enables a capability in the Effective and Permitted sets and deletes it from the Inheritable set. + and - tell setcap to add capabilities to or subtract capabilities from the specified sets, without changing the other sets.

The getcap command lists the PCaps in a file. A normal directory listing does not show files with extended attributes - this is a problem that is common to all extended attributes and thus to PCaps. At least the extended attribute tool attr -l shows that a program has an extended attribute called capability (i.e., File PCaps have been assigned to it).

Frequently, but Not Always

The passwd command referred to earlier will work with filesystem capabilities - this removes the need for an SUID flag. The program requires the ability to work around file access controls. A quick look at Table 1 shows which capability handles this:

setcap cap_dac_override=ep /usr/bin/passwd

These privileges might not be sufficient in a production environment, especially if the password program relies on PAM (Pluggable Authentication Modules), because it will need extended privileges for other tasks.

Many services that do not have an SUID flag but that launch as the root account can be induced to run on a non-privileged account thanks to PCaps. Chris Friedhoff's page [8] gives examples of this for Apache, Bind, Samba, and the DHCP server. Interestingly, he combines PCaps and SUID techniques, using separate user and group IDs for each service. ACL-based access privileges for files with PCaps Capabilities prevent non-privileged users from running Apache or Bind with undesirable options.

Doomed to Failure with UID 0

Unfortunately, File POSIX Capabilities cannot replace SUID root techniques in some situations. Many applications simply assume they are running as root and check their UIDsID. A simple test reveals this approach:

On a Fedora 8 system, for instance. the NTP server does not take kindly to the change. Thanks to the full set of capabilities, the program effectively has the privileges it would have as root, despite running as nobody. However, the server does not notice this and demands UID=0:

# setcap all=ep /usr/sbin/ntpd
# su - nobody
$ /usr/sbin/ntpd
must be run as root, not uid 99

It is easy to assign all PCaps at once with all=ep. This option is available as of libcap 2.08; earlier versions are affected by a bug converting a 64-bit value to a 32-bit value. If you have an earlier version, you will have to set all capabilities individually. In addition to names, setcap fortunately understands numbers, and an expression like setcap `seq -s, 0 31'=ep /usr/sbin/ntpd will replace all.

Once the program is running with all PCaps and on a non-privileged user account, you can start to remove the unnecessary capabilities one by one.

More Privileges

Filesystem capabilities give non-privileged users access to functions that formerly required the use of the SUID bit and, therefore, are a critical security risk. For example, the system administrator can assign the required capabilities to the ntpdate program, allowing normal users to synchronize the system time with a central time server.

The following command takes care of the capabilities:

setcap cap_net_bind_service,cap_sys_time=U
ep /usr/sbin/ntpdate

After issuing this command, non-privileged users can run the synchronization tool. However, this technique exposes the system to new dangers: A user could point the ntpdate command at a rogue time server and thus inadvertently, or deliberately, change the system time.

Pitfalls!

Where an administrator might expect this kind of attack, the software will not expect to have more privileges than the user calling it. In this scenario, programs have to work very carefully to avoid inventive users exploiting them.

The only genuine way to discover whether a program is secure is with an intensive audit. In a worst case scenario, the attacker's privileges are defined by the capabilities assigned to the compromised program, but this is still better than when an all-powerful SUID root program is compromised.

Finally

File POSIX Capabilities finally allow administrators to manage the PCaps implemented in the kernel via the filesystem. Also, the system works in the way a Unix/Linux admin would expect: The setcap privileges file command sets the granular PCaps just as chown root && chmod u+s file assigns SUID root privileges globally. It is a pity that utilities like ls do not understand these additional permissions, although a call to getcap clarifies the situation.

Replacing SUID root with PCaps will not remove any security holes, and it might even add vulnerabilities to programs that are not PCaps-aware. If worst comes to worst, capabilities will help to mitigate the effect: Instead of escalating to root, a successful attacker just gains a few additional privileges that restrict the amount of damage the attack will cause to the system [10].

INFO
[1] Set UID patent by Dennis Ritchie and Bell Labs: http://www.freepatentsonline.com/4135240.html
[2] "Summary about POSIX.1e" by Winfried Trümper, http://wt.xpilot.org/publications/posix.1e/
[3] libcap1: http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap1/
[4] Serge E. Hallyn's patch: http://lkml.org/lkml/2006/11/27/170
[5] Olaf Dietsche's patch: http://www.olafdietsche.de/linux/capability/
[6] David A. Madore's patch: http://www.madore.org/~david/linux/newcaps/
[7] libcap2: http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/
[8] "POSIX Capabilities & File POSIX Capabilities" by Chris Friedhoff, May 2008, http://www.friedhoff.org/posixfilecaps.html
[9] Capable_Probe download: http://www.friedhoff.org/posixfilecaps/capable_probe.tar.bz2
[10] "POSIX File Capabilities: Parceling the Power of Root" by Serge E. Hallyn, IBM developerWorks, October 2007, http://www.ibm.com/developerworks/linux/library/l-posixcap.html
THE AUTHOR

Ralf Spenneberg works as a freelance Unix/Linux trainer, consultant, and author. Ralf has published several books on the topics of intrusion detection, firewalling, and virtual private networks. His latest book, SELinux & AppArmor, was published recently .