|
|
Subscribe / Log in / New account

A bid to resurrect Linux capabilities

Back in 1998, as the 2.1 kernel went into yet another feature freeze, the capabilities feature was merged. Capabilities split the power of the root account into a set of privileges, each of which can be granted or withheld independently of the others. A process which needs to be able to bind to a privileged port number, for example, could be given that ability without simultaneously enabling it to override file permissions, kill other processes, or exceed resource limits. Proponents of capabilities have long seen a world where the root account no longer exists and all tasks have the minimum level of privilege they need to get their jobs done. A system organized in this way, it is thought, would be more secure.

The world is full of Linux distributions, many of which are oriented toward higher levels of security. But, to your editor's knowledge, nobody has ever put together a successful, capability-based distribution. There are many reasons for this lack of implementations, including the fact that nobody has really figured out a way to administer a system with a couple dozen more security-related bits attached to every executable file. But one should also not overlook the fact that, from the 2.1.x days to now, there has never been a Linux kernel where capabilities actually worked as intended.

Part of the problem is an incomplete implementation: no patch which attaches capability masks to files has ever been merged. But the kernel has also never implemented capability inheritance - what happens to the capability bits when a process executes a new program - in a correct manner. For some time now, in fact, capability inheritance has been disabled completely. Without inheritance, the full capability model cannot work. So the use of capabilities in Linux systems has been limited to a very small number of programs which have been coded to drop the capabilities they do not need.

David Madore has set out to change that state of affairs with a set of patches to fix up capability support. This patch set does a few things, the first of which being to expand the capability set from 32 to 64 bits. Current kernels have 31 capabilities defined, so it is not especially hard to imagine needing more in the future. That need could become pressing if anybody ever gets serious about splitting the catch-all CAP_SYS_ADMIN capability into several smaller privileges.

This patch uses some of those new bits from the outset for a set of "regular capabilities" which all processes are normally expected to have. These capabilities include the ability to use fork() or exec(), the ability to open files and to write to files, the ability to use ptrace(), and the ability to increase privilege by running a setuid program. The idea here is that processes running in security-relevant settings can drop those capabilities if they are not needed, making it harder to exploit any vulnerabilities in those processes.

The core of the patch, however, is the implementation of capability inheritance. Understanding this part requires just a bit of background. As it happens, while one can talk about the capabilities possessed by a process, each process in Linux has three separate capability masks. The permitted set is all of the capabilities that the process is allowed to have. But capabilities cannot be used unless they are set in the effective set, is a subset of the permitted set. Finally, each process has an inheritable set, listing the capabilities (again, a subset of the permitted set) which can be passed on to any program run with exec(). Processes can adjust the effective and inheritable sets at any time (within the bounds of the permitted set), but the permitted set cannot be expanded.

In a capability-based system, executable files also have a set of three capability masks. Those masks have the same names as the process masks, and their function is almost the same. The file's inherited mask, however, will limit the capabilities which can be inherited from any other process. David's patch set includes a patch (by Serge Hallyn) which adds support for capability masks to the filesystem layer.

When a process runs a new executable, the masks are combined as follows:

  • P′p ← (Pi ∩ Fi) ∪ (Fp ∩ bnd)
  • P′e ← (Pi ∩ Pe ∩ Fi) ∪ (Fp ∩ Fe ∩ bnd)
  • P′i ← P′p

These equations are taken directly from David's "new capabilities" page, which has much more detail on all of this work. What they say, in English, is something like this:

  • The permitted capabilities for the new executable (P′p) are the intersection of the inheritable set from process before calling exec() (Pi) and the file's inherited set (Fi). The permitted set from the file (Fp) is then added in, but not before being limited by the system-wide capability bounding set.

  • The effective capabilities (P′e) will be the same as the inherited capabilities, except that capabilities which are not effect in the current process or in the file's effective set will be masked out.

  • The inheritable capabilities (P′i) will be the same as the permitted capabilities.

For the most part, these rules match the usual understanding of how capability-based systems are supposed to work. Capabilities, in such a system, are assigned to programs, not to users; the normal permissions bits can then come into play to control which programs specific users can run.

David's patch differs from the usual idea of capability-based systems in one important regard, however: how it handles programs with no capability sets defined. On most systems, that will be almost every executable file there is. By the rules, such programs should be treated as having an empty inherited set, which, by the rules above, would cause them to be run with no capabilities at all. David's patch, instead, causes these programs to be run with the same capabilities the process had before - though the presence of things like setuid bits can obviously change that calculation. This interpretation breaks the classic capability-based model, but it has the advantage of actually working on current systems.

