-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Snapshot sandbox at start of navigation. #5098
Conversation
This change fixes a race condition where an iframe's sandboxing flag set could be changed in between the start of a navigation and when the response is returned, and the new document created. In that case, it was unclear how the new document could reliably synchronously get the updated flags, or just exactly how late those flags could be changed and still impact the new document. Now, the sandboxing flag set is routed from the beginning of the navigation to the eventual document creation. Ref: whatwg#4783, and also see w3c/webappsec-permissions-policy#256
This makes sense to me in general; I don't see a good way to sanely define this otherwise. I do have one compat concern here: browsers are currently not entirely aligned with each other, or with the spec, in terms of exactly when "start of navigation" is. That means that they can end up picking up different sandboxing flags if people do things that change the sandbox flags right around when navigation might be starting. @natechapin has been doing some awesome work aimed at reconciling those implementation/spec differences in navigation start behavior, but I'm not sure what the status of that is.... It might be worth getting implementation and spec bugs filed on any remaining issues there and maybe addressing them in parallel with this. I don't think we need to block this change on that work, just keep it in mind. |
@natechapin, is that work tracked anywhere? Also related -- https://wpt.fyi/results/html/browsers/sandboxing/sandbox-new-execution-context.html is broken by this change, but it looks like it was relying on pretty subtle timing behaviour, and doesn't work anywhere but in Blink. (In FF, it breaks without devtools: the iframe's contentDocument is null after appendChild and before the script completes. Safari is doing something I don't understand yet.) |
Chrome matches Firefox and the spec in most cases, but there are still some open questions around form submission and following hyperlinks.
|
I'm working on changing form submission in chrome to be async again by implementing plan-to-navigate, but so far I seem to be breaking a lot of tests. I'm not sure when I'll figure it out. As for what I've run into, in the case of an tag with an onclick handler that submits a form manually, the click navigation is supposed to take precedence over the form submission, which is challenging when the click starts a navigation synchronously and then gets later superseded by the async form submission navigation. |
@clelland It looks like Firefox already makes the "should this get an opaque origin?" decision based on the sandbox flags in effect when the navigation started, not the ones in effect at document creation time. That's why Firefox is failing that new test at https://wpt.fyi/results/html/browsers/sandboxing/sandbox-new-execution-context.html. Other sandbox flags, inconsistently, are in fact picked up at document creation time. On the bright side, the fact that Firefox already has this behavior for this flag and it hasn't caused obvious compat issues is a really good sign! @natechapin It's worth filing a separate issue on the form submission bits so we can sort out why the double-submission problems are not a problem for Firefox, with its sync form submission... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great to me, and nice job threading everything through. I think there is a potential cleanup, which is that "determining active sandboxing flags" no longer needs its second argument to exist, right?
@domenic, good catch -- yes, since the only caller that used that parameter has been rewritten, I can take that out now. |
Does "determine active sandbox flags" still make sense as a name for that algorithm, or should we look for a better name, now that it's mostly used to get the flags for a browsing context before it is actually populated with a document? |
Yeah, I'm not really sure what "active" was supposed to connote, but it probably is less applicable now. So maybe just "determine sandboxing flags"? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me. It sounds like at least Blink and Gecko are on-board, so the only thing we're waiting for is tests.
I assume this will be tricky to test since it's about a race condition, but it sounds like you do have a plan in that regard?
In Chromium we can test this directly; on WPT it will be a bit more difficult. There are a couple of things that we can do by manipulating network timing: we can test that a sandbox attribute change after navigation starts doesn't do anything, and we can test that if a second navigation is triggered before the first one returns, that any attribute changes in the interim are effective. If we do that with cross-origin network requests, same-origin network requests, and data/srcdoc documents, we should hopefully trigger any in-process vs out-of-process code paths. After that, if a race is still present, then it's likely to show up as a flaky test. Again, Chrome has infrastructure in place to detect those flakes, but I don't know what other implementers do. I don't think wpt.fyi would be sufficient in that case. |
Yes, that should be pretty simple to test deterministically.
Why is "before the first one returns" relevant? That is, it seems like we can do two tests:
that's all assuming the navigation is started from the same script as sets the sandbox attr. Obviously if we're in a multiple-process case with different origins and the parent sets the sandbox attr "while" the child is navigating itself, that's all racy. It can be somewhat serialized via As far as the "Apparently unnecessary, but will commit more WPT to ensure" bit up-thread, that really depends on what sandbox flags get tested. As I said above, Firefox effectively grabs the "allow-same-origin" flag when navigation starts an the rest when the document is created right now, at least if I read the code right. |
That's basically what I was thinking: to check the case where the first navigation was cancelled, to ensure that the initial flags are not re-used. (I want to test the cancellation case specifically, not just a sequence of two navigations.) There may be another edge case where the first response triggers a redirect to another resource, where we need to ensure that the initial flags are used, even if they were changed in the meantime.
That might be fundamentally racy :( I suppose in theory that the postMessage could be delivered to the child frame, and handled by the onmessage handler there, before the next line of code runs in the parent frame. (It looks like step 8 of the post message steps runs synchronously in the sender, and the queued task could be picked up immediately in the receiver process) (I imagine we could resolve that race by forcing postmessage to wait until the current script finishes before actually sending the message -- make step 8 say "queue a task to queue a task on the posted message task source... -- but that would probably have other unintended effects.)
Do you think there are other flags which are handled differently? Should there be a bug filed on bugzilla to ensure that? |
I think the "allow-same-origin" flag is the only "weird" one at the moment in Firefox. |
Added tests in a WPT PR; updated top comment with the link. |
I'll go ahead and merge this, as everyone seems to be on board and there are tests in web-platform-tests/wpt#20411. I'll trust @clelland to get those reviewed and, if the results show failures on Gecko and WebKit, file bugs and link to them here. |
This change fixes a race condition where an iframe's sandboxing flag set could
be changed in between the start of a navigation and when the response is
returned, and the new document created. In that case, it was unclear how
the new document could reliably synchronously get the updated flags, or
just exactly how late those flags could be changed and still impact the
new document. Now, the sandboxing flag set is routed from the beginning of the
navigation to the eventual document creation.
Ref: #4783, and also see
w3c/webappsec-permissions-policy#256
(See WHATWG Working Mode: Changes for more details.)
/browsers.html ( diff )
/browsing-the-web.html ( diff )
/origin.html ( diff )