Some Comments on Linux “Capabilities”
First I must thank Mike Goldman for his excellent FAQ on Linux capabilities.
Nearly everything I know of them comes from that FAQ.
(2010: I can’t find that FAQ now. This FAQ seems useful on the same subject and also distinguishes Linux caps from historical CS caps.
Here is some other recent information.)
The FAQ adequately explains why the Linux capability idea, which originated with a Posix capability draft, departs radically from what has been called “capabilities” in classic OS literature.
I want to describe here some of the similarities and differences.
Here is an even briefer description of the proposal but from our conceptual and terminological framework.
There are a fixed number of capabilities, about 128 for the whole system, that are individually documented in the kernel manual (currently here).
Some of these capabilities convey some strict and narrow subset of authority that a root program would have.
There are some Linux extensions.
Being a fixed finite set, there are none referring to objects of individual users or applications.
These capabilities can be held by processes and can also reside in file directories.
Like the setuid file directory attribute of a program file, these directory capabilities are granted to the process that starts from that file.
The program may receive capabilities from its parent as well.
A Linux cap is held by a process.
The program can nominate caps in particular system calls, (but often with insufficient precision).
The process can transfer a cap to processes that it creates.
A program that lives in a file while the machine is turned off, can hold caps.
When Program X invokes program Y as in exec(), Y may run with both caps granted by X and those inherent in Y.
You have to write new kernel code to implement new caps.
Capabilities in capability systems are dynamically created as the things to which they refer, are created.
There are a finite number of caps in a Linux system.
Specific caps are for specific kinds of operations instead of specific things in the system.
I don’t care whether you can do raw IO to your device, but whether you can do raw IO to my device.
You cannot create new capabilities as the primary way of building new function, such as building, upon a capability to a comm link, a capability to ring the bells in the campanile.
One of the first exercises in a classic capability system is to run untrusted code with only read access to one of your files.
The Linux scheme seems to provide no direct support for this as far as I can see.
This is how capability systems resist viruses.
Security arguments for a given application must argue from absence of capabilities that can do bad things to components of the application.
In a classic capability system I can make such arguments because capabilities are to specific things and there are no generic capabilities.
In the Linux scheme ...
Monolithic Security Policies
The Unix or Linux kernel obeys extra system calls by user code that runs with the user ID of root.
This allows many system wide functions to be provided by code that is more like normal user code than kernel code.
Bugs in such code are much less likely to cause havoc when they run in user mode, unless those bugs are being exploited to malevolent ends.
With the Posix “capabilities” proposal such code can have compartmented authority which further limits the effects of bugs in such code, even when exploited.
This is a substantial improvement over previous Unix art.
It is in this regard like the two state
architecture of CPU designs which is used to support most security and protection schemes, including by those of Keykos.
Capsicum, on the other hand, brings real capabilities to Linux, yet Capsicum is less that a full capability system.