L4, High Assurance, and Protection
Jonathan S. Shapiro
shap at eros-os.org
Mon Jan 5 21:31:24 CET 2004
On Mon, 2004-01-05 at 12:56, Volkmar Uhlig wrote:
> 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....
I believe that I have now asked twice for a URL to this specification.
Can you send me a URL? Otherwise we will continue to waste each other's
time. Please accept my apologies that, in the absence of this document,
I may have done so.
If it was on one of the L4 web sites, I failed to see it.
> 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.
This sound like a very good thing, and it almost certainly addresses the
issue of "revealed thread ids".
> > 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.
If there is a faster way, great! But protection is not merely a desire.
It is a hard requirement. *Every* mechanism I know about for achieving a
protected interface carries a fundamental cost somewhere. You can do it
with address space traversal, or you can accept the need for a
replacement policy, or you can do something else, but you are going to
My problem is that performance cannot be used to justify fundamental
insecurity. Speed at the cost of correctness is simply unacceptable.
> > 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
> > 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.
>From a security perspective, the problem is with the presence of mapping
operations at all. Mapping establishes a high-speed, mutable channel, so
it tends to undermine reference monitors.
My preferred model is that performing a send with a mapping on a
disabled descriptor would be treated as an access violation, and a
suitable exception would be delivered to fault handler. I don't want to
pay any indirection cost for the legal (non-mapping) IPCs.
> > 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.
>From a security perspective, failing silently is *always* a mistake. It
also makes virtualization difficult if somebody wishes to be backward
compatible with the interface later. You are describing a situation in
which a sender has done a known-illegal operation, but no fault is
generated? This doesn't seem like a good design.
> > 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?
It is a big problem for the pager to be settable by the thread. There
are some systems in which this can be permitted, and other systems in
which it **must not** be permitted. Because there exists systems in
which this must not be permitted, the operation must (at a minimum)
involve invocation of a trusted party.
Perhaps there is some third design possibility that I have not
considered carefully enough, but it appears to me that a high-assurance
system constructed on top of L4 must be built exclusively using trusted
pagers. While it is possible, in abstract, to use untrusted pagers in a
descriptor-based system (as EROS does), the L4 map/grant operations
don't appear to provide enough book-keeping controls to be trusted.
More information about the l4-hackers