Ted T'so, however, complains that this compromise fundamentally weakens the security of the capability-based model. He has suggested that the behavior be configurable, with each filesystem having a flag describing how capabilities should be handled in the absence of a set per-file masks. A set of default capabilities for new files could be part of this change as well.

The other complaint which has been heard is fairly predictable: why, it is asked, should we bother with capabilities when SELinux can do all of the same things and more? In fact, SELinux does something vaguely similar, but with a level of indirection; it attaches labels to files, then associates capabilities with the labels through the policy mechanism. Anybody who has ever gotten that cheery Fedora "your filesystem must be relabeled, please wait for a very long time" boot message knows that keeping files and labels properly synchronized is a difficult task. There is no real reason to believe that keeping capability masks in a correct state would be any easier. That fact alone may continue to limit the real usage of capabilities well into the future.

Index entries for this article
KernelCapabilities
KernelSecurity/Security technologies


to post comments

Editorial fixes...

Posted Sep 14, 2006 7:17 UTC (Thu) by alonz (subscriber, #815) [Link] (1 responses)

(Is our esteemed editor becoming tired? ;-) )
Third paragraph: "the kernel has also never inherited capability inheritance" should be "the kernel has also never implemented capability inheritance"
Sixth paragraph: "implementation of priority inheritance" should be "implementation of capability inheritance"

Editorial fixes...

Posted Sep 14, 2006 14:51 UTC (Thu) by corbet (editor, #1) [Link]

Your editor was in a hurry, trying to get things done before traveling to Europe for the Wizards of OS. Thanks to the magic of free hotspots in Potsdamer Platz, the mistakes are now fixed.

A bid to resurrect Linux capabilities

Posted Sep 14, 2006 10:00 UTC (Thu) by nix (subscriber, #2304) [Link] (3 responses)

Well, a capability-based system would have no trouble keeping anything in sync with the capability masks on files, because there *is* nothing to keep in sync. The relabelling operation consists (very roughly) of tracking down the xattrs on labelled files and bringing them in sync with what's defined in the SELinux config files: no analogous operation exists if xattrs are the only storage representation, just as you don't need to wait for ages while permissions are synched with anything when you boot :)

(The interaction of all this with Samba and NFS-without-xattrs is interesting: the standard capability inheritance model is totally broken in that situation. Mind you it's quite rare to run binaries over NFS these days.)

A bid to resurrect Linux capabilities

Posted Sep 14, 2006 11:35 UTC (Thu) by jschrod (subscriber, #1646) [Link] (2 responses)

Mind you it's quite rare to run binaries over NFS these days.
I don't agree with that opinion. A common use of NFS is to provide netwide home directories. If a user installs any program privately, or if she develops programs, executables will be run from this NFS share. And IMNSHO this scenario is not "quite rare".

Cheers, Joachim

A bid to resurrect Linux capabilities

Posted Sep 14, 2006 18:58 UTC (Thu) by nix (subscriber, #2304) [Link] (1 responses)

I was thinking that it's rare compared to the number of programs installed
in /usr/bin: but then if the user's compiled a program herself she's a lot
more likely to run it than a given random binary in /usr/bin...

A bid to resurrect Linux capabilities

Posted Sep 14, 2006 22:13 UTC (Thu) by jzbiciak (guest, #5246) [Link]

...in which case a "default per-mount permitted capabilities" sounds useful.

A bid to resurrect Linux capabilities

Posted Sep 14, 2006 17:35 UTC (Thu) by kfiles (guest, #11628) [Link]

I'm not sure I agree with the premise that no Linux distribution has shipped with active capabilities support, or that current capabilities support is inherently unusable due to the lack of inheritance.

For many years, I've used the highly-secure EngardeLinux distribution from Guardian Digital, which shipped with LIDS (http://www.lids.org) installed and enabled by default. Now, LIDS development is mostly bug-fixing at this point -- it's not pushing cutting edge features. However, for a manageable Mandatory Access Control system utilizing capabilities, it's quite nice. Like SELinux, it uses centralized ACL configuration rather than file attributes, which makes it a better fit for distributions than for package owners (See, e.g. AppArmor, as a solution that enables each package to ship its own ACLs).

Thanks,
--kirby

A bid to resurrect Linux capabilities

Posted Sep 14, 2006 19:18 UTC (Thu) by giraffedata (guest, #1954) [Link] (1 responses)

I've always wondered why the security conscious world hasn't paid more attention to using Linux capabilities. People go to great lengths to change UID and re-exec things and create setuid helper programs and such to reduce the amount of code that has privilege, but Linux capabiities do the same thing (by design, that is) and get ignored.

I liked the idea so much for protecting my own systems that I made a few small fixes to Linux 2.4 years ago to make capabilities work, wrote the missing administration tools for them, and have used them extensively. Hardly anything runs as superuser on my systems.

For the missing setuid function (attaching capabilities to files), I used an idea that was posted in a comment to an LWN article on the topic a few years ago: Rather than mess with exec and filesystem code, I wrote a simple executable interpreter (those are modular in Linux; the ELF interpreter is one example). Execing a privilege-raising program is two steps: user execs a setuid file which is in "capx" format, and that file sets proper capabilities then execs the regular non-setuid ELF file.

It will be nice to have a clean, working implementation in mainstream Linux, but I wonder if anyone will use it, since they haven't cared so far. I'm the only person I've ever known to use capabilities.

A bid to resurrect Linux capabilities

Posted Sep 15, 2006 9:27 UTC (Fri) by jbailey (guest, #16890) [Link]

I suspect yes. The problem in that scenario is that you still have to go to full priviledges first. So while the attack vector is very small and unlikely, it's not non-existant.

If we had fullsystem-based priviledge raises beyond just SUID/SGID, I suspect it would be taken up quite quickly by distros.

Tks,
Jeff Bailey

capability inheritance works fine in 2.4

Posted Sep 15, 2006 3:10 UTC (Fri) by sweikart (guest, #4276) [Link]

> But the kernel has also never implemented capability inheritance
> - what happens to the capability bits when a process executes a
> new program - in a correct manner.
Actually, the inheritance behavior in the 2.4 kernel worked fine for me. The GPL'ed Martus Server software (available near the bottom of the Martus download page) implements my custom security model based on Linux capabilities. I wrote a caps command that root can execute to change the capabilities of other processes (it sets CAP_SETPCAP in the capability bounding set by poking /dev/mem, then forks and execs to acquire CAP_SETPCAP, then clears CAP_SETPCAP in the bounding set, then applies the user-specified capabilities to the user-specified processes). I wrote a few paragraphs describing the semantics of the 2.4 kernel's capabilities, based on my experimentation. My /etc/rc.d/init.d/martus startup script sets CAP_SETPCAP (plus a subset of the normal capabilities) in the inheritable set of the sshd listener and init, and then clears all capabilities in the bounding set (and in other processes running at startup time). So, a human that logs in gets (a reduced set of) the normal capabilities, but the application-listeners have no capabilities.

I even use my caps command to give CAP_NET_BIND_SERVICE to a non-root java, so it can open a privileged port (after which I remove CAP_NET_BIND_SERVICE).

But, all this was a lot of work. I'll just use SELinux when I move the software to the 2.6 kernel.

-scott

A bid to resurrect Linux capabilities

Posted Sep 22, 2006 8:24 UTC (Fri) by slamb (guest, #1070) [Link] (1 responses)

This patch uses some of those new bits from the outset for a set of "regular capabilities" which all processes are normally expected to have. These capabilities include the ability to use fork() or exec(), the ability to open files and to write to files, the ability to use ptrace (), and the ability to increase privilege by running a setuid program.

Woo! I'm glad to see someone do this. I've long thought this was the best way to take advantage of capabilities. I even wrote a crappy patch to OpenBSD long ago, which fortunately for the world never made it beyond my system.

Many of the regular capabilities can easily be used to gain full root access. (Though I thought that about pcap, and omnipresent ssh has proven me wrong.) But locking down ptrace() might be a good way to prevent an exploited connection from messing with another one in forked servers. I think the only other way would be to bind as root, then setuid() to one of a pool of uids or something...I hope no one's doing that.

A bid to resurrect Linux capabilities

Posted Sep 25, 2006 8:21 UTC (Mon) by cras (guest, #7000) [Link]

But locking down ptrace() might be a good way to prevent an exploited connection from messing with another one in forked servers. I think the only other way would be to bind as root, then setuid() to one of a pool of uids or something...I hope no one's doing that
A pool of UIDs is not required, just doing setuid() after exec() will make the kernel think the process is in "setuid state" and won't allow other processes ptrace it.


Copyright © 2006, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds