[e-lang] Revoking Capabilities
Mark S. Miller
e-lang@mail.eros-os.org
Thu, 30 Jan 2003 10:20:48 -0800
At 09:27 PM 1/27/2003 Monday, Chris Turner wrote:
>Hi all,
>
>I've recently started playing around with E, and am trying to wrap my head
>around some things... Would the following code snippet work for capability
>revocation?
Yes! Although Constantine's suggested alternative of declaring "obj" to be
"var" and setting it to null is better style, your's does work. You got it
on the first shot.
Constantine and Bill are also right when about the weakness of this
approach, but that doesn't invalidate it. It only limits its usefulness. I
call this kind of revocation pattern "cooperative revocation" -- when the
wrapped object's protocol is designed to be revoked by this pattern.
A complex and useful example of cooperative revocation shown on
http://www.erights.org/elib/capability/ode/ode-bearer.html is the use of
makeTitleCompany -- an abstraction built around a revocable wrapper maker --
to transfer exclusive rights to a coveredCallOption as made by
makeCoveredCallOption. The API of coveredCallOption is designed to not
subvert the need to revoke access, and the scenario of use these were
designed for justifies the cooperative assumption between the two
abstractions -- they're both instantiated and composed by one interest --
the broker -- who uses this code to stand between four other mutually
suspicious interests (the money issuer, the stock issuer, the options
writer, and the options holder).
For uncooperative revocation, we need an abstraction I call a Membrane. It
is much like the current CapTP comm system, in that 1) it stand between two
subgraphs of the object graph by wrapping references going in either
direction, 2) as messages are passed, to wraps and unwraps args and results
in order to stay between, and 3) it can be severed, partitioning the two sides.
Unlike the CapTP comm system, this will be built only for intra-process use,
keeping the revocability-for-security concerns separate from the comm system
concerns, even though the mechanisms are so similar.
Unlike the CapTP comm system, and like E-Speak2.2, the Membrane must proxy
introductions rather than shorten them. In other words, if Alice is within a
Membrane and Bob and Carol are both outside, after Alice introduces Bob to
Carol, the reference Bob holds goes back into the Membrane to a proxy for
Carol, and then back out to Carol herself. When Bob's access to Alice gets
revoked, so does the access to Carol that he obtained through Alice.
By contrast, in the corresponding 3-vat CapTP introduction, we shorten, so
that if a partition separates Bob from Alice, Bob can remain connected to
Carol. A revocation is an expression of policy, whereas a partition is
simply a problem you survive as best you can.
>As far as I can tell this should work in a distributed
>environment for remote revocation on a larger scale than this simple test
>case, but I thought I'd check.
Almost perfect, but for one additional issue when your pattern is used in a
distributed context.
The distributed capability paradigm is surprising faithful to the properties
of the single-machine capability paradigm. One of the differences between
the two is that single-machine capabilities are "reliable", meaning that
they work perfectly for as long as their universe exists. Distributed
capabilities can be at most fail-stop, since one side can fail without the
other, or a partition can separate them. Usually, this fails safe, since an
inability to exercise authority is a lack of service, but not a breach.
The revoker is a nice example of the other case. If the holder of the
revoker is remote, then a partition can prevent them from sending a revoke
message, leaving the holder of the wrapper with too much authority. To solve
this, we turn the revoker into a "dead-man switch" as follows:
def revoker {
to revoke() { ... }
to __reactToLostClient(problem) { revoker.revoke() }
}
__reactToLostClient is a MirandaMethod explained at
http://www.erights.org/javadoc/org/erights/e/elib/prim/MirandaMethods.html#__reactToLostClient(java.lang.Object,java.lang.Throwable)
as:
>When someone was holding a partitionable eventual reference to this object,
>and it suffers a partition, then inform this object that one of its clients
>may no longer be able to talk to it, and why.
>
>The Miranda behavior is to do nothing, but objects may override this to
>provide DeadManSwitch behavior. For example, a revoking facet of a revokable
>service may decide that if its client may no longer be able to talk to it,
>that it should auto-revoke. However inconvenient this solution, it is failsafe.
So, once we introduce Membranes, we have an interesting design choice.
Should a revoking Membrane send __reactToLostClient messages to the severed
parties? How should we think about revocable rights to revoke?
----------------------------------------
Text by me above is hereby placed in the public domain
Cheers,
--MarkM