9 comments

[ 3.0 ms ] story [ 36.8 ms ] thread
A shared global namespace ultimately makes it very difficult to have a decent capability based security system. Namespaces limited to the set of actions you have and a hierarchy of capabilities whereby children can only be given access to capabilities their parents have is required for a sane view of how things work. Much like encapsulation makes it easier to reason about abstractions in a program, this nested hierarchy of capabilities makes it easier to reason about the privilege of various parts of the system. Instead we have soup where no one can quite reason about what has access to what.
Linux capabilities are fairly unrelated to the traditional concept of object capability based security.

They're closer to apple entitlements, but inherited through through forks rather than being attached to a binary.

I don't think you can bolt something like what you're describing onto an existing kernel (like linux did with capabilities). You'd have to design it this way from the ground up. I think I've read about some experimental OSs exploring that kind of capability by design, almost like a type 1 hypervisor but for processes.
> whereby children can only be given access to capabilities their parents have

The one thing that makes capabilities usable is that they don't need to follow that rule.

If you don't have processes that let your programs get capabilities from any source other than their creation, you are better just adding your program names into your ACLs.

Note that namespaces are effectively capabilities.
Fascinating, thank you for sharing.
One problem that I have with fine-grained ACLs is that they can unintentionally add security risk, because sometimes those finer grained controls can be exploited to gain additional privledges.

If I grant something root, I know what that means and I'll be very careful. But if I grant something permission X thinking I'm safe, and then it can be used to gain permission Y, or even root, then I can be accidentally exposed.

There is just a much larger surface area to guard against, ensuring that each granular permission can't be so exploited.

I find Linux’s approach on capabilities underwhelming, and not even close to a true capability-based system.

For example, you can pass a program a capability to bind any privileged port, but not a specific one. For this scenario, just passing an fd bound to the port is actually much simpler and safer. For other capabilities, they’re just too coarse.

The fact that capabilities are implicitly inherited also doesn’t sound like a good approach on security. It’s likely like this due to backward compatibility, but I really think that capabilities ought to be passed explicitly, and we should be able to transfer them between processes. In fact, using an fd as a handle for capabilities would probably be a much clearer and explicit approach.

Ditto Solaris' privileges system (which is basically Linux capabilities done better, but still the same abstract model).