The global object in browsers

Brendan Eich brendan at mozilla.com
Mon Jul 6 14:35:36 PDT 2009


Picking up this older thread, I owed you and others in TC39 a reply  
from two face-to-face meetings ago.

On Feb 18, 2009, at 3:57 AM, Brendan Eich wrote:

> On Feb 17, 2009, at 11:18 PM, Mark Miller wrote:
>
>> You misunderstood me a bit, but no matter.
>
> Sorry, I couldn't see how to interpret your proposal otherwise. Let  
> me know what I missed if you like.
>
> Maciej's right, the object identities practically dictate split  
> windows. I suppose the original DOM level 0 could have made the  
> split explicit, but it was not implemented this way at all back in  
> the day. Different browser implementors solved the security and  
> performance problems in similar ways, to preserve the view of the  
> persistent window container as the one true "window object", really  
> a proxy with multiple global objects hidden within it.

The issue we were debating in the TC39 meeting in March at Yahoo! was  
whether |this|, window, self, and any other synonyms should bind to  
the inner or outer window object.

Recall that split windows arise because the outer window is the  
persistent object reference returned by window.open, frames[n],  
document.getElementById(frameId), etc. that perdures across document  
loads into that window or frame. The inner window is the ECMA-262  
global object, a capability through which unmediated access to  
sensitive variables including much of the DOM happens.

The inner window is thus the final object on the scope chain of all  
objects created for a particular page, whether induced by markup or  
created by DOM API calls. The outer window is a proxy that monitors  
accesses and forwards them to the current inner window, or denies them.

During the evolution of split windows in Mozilla's codebase, we  
observed that it's frightfully easy to leak the inner-window  
capability if it is allowed to escape to script. So we made |this|,  
window, and self bind to the outer window.

We even made our __parent__ extension, the read-only and undeletable  
property reifying the intrinsic scope chain link in SpiderMonkey,  
return the outer window, not the inner window that is the last object  
on the scope chain of objects subordinate to that inner window, e.g.,  
the current document, where document.__parent__ would seemingly  
reference the inner window containing document.

Instead, we "outerize" inner window references as they try to escape  
to user-level JS. Only privileged API can get the capability, and of  
course it's baked in as the lexical scope chain link by the JS  
compiler for top-level functions and variously optimized closures.

If the outer window sees that the "outerized" access is from the same  
origin as the *current* inner window, it allows access. This is  
expensive, or at least it has been until recently. With tracing and  
polymorphic inline caching and the like, it's no longer too expensive  
to consider imposing on all accesses.

(Maciej and I debated this with David-Sarah Hopwood for function  
calls, and the jury's still out; more on this later, but see the paper  
cited below for some encouraging results. But this is only one of the  
reasons for split windows, so even if we did check access always, we  
wouldn't give up split windows.)

The DOM does not use a capability model, rather it monitors certain  
references to implement access control policies, again because  
monitoring all references is too costly (or was in the nineties); also  
access control was still the rage back when JS and Java were co- 
evolving their security models. These access control judgments depend  
on the baked-in and unforgeable intrinsic scope chain link, in order  
to find the principals for subject script and target object. But the  
DOM checks only some accesses, not all -- and in particular not access  
to JS variables.

Here's the paper I mentioned at the last face-to-face but forgot to  
follow up on (perhaps you've seen it already): http://www.adambarth.com/papers/2009/barth-weinberger-song.pdf 
  -- a nice paper on the problem of mixing capability with access- 
control models -- old news to you I'm sure in its general results, but  
perhaps novel in the split window and DOM vs. JS browser conflict.

Section 4.2 in the paper talks about a split window bug, or possibly  
the lack of split windows altogether -- I *think*; I haven't looked  
closely at the WebKit code in question. 4.3 describes a bug that is  
very familiar to Mozilla JS hackers; nothing against WebKit here,  
we're all in the same boat.

The paper's conclusion that defense in depth requires universal access  
control checks at the JS level may not sit well with obj-cap fans, but  
it fits the threat-space we've been facing all these years. Blame the  
DOM, try to reform it or rewrite it (Caja, ADSafe) to use capabilities  
instead of ids and names and too many references, but in the short run  
the right fix for browser vendors dealing with the web-as-it-is looks  
to me like this:

Convolve security labels with polymorphic inline cache keys ("shapes")  
to fast-path same-origin accesses, and check all others for complete  
mediation. This work is happening in SpiderMonkey now. It will not  
relieve us of compatibility requirements for split windows, but it  
might allow us to bind |this| to the inner window. That doesn't say we  
*should * so bind in the HTML 5 spec, of course.

IIRC from the March meeting, you and Waldemar were in favor of binding  
|this| etc. to the inner window. I believe if we had done that in  
Mozilla starting with Firefox 1.5 (when split windows were finally  
implemented) we would have had significantly more exploits than we  
have had given the "outerizing" defense we chose.

Of course you shouldn't be able to tell whether |this| binds to inner  
or outer window, except when attacking a browser that access-checks  
only via the outer window. One that checks all accesses would stop all  
attacks, even when the inner-window capability leaked.

If we must have split windows in all top browser implementations (so  
the argument goes), then we must have them in a spec. If not ECMA-262,  
then HTML5. If split windows, then what |this| binds to (outer or  
inner) needs to be spec'ed. So here we are. Comments?

/be

> The ability to "use lexical scope" (however the syntax turns out)  
> and make the global variables truly lexical bindings in a top-level  
> environment, not properties of some grotty object, is something I  
> look forward to in Harmony:
>
> http://wiki.ecmascript.org/doku.php?id=strawman:lexical_scope
>
> /be
>
> _______________________________________________
> Es-discuss mailing list
> Es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss



More information about the es-discuss mailing list