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
pay *somewhere*.

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
> 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.

>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 mailing list