WeakMap API questions?

Mark S. Miller erights at google.com
Tue Aug 31 21:32:23 PDT 2010


On Thu, Aug 26, 2010 at 9:03 PM, Brendan Eich <brendan at mozilla.com> wrote:

> On Aug 26, 2010, at 8:19 PM, Bradley Meck wrote:
>
> I am not sure that would make it a regular map. Having the keys available
> does not ensure that the keys will not be collected.
>
>
> That's the crux of the matter. Mark Miller should weigh in, since he has
> argued this point in the past with some good arguments.
>
> The issue is that enumeration or even a weakmap.length property would
> convey what has been collected as garbage, and what has not yet been
> collected even though weakly referenced by a map entry. There could be
> strong refs elsewhere, or the GC might just not have gotten around to
> collecting the still-enumerated or counted-by-length entry.
>
> This makes a covert channel from the implementation's garbage collector,
> and it can be abused. The GC schedule may be deterministic, so as I
> understand it the issue is not non-determinism (or it's more than ND vs. D
> -- it's really the ability of attackers to tell what the GC considers live
> still).
>

Thanks Brendan, that's an elegant summary. To make the covert channel
problem here more concrete for those interested, here's an example:

Say a.js wishes to mashup two libraries, b.js and c.js, and to keep them
isolated. Using our new SES prototype <
https://mail.mozilla.org/pipermail/es-discuss/2010-August/011684.html> to
make this concrete,

a.js:
-----------------
  // cajaVM.protect freezes its argument and all data transitively
reflectively
  // reachable from that argument. For the simple json data resulting from a

  // one-arg JSON.parse, the result is transitively immutable, as so is safe
  // to share among isolated components such as b.js and c.js
  var immutableData = cajaVM.protect(JSON.parse(dataFromSomewhere));

  var bSrc = //... Text of b.js
  var cSrc = //... Text of c.js

  // For simplicity, let secretBits by a frozen array of 0s and 1s. Let's
say that immutableData
  // happens to be a pair of arrays of unique objects, just as long.
  // Since b and c are isolated, it's ok to give b the secrets because b
can't communicate.
  // And it is ok to give c the ability to communicate, since it doesn't
know the secret.

  var b = eval(bSrc)(immutableData, secretBits);
  var c = eval(cSrc)(immutableData, internetAccess, setInterval);

  // ... for whatever reason, a happens to retain both b and c.


b.js
----------------------
  (function(data, secretBits) {
    return secretBits.map(function(bit, i) {
      return immutableData[bit][i];
    });
  });


c.js
-------------------
  (function(data, internetAccess, setInterval) {
    var len = data.length;
    var wm = WeakMapWithEnumerableKeys();
    for (var i = 0; i < len; i++) {
      for (var bit = 0; bit < 2; bit++) {
        wm.set(data[bit][i], {bit:bit, i:i});
      }
    }

    function poll() {
      var clues = [];
      var keys = wm.getKeys(); // only those not yet collected
      for (var j = 0; j < keys.length; j++) {
        var v = wm.get(keys[j]);
        clues[v.i] = (clues[v.i] || 0) | (1 << v.bit);
      }
      internetAccess(clues); // 1 ==> 0, 2 ==> 1, 3 ==> don't know
    }
    setInterval(poll, 10000);
  });


Note that the "security critical code", a.js, did everything right. By the
normal reasoning we use to think about object computation, b.js and c.js are
indeed isolated, in the sense that there is no vert communications possible
between them. With WeakMaps as currently specified, gc is unobservable and
c.js evil job is harder. With the addition of a getKeys() operation, c.js
could observe which shared immutable objects b.js has dropped.

The example above is of a covert channel, in the sense that b.js *intends*
to send a signal that c.js can read. When b.js does not intend to signal, we
have a side channel rather than a covert channel. Preventing a covert
channel is generally much harder than preventing a side channel, so one
might argue that the addition of this covert channel doesn't matter much.

But JavaScript currently doesn't have any side channels as juicy as this
one. If b.js is not intending to signal to c.js, but rather is just
innocently doing some internal data-dependent algorithmic task, how much can
c.js ascertain about b.js's internals by seeing which shared immutable
objects get dropped? Securing JavaScript is already hard enough as it is.
I'd rather not have to add to it the burden of trying to answer this very
hard question.

Ok, say you don't buy this whole safe mashup fantasy and think we should
just depend on the next and future generations of browsers to secure iframes
from different origins against each other. Well, these are able to
communicate with postMessage. Currently, postMessage just passes copies of
JSON data so there are no object to share. When the frames in communication
are in the same address space and the JSON data is (somehow cheaply known to
be) transitively immutable, a natural and safe optimization is to pass these
by pointer sharing rather than copying. If transitively immutable data is
thread-safe, as it probably is, then this optimization even works between
workers that are running in separate threads in the same address space. (E
does this optimization and I believe it is important. See section 14.3 of <
http://erights.org/talks/thesis/>.)

But if WeakMaps with getKeys() makes gc observable, then this optimization
would open up this juicy side-channel for spying between frames and workers
from different origins.




>
> I personally use the keys on a personal implementation to check and see
> what callbacks may be outstanding, and if I need to reference all the
> Objects of a given type at once.
>
>
> How does your implementation work (or is it native code)?
>
> /be
>
>
> On Thu, Aug 26, 2010 at 8:14 PM, Waldemar Horwat <waldemar at google.com>wrote:
>
>> Erik Arvidsson wrote:
>>
>>> 3. Why isn't there a way to iterate over the keys?
>>>
>>
>> Because then it would be a regular map, not a weak map.  This is something
>> that only a debugger should be able to do.
>>
>>   Waldemar
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>


-- 
    Cheers,
    --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20100831/aca2ac86/attachment.html>


More information about the es-discuss mailing list