Capabilities in a nutshell
What are capabilities?
Capabilities are most easily envisaged as keys. When a process wants to perform a privileged operation a check is made whether the process posses a key that fits the respective lock.
Every process has three capability sets: inheritable, permitted and effective. Inheritable set says what capabilities will be passed onto the process’ children. Effective set is the set that is checked on a privileged operation request for required capabilities. Permitted set is a set that says which capabilities may exist in process’ effective set.
Where do the process capabilities come from?
The contents of the process capability sets are determined on process creation by the capability inheritance algorithm. They are determined from:
User capabilities, and
Capability bounding sets.
File capabilities are stored in three capability sets: fA, fF, fE.
fA, file allowed capability set, determines which of the capabilities from the parent’s inheritable capability set will be carried over to the inheritable set of the newly created process.
fF, file forced capability set, contains capabilities that are forced into new process’ permitted set.
fE, file effective capability set, determines which of the capabilities from newly computed process’ permitted capability set are transferred to the process’ effective capability set.
User capabilities are represented by two sets: uP and uB. uP, user permitted capability set, defines which privileges user can claim. uP takes part in the second stage of the capability inheritance algorithm in which new process’ permitted set is computed. uB, user bounding capability set, defines maximum privileges that the user can ever obtain. uB is used to mask new process’ permitted capability set after it has been computed.
Apart from the user bounding set, there is also a global bounding set (gB) which determines the set of capabilities which can never be exceeded by any process on the system.
To cut the long story short, there are two ways to make process’ effective capability set contain required capabilities ie. make a program do what it is actually meant to do without complaining (it is useful to be looking at the actual algorithm when thinking about this):
Let binary have the desired capabilities in its fA and fE and also make parent process have those capabilities (possibly among others) in its inheritable set. Also, pay atention that the user who actually execs the binary has the capabilities in its bounding set and that global bounding does not mask them out.
An example of this is LinSec administrative tools: lsenable (the tool that requires a password and needs to be executed before any other tool) essentially sets inheritable capability set of the parent process (shell). Other tools have the needed capabilities in their fA and fE and so, when you execute them, they inherit the required privileges from the shell.
Let a user have the desired capabilities in its uP and let the binary have the same capabilities in its fE.
Let the binary have the desired capabilities in both its fF and fE. This is the least desired option as it forces certain privileges into process’ permitted set irrespective of executing user’s uP (uB can still be used to control the process’ permitted set).
This appoach is used for boot time programs as they (and this is a difference from traditional Linux approach) are not owned by any user. Yes, they run as uid 0, but in LinSec environment all boot time process’ have no owner. Therefore, all capabilities they require have to be obtained through fF and fE.
Now, if this is not clear, please look at the inheritance algorithm and at the example configuration provided. And if it is still not clear please ask on the mailing list.