[e-lang] A broken brand?

David Wagner daw at cs.berkeley.edu
Sun Mar 2 02:38:40 EST 2008


I've been reading the Caja spec.  It includes an example of a brand
implemented in Caja, using an implementation technique attributed to
Marc Stiegler.  I think I may have found an attack on it, and I was
curious whether this was well-known.  I'll re-print the Caja code:

function Brand() {
  var flag = false;
  var squirrel = null;

  return caja.freeze({
    seal: function(payload) {
      function box() {
         squirrel = payload;
         flag = true;
      }
      box.toString = function() {
        return "(box)";
      }
    unseal: function(box) {
      flag = false; squirrel = null;
      box();
      if (!flag) {
        throw ...;
      }
      return squirrel;
    }
  });
}

Now for the attack.  Let Br be some brand.  Let Bx be some sealed that
was generated by a call to Br.seal(P), where P is some precious payload.
Suppose that Viktor the Victim has access to Br.unseal and to Bx.
Suppose that Attila the Attacker has access to Br.unseal.  Suppose that
Viktor exports a public method go().  When someone invokes go(), Viktor
will perform some operations that, among other things, involve calling
Br.unseal(Bx).  Assume that Attila has access to go().

Here is an attack by which Attila can gain access to the precious payload
P, even though Attila does not have access to Bx.  Attila creates the
following function:
  function trap() {
    Viktor.go();
  }
Then, Attila executes
  var v = Br.unseal(trap);
Now Attila's v contains the precision payload P.  Why does this work?
Because Br.unseal(trap) invokes trap(), which invokes Viktor.go(), which
invokes Br.unseal(Bx), which invokes Bx(), which sets Br.squirrel = P
and Br.flag = true, then everyone returns back to the outermost invocation
of Br.unseal, which finds that Br.flag is true and returns Br.squirrel
(i.e., P) to Attila.

It seems the problem is that the brand above is not safe in the
presence of re-entrant calls.  Put another way, it is subject to "plan
interference", to borrow MarkM's term.  It doesn't look too difficult to
modify the brand to defend against the above attack (e.g., by resetting
flag to false and squirrel to null before unseal() returns), although
I haven't checked whether there are any other attacks.

Does this attack look correct to you?  Is it well-known?

P.S. How did I find the attack?  I used trust analysis (aka taint
analysis).  For each security perimeter (e.g., each function), you treat
the data flowing across that security parameter (e.g., the arguments to
that function) as untrusted.  All of the fields/properties of an untrusted
object are themselves untrusted.  Invoking an untrusted object gives the
attacker a chance to run code; the return value from such an invocation
is itself untrusted.


More information about the e-lang mailing list