nick8325 wrote:
[*]Each process has a table of capabilities. A capability is (more or less) a pointer to a thread, and an object ID. It's meant to represent an object. The table is stored in kernel-mode and not directly accessible to user-mode code.
This is what I have too. As it is, after Hurd people tried to build their system over L4, they noticed that wasting the few cycles in IPC to do capability validation will translate into lots of overhead reduction in userspace. Hence, L4.sec, the status which I must confess I haven't followed really.
In any case, how is userspace supposed to perform validation anyway? Either you try to make thread IDs unique over "sufficiently long time" (like original L4) and implement capability system based on that, which is hairy at best, or you revert to something like ACLs, which without stateful connections introduce tons of overhead, and which are pain to manage if you try to enforce strict POLA.
[*]Instead of asking to send a message to a thread ID, the sender asks to send a message to a capability (by giving an index into the capability table). The kernel looks up the thread (just an array lookup), and passes the object ID and message along to the receiver.
Yep. This means that the protected payload (or objectId) carries not only state but access priviledges as well. If it's unforgeable, access is unforgeable as well. While you can think of thread-id/object-id being a secure pointer to an interface of an object, you can also think of it as an opaque remote continuation, or a lot of other interesting things...
Btw, this isn't too different from using session cookies in web applications (session ID is little different from object ID), except it's much less overhead (just fetch two pointers from a table). Nobody complains that session IDs won't allow fine grained security; they do.
Ofcourse capabilities can be made fully unforgeable on local machine.
[*]Messages can transfer capabilities as well as data. In other words, if a process can access an object, it can give another process permission to access the object by sending it a capability to the object in a message.
Yes, and this is proven to be sufficient to implement any kind of access control whatsoever. So it is both more lightweight and more general than most other solutions. Ofcourse capabilities make almost no sense if you don't do this.
As for copying capabilities, my capability move (no copies in general case) invalidates the capability from sender, by writing a single pointer, and saves the capability as part of the message (two pointers). So it's about as fast as sending two pointers, too.
I hope that that's a counterexample to your assertion that "the main problem with kernel enforced messaging security is that it's either limiting, slow or coarse grained"
I'd personally like hear of single other option that is:
- as fast: remember, two pointers fetched.
- as fine grained: you can easily enumerate each and every method somebody is allowed to call
- as secure: fine grained POLA is enforceable mostly even in presence of bugs.
- as general: proven to be universal (as in equivalent in power to Turing/Lambda....)
One example that you don't mention, but which my system allows, is doing system virtualization with little extra effort: in my system every process gets one capability too ("master" capability), but this capability is used to access all kernel services as well.
So any process can implement proxies for kernel services, and start other processes (provided it's own master allows), so that running a virtual copy of the system under system is just a matter of writing a suitable server. The processes running within the virtualized system can't (theoretically) tell whether they are running in a virtual system, and still might have direct access to some subdirectory (or well, subnamespace) of the global namespace, avoiding overhead there.
Now, ofcourse the principal problem is how to maintain the capability table, when the number of capabilities per process grows. But this is little different from maintaining a list of file descriptors in a Unix process...
Oh, and unix-domain datagram sockets could be considered a capability system (they can transfer filedescriptors too) if other IPC mechanism wouldn't exist in Unix. I'm going to write an emulation library on top of those to debug servers on top of Unix at some point, btw.
---
One thing I'm unsure about: should messaging be symmetric or asymmetric. If client/server model is assumed anyway, then would it make sense to support that directly, instead of a general P2P mechanism (which can't take some shortcuts).