-----Original Message----- From: Jonathan S. Shapiro [mailto:shap@eros-os.org] Sent: Monday, January 05, 2004 4:56 PM To: Volkmar Uhlig Cc: rudykoot@mithrill.org; L4 Hackers List Subject: L4, High Assurance, and Protection
Issue 1: Need for Protected IPC
On Thu, 2004-01-01 at 18:09, Volkmar Uhlig wrote:
If it does not matter where the check code is executed (client/kernel/server) but only who gets accounted for the used resources (CPU, cache, whatever) this is not the case. (I'm not claiming L4 can do that (yet).)
In answer to Volkmar's question: it matters very fundamentally where the check is performed. It is the difference between mandatory and discretionary controls.
The current L4 IPC is discretionary: the sender can invoke anyone, and the recipient checks the sender identity and decides whether to accept the IPC.
In such systems, it is a fundamental requirement that the reference monitor be able to PREVENT (absolutely) communication between processes that are under its control. If a sender S is not permitted to send to a recipient R, the behavior must be exactly as if the send was performed to a non-existent ID.
Ok, I see that point.
The main change that is needed in L4 to resolve this is to define the recipient-id and sender-id fields as opaque fields. Under high-assurance requirements, the sender is not entitled to know how many threads execute within the recipient. The sender-id and recipient-id therefore must not encode "thread within process". Similarly, it must not encode "process ID".
I think there is some misconception around about L4's thread ids. In L4 V4 (X.2 is going to become V4 after maturing) threads and address spaces are completely independent of each other. Threads execute in an address spaces, but they can migrate. A thread ID is a communication-endpoint place holder. If you have, say, 100 threads in an address space and you want to hide that fact you can use a single thread serving as a distributer. Since we have local IPC the distribution can completely take place in user land without a kernel invocation. The worker can impersonate the distributer for the reply.
While I do not advocate any particular implementation strategy, let me give an *example* of one that might suffice: a simple hash table. Instead of using the PCB address as the process ID, the kernel could use H(sender kernel ID, requested-recipient-ID) as an index into a hash table and perform a single indirection (and possible hash bucket chasing) to find the process address. This is fundamentally the design proposed by Trent several years ago.
You immediately run into replacement policy issues.
2: Restricted Mapping
This is a very small issue, and there may be some way around it.
In general, I like the map/grant model very much, but in some systems it is necessary for the manager to know who has what mappings.
In these systems, having applications perform mappings directly to
each
other creates a consistency problem.
Here the argument is around IPC redirection (which is arguably expensive). By sticking an interceptor in between you know which mappings go in and out. That way you can control it. But I suspect that fine-grain control over mapping privileges makes sense. The question is what this granularity should be--page or mapping in general.
My preference would be to have *both* controls, because they serve slightly different purposes. The first lets me virtualize the map/grant operations (in order to keep manager metadata updated), while the second prevents map recursion.
The problem with the first method is that it requires protected recipient descriptors.
You can transparently drop the mapping if it is not allowed. Since the guarantees whether a page is mapped or not come from the pager hierarchy it is only as strong as all combined pagers. By adding a non-guaranteeing pager in the hierarchiy you are set.
The problem with implementing only the second method is: what thread id should a page fault handler receive from a faulting thread? Restricted or non-restricted? I can argue for either depending on what
kind of system I am trying to build.
That raises the question whether the pager is privileged or not. Since the pager can be set by the thread the pager can be changed and the thread could elevate its privileges. Or did I misunderstand you?
- Volkmar