[whatwg] The choice of script global object to use when the script element is moved

On Thu, 9 Sep 2010, Henri Sivonen wrote:
> On Sep 9, 2010, at 00:47, Ian Hickson wrote:
> > On Fri, 3 Sep 2010, Henri Sivonen wrote:
> >> 
> >> When evaluating a parser-inserted script, there are three potential 
> >> script global objects to use:
> >>
> >> 1) The script global object of the document whose active parser the 
> >> parser that inserted the script is.
> >>
> >> 2) The script global object of the document that owned the script 
> >> element at the time of invoking the "run" algorithm.
> >>
> >> 3) The script global object of the document that owns the script 
> >> element at the time of script evaluation.
> > 
> > #1 and #2 are dodgy because the documents in question might have been 
> > GC'ed by that point.
> 
> This problem doesn't arise in Gecko, because if a document gets GC'ed, 
> the pending external script loads that have started while the script was 
> in that document never get evaluated. That is, the document (via its 
> script loader) owns the pending loads--not the script node.

That's a problem in itself. It means you are exposing GC behaviour.

I suppose we could make it so that scripts get neutered when the document 
that they were first associated with gets unloaded. Would that work?


> >> The spec says the answer is #3. WebKit (with HTML5 parser or without) 
> >> says the answer is #1. Firefox 3.6 says the answer is #2.
> >> 
> >> I doubt that there are Web compat considerations forcing this choice, 
> >> because IE8 doesn't get as far as running the script in this case. 
> >> IE9 tries to do either #2 or #3 (not sure which) succeeding for 
> >> inline scripts and failing for external ones. (IIRC, the text in the 
> >> spec that explains the distinction between 1 and the other (without 
> >> explaining the distinction between 2 and 3) was added specifically 
> >> for the benefit of the IE team.)
> > 
> > I'm not sure exactly which sentence you mean here, but I'm happy to 
> > clarify text if anything is ambiguous.
> 
> The example 
> http://www.whatwg.org/specs/web-apps/current-work/#scripts-that-modify-the-page-as-it-is-being-parsed 
> doesn't cover the script moving to a third document between the first 
> parser-performed insertion and the external script finishing loading.

I've added an example for this; I'll change it if we change the spec.


> > One advantage of doing #3 is that, as Adam pointed out, the 
> > implementation is required to get the security context at the last 
> > minute, where it's most likely to be up to date (e.g. with 
> > document.domain changes, etc) even in the case of the <script> element 
> > not being moved around.
> 
> For last-minute security context grabbing to have an extra benefit, 
> wouldn't the security checks have to be re-performed at last-minute?

I don't see why. The idea is to make sure that further origin checks are 
done with the latest information, to _enable_ further interactions; not to 
reduce the number of interactions. Doing the other checks later wouldn't 
enable anything new as far as I can tell.


> > #3 is simpler to understand, IMHO. However, #1 is not particularly 
> > hard to spec, and I guess does decrease the odds of scripts being made 
> > to run accidentally by a bug in a script using sandboxed or CSP 
> > context.
> > 
> > If everyone is ok with #1, I'm happy to change the spec accordingly.
> 
> In case we don't end up doing #1, I have a follow-up question:
> 
> Is there a good reason to perform the "run" algorithm against the 
> then-current owner doc as opposed to the parser's doc for 
> parser-inserted scripts? (Performing it against the parser's doc would 
> require fewer changes to Gecko but implementing the checks against the 
> owner doc would be doable.)

If we don't end up doing #1, then the answer would be that doing anything 
against the parser's doc would be quite inconsistent.


> >> Suppose there are two docs from one Origin. The document that the 
> >> parser is associated with doesn't have a CSP. A script in it moves a 
> >> node in such a way that the parser ends up inserting subsequent 
> >> scripts into another document. That document has a CSP that bans 
> >> scripts. Would you consider it a bug if a script ran in the context 
> >> of the script global object of the document whose CSP says no 
> >> scripts?
> > 
> > If the CSP applied then the script would not run, if it didn't then it 
> > would run in the context of the doc without the CSP. I'm sure we 
> > wouldn't want to define the CSP as applying to nodes in a different 
> > way than the global scope is picked.
> 
> Currently, CSP is evaluated at the "run" algorithm time. This seems a 
> natural extension to the "scripting disabled" check that happens at 
> "run" algorithm time.

I guess that makes sense.

I don't really see a scenario in which a non-hostile script would insert 
possibly-untrusted scripts into another document _after_ they have been 
created and 'run', but _before_ they have been 'executed'. If the are 
inserted into the other doc _before_ they are 'run', you'd want the CSP to 
apply, and you'd want either #2 or #3 from the list above, though I am 
finding it hard to imagine a scenario in which _parser-created_ scripts 
would be legitimately going through such a dance.

(If the script is hostile, none of this matters, you already have XSS.)


Anyway. I can see arguments for all the various behaviours here.

Proposal #1:

 * We define the parser's associated Document as being the original 
   Document for any node the parser creates, and we define the Document in 
   Document.createElement() as the original Document for any node it 
   creates.

 * We say that when a document is unloaded, any <script>s for which the 
   document is the original Document get neutered, so that they can't 
   execute any more.

 * We say that the Document used for Window, for fetch origin, for 
   cookies, for the various pending script stuff and lists of scripts, for 
   delaying the load event, for /neutralised doc/, etc, is the original 
   Document, not the Document the script node is in.


Proposal #2:

 * We say that the Document used for Window, for fetch origin, for 
   cookies, for the various pending script stuff and lists of scripts, for 
   delaying the load event, for /neutralised doc/, etc, is the Document
   that the script element was in when the 'running a script' algorithm is 
   run (if any; if there isn't one, nothing happens).

 * We say that if the document in question gets unloaded between the time 
   the 'run' algorithm ran and the 'execute' algorithm runs, then the 
   'execute' algorithm does nothing.


Proposal #3:

 * We leave the spec as is.


Any opinions on which is best?

-- 
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

Received on Tuesday, 1 February 2011 17:07:13 UTC