From aa37ddcd27dab1164fcb0ad066134efd6bc72499 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Mon, 6 Feb 2017 12:14:21 +0000 Subject: [PATCH] Bug 1317921 Part 1: Handle nested URIs properly in E10SUtils.jsm. r=Gijs --- browser/modules/E10SUtils.jsm | 161 +++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 72 deletions(-) diff --git a/browser/modules/E10SUtils.jsm b/browser/modules/E10SUtils.jsm index 6802bc0e0f67..d2f6b243ee99 100644 --- a/browser/modules/E10SUtils.jsm +++ b/browser/modules/E10SUtils.jsm @@ -13,8 +13,12 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions", "extensions.webextensions.remote", false); +XPCOMUtils.defineLazyPreferenceGetter(this, "useSeparateFileUriProcess", + "browser.tabs.remote.separateFileUriProcess", false); XPCOMUtils.defineLazyModuleGetter(this, "Utils", "resource://gre/modules/sessionstore/Utils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "console", + "resource://gre/modules/Console.jsm"); function getAboutModule(aURL) { // Needs to match NS_GetAboutModuleName @@ -56,7 +60,7 @@ this.E10SUtils = { }, getRemoteTypeForURI(aURL, aMultiProcess, - aPreferredRemoteType = DEFAULT_REMOTE_TYPE) { + aPreferredRemoteType = DEFAULT_REMOTE_TYPE) { if (!aMultiProcess) { return NOT_REMOTE; } @@ -66,92 +70,105 @@ this.E10SUtils = { aURL = "about:blank"; } - // Javascript urls can load in any process, they apply to the current document - if (aURL.startsWith("javascript:")) { - return aPreferredRemoteType; + let uri; + try { + uri = Services.io.newURI(aURL); + } catch (e) { + // If we have an invalid URI, it's still possible that it might get + // fixed-up into a valid URI later on. However, we don't want to return + // aPreferredRemoteType here, in case the URI gets fixed-up into + // something that wouldn't normally run in that process. + return DEFAULT_REMOTE_TYPE; } - // We need data: URI's to load in a remote process, because some of our - // tests rely on this. For blob: URI's, load them in their originating - // process unless it is non-remote. In that case, favor a remote (sandboxed) - // process with fewer privileges to limit exposure. - if (aURL.startsWith("data:") || aURL.startsWith("blob:")) { - return aPreferredRemoteType == NOT_REMOTE ? DEFAULT_REMOTE_TYPE - : aPreferredRemoteType; - } - - if (aURL.startsWith("file:")) { - return Services.prefs.getBoolPref("browser.tabs.remote.separateFileUriProcess") - ? FILE_REMOTE_TYPE : DEFAULT_REMOTE_TYPE; - } - - if (aURL.startsWith("about:")) { - // We need to special case about:blank because it needs to load in any. - if (aURL == "about:blank") { - return aPreferredRemoteType; - } - - let url = Services.io.newURI(aURL); - let module = getAboutModule(url); - // If the module doesn't exist then an error page will be loading, that - // should be ok to load in any process - if (!module) { - return aPreferredRemoteType; - } - - let flags = module.getURIFlags(url); - if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) { - return DEFAULT_REMOTE_TYPE; - } - - // If the about page can load in parent or child, it should be safe to - // load in any remote type. - if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) { - return aPreferredRemoteType; - } + return this.getRemoteTypeForURIObject(uri, aMultiProcess, + aPreferredRemoteType); + }, + getRemoteTypeForURIObject(aURI, aMultiProcess, + aPreferredRemoteType = DEFAULT_REMOTE_TYPE) { + if (!aMultiProcess) { return NOT_REMOTE; } - if (aURL.startsWith("chrome:")) { - let url; - try { - // This can fail for invalid Chrome URIs, in which case we will end up - // not loading anything anyway. - url = Services.io.newURI(aURL); - } catch (ex) { + switch (aURI.scheme) { + case "javascript": + // javascript URIs can load in any, they apply to the current document. return aPreferredRemoteType; - } - let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIXULChromeRegistry); - if (chromeReg.mustLoadURLRemotely(url)) { - return DEFAULT_REMOTE_TYPE; - } + case "data": + case "blob": + // We need data: and blob: URIs to load in any remote process, because + // they need to be able to load in whatever is the current process + // unless it is non-remote. In that case we don't want to load them in + // the parent process, so we load them in the default remote process, + // which is sandboxed and limits any risk. + return aPreferredRemoteType == NOT_REMOTE ? DEFAULT_REMOTE_TYPE + : aPreferredRemoteType; - if (chromeReg.canLoadURLRemotely(url) && - aPreferredRemoteType != NOT_REMOTE) { - return DEFAULT_REMOTE_TYPE; - } + case "file": + return useSeparateFileUriProcess ? FILE_REMOTE_TYPE + : DEFAULT_REMOTE_TYPE; - return NOT_REMOTE; + case "about": + let module = getAboutModule(aURI); + // If the module doesn't exist then an error page will be loading, that + // should be ok to load in any process + if (!module) { + return aPreferredRemoteType; + } + + let flags = module.getURIFlags(aURI); + if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) { + return DEFAULT_REMOTE_TYPE; + } + + // If the about page can load in parent or child, it should be safe to + // load in any remote type. + if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) { + return aPreferredRemoteType; + } + + return NOT_REMOTE; + + case "chrome": + let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]. + getService(Ci.nsIXULChromeRegistry); + if (chromeReg.mustLoadURLRemotely(aURI)) { + return DEFAULT_REMOTE_TYPE; + } + + if (chromeReg.canLoadURLRemotely(aURI) && + aPreferredRemoteType != NOT_REMOTE) { + return DEFAULT_REMOTE_TYPE; + } + + return NOT_REMOTE; + + case "moz-extension": + return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE; + + default: + // For any other nested URIs, we use the innerURI to determine the + // remote type. In theory we should use the innermost URI, but some URIs + // have fake inner URIs (e.g. about URIs with inner moz-safe-about) and + // if such URIs are wrapped in other nested schemes like view-source:, + // we don't want to "skip" past "about:" by going straight to the + // innermost URI. Any URIs like this will need to be handled in the + // cases above, so we don't still end up using the fake inner URI here. + if (aURI instanceof Ci.nsINestedURI) { + let innerURI = aURI.QueryInterface(Ci.nsINestedURI).innerURI; + return this.getRemoteTypeForURIObject(innerURI, aMultiProcess, + aPreferredRemoteType); + } + + return validatedWebRemoteType(aPreferredRemoteType); } - - if (aURL.startsWith("moz-extension:")) { - return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE; - } - - if (aURL.startsWith("view-source:")) { - return this.getRemoteTypeForURI(aURL.substr("view-source:".length), - aMultiProcess, aPreferredRemoteType); - } - - return validatedWebRemoteType(aPreferredRemoteType); }, shouldLoadURIInThisProcess(aURI) { let remoteType = Services.appinfo.remoteType; - return remoteType == this.getRemoteTypeForURI(aURI.spec, true, remoteType); + return remoteType == this.getRemoteTypeForURIObject(aURI, true, remoteType); }, shouldLoadURI(aDocShell, aURI, aReferrer) {