Bug 1253673, r=bz
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Tue, 19 Apr 2016 09:56:19 +0100
changeset 331611 739482fdb6fe6b93f9b5a6cf7d50e373d6d84bca
parent 331514 9a8ff2f4978493c3fd9982652a09ffcdf2333a75
child 331612 d4b74afcc60b937f25d54f365be46a8133980209
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1253673
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1253673, r=bz MozReview-Commit-ID: eyZ0XvZkfM
browser/components/about/AboutRedirector.cpp
browser/extensions/pocket/bootstrap.js
docshell/base/nsAboutRedirector.cpp
dom/tests/browser/browser.ini
dom/tests/browser/browser_test_new_window_from_content.js
dom/tests/browser/browser_test_toolbars_visibility.js
dom/tests/browser/dummy.html
dom/tests/browser/test_new_window_from_content_child.html
mobile/android/components/AboutRedirector.js
netwerk/protocol/about/nsAboutBlank.cpp
netwerk/protocol/about/nsAboutProtocolHandler.cpp
netwerk/protocol/about/nsIAboutModule.idl
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -29,20 +29,18 @@ struct RedirEntry {
 };
 
 /*
   Entries which do not have URI_SAFE_FOR_UNTRUSTED_CONTENT will run with chrome
   privileges. This is potentially dangerous. Please use
   URI_SAFE_FOR_UNTRUSTED_CONTENT in the third argument to each map item below
   unless your about: page really needs chrome privileges. Security review is
   required before adding new map entries without
-  URI_SAFE_FOR_UNTRUSTED_CONTENT.  Also note, however, that adding
-  URI_SAFE_FOR_UNTRUSTED_CONTENT will allow random web sites to link to that
-  URI.  If you want to prevent this, add MAKE_UNLINKABLE as well.
- */
+  URI_SAFE_FOR_UNTRUSTED_CONTENT.
+*/
 static RedirEntry kRedirMap[] = {
 #ifdef MOZ_SAFE_BROWSING
   { "blocked", "chrome://browser/content/blockedSite.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
 #endif
@@ -76,51 +74,56 @@ static RedirEntry kRedirMap[] = {
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
   { "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
   { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul",
     nsIAboutModule::ALLOW_SCRIPT },
+  // Linkable because of indexeddb use (bug 1228118)
   { "home", "chrome://browser/content/abouthome/aboutHome.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
     nsIAboutModule::ALLOW_SCRIPT |
+    nsIAboutModule::MAKE_LINKABLE |
     nsIAboutModule::ENABLE_INDEXED_DB },
   // the newtab's actual URL will be determined when the channel is created
   { "newtab", "about:blank",
     nsIAboutModule::ALLOW_SCRIPT },
   { "preferences", "chrome://browser/content/preferences/in-content/preferences.xul",
     nsIAboutModule::ALLOW_SCRIPT },
   { "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul",
     nsIAboutModule::ALLOW_SCRIPT },
 #ifdef MOZ_SERVICES_HEALTHREPORT
   { "healthreport", "chrome://browser/content/abouthealthreport/abouthealth.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
 #endif
   { "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
+  // Linkable because of indexeddb use (bug 1228118)
   { "loopconversation", "chrome://loop/content/panels/conversation.html",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT |
+    nsIAboutModule::MAKE_LINKABLE |
     nsIAboutModule::ENABLE_INDEXED_DB },
+  // Linkable because of indexeddb use (bug 1228118)
   { "looppanel", "chrome://loop/content/panels/panel.html",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT |
+    nsIAboutModule::MAKE_LINKABLE |
     nsIAboutModule::ENABLE_INDEXED_DB,
     // Shares an IndexedDB origin with about:loopconversation.
     "loopconversation" },
   { "reader", "chrome://global/content/reader/aboutReader.html",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
-    nsIAboutModule::MAKE_UNLINKABLE |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
 };
 static const int kRedirTotal = ArrayLength(kRedirMap);
 
 static nsAutoCString
 GetAboutModuleName(nsIURI *aURI)
 {
   nsAutoCString path;
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -99,18 +99,17 @@ function PocketAboutPage(chromeURL, abou
   this.classID = Components.ID(classID);
   this.description = description;
 }
 PocketAboutPage.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
   getURIFlags: function(aURI) {
     return Ci.nsIAboutModule.ALLOW_SCRIPT |
            Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
-           Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT |
-           Ci.nsIAboutModule.MAKE_UNLINKABLE;
+           Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
   },
 
   newChannel: function(aURI, aLoadInfo) {
     let newURI = Services.io.newURI(this.chromeURL, null, null);
     let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
                                                             aLoadInfo);
     channel.originalURI = aURI;
     return channel;
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -64,17 +64,19 @@ static RedirEntry kRedirMap[] = {
   },
 #endif
   {
     "license", "chrome://global/content/license.html",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
   },
   {
     "logo", "chrome://branding/content/about.png",
-    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
+    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+    // Linkable for testing reasons.
+    nsIAboutModule::MAKE_LINKABLE
   },
   {
     "memory", "chrome://global/content/aboutMemory.xhtml",
     nsIAboutModule::ALLOW_SCRIPT
   },
   {
     "mozilla", "chrome://global/content/mozilla.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
@@ -116,16 +118,18 @@ static RedirEntry kRedirMap[] = {
   },
 #endif
   // about:srcdoc is unresolvable by specification.  It is included here
   // because the security manager would disallow srcdoc iframes otherwise.
   {
     "srcdoc", "about:blank",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT |
+      // Needs to be linkable so content can touch its own srcdoc frames
+      nsIAboutModule::MAKE_LINKABLE |
       nsIAboutModule::URI_CAN_LOAD_IN_CHILD
   },
   {
     "support", "chrome://global/content/aboutSupport.xhtml",
     nsIAboutModule::ALLOW_SCRIPT
   },
   {
     "telemetry", "chrome://global/content/aboutTelemetry.xhtml",
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -2,16 +2,17 @@
 support-files =
   browser_frame_elements.html
   page_privatestorageevent.html
   position.html
   test-console-api.html
   test_bug1004814.html
   worker_bug1004814.js
   geo_leak_test.html
+  dummy.html
   !/dom/tests/mochitest/geolocation/network_geolocation.sjs
 
 [browser_test_toolbars_visibility.js]
 support-files =
   test_new_window_from_content_child.html
 [browser_bug1008941_dismissGeolocationHanger.js]
 skip-if = buildapp == 'mulet'
 [browser_test__content.js]
--- a/dom/tests/browser/browser_test_new_window_from_content.js
+++ b/dom/tests/browser/browser_test_new_window_from_content.js
@@ -34,17 +34,16 @@
      This file attempts to test each window opening technique against all possible settings for
      each preference.
 */
 
 Cu.import("resource://gre/modules/Task.jsm");
 
 const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const kContentDoc = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html";
-const kContentScript = "chrome://mochitests/content/browser/dom/tests/browser/test_new_window_from_content_child.js";
 const kNewWindowPrefKey = "browser.link.open_newwindow";
 const kNewWindowRestrictionPrefKey = "browser.link.open_newwindow.restriction";
 const kSameTab = "same tab";
 const kNewWin = "new window";
 const kNewTab = "new tab";
 
 SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
 
@@ -102,40 +101,41 @@ registerCleanupFunction(function() {
  * closes it before resolving.
  *
  * @param aBrowser the <xul:browser> with the test document
  * @param aExpectation one of kSameTab, kNewWin, or kNewTab.
  * @return a Promise that resolves when the expectation is fulfilled,
  *         and cleaned up after.
  */
 function prepareForResult(aBrowser, aExpectation) {
+  let expectedSpec = kContentDoc.replace(/[^\/]*$/, "dummy.html");
   switch(aExpectation) {
     case kSameTab:
       return Task.spawn(function*() {
         yield BrowserTestUtils.browserLoaded(aBrowser);
-        is(aBrowser.currentURI.spec, "about:robots", "Should be at about:robots");
+        is(aBrowser.currentURI.spec, expectedSpec, "Should be at dummy.html");
         // Now put the browser back where it came from
         yield BrowserTestUtils.loadURI(aBrowser, kContentDoc);
         yield BrowserTestUtils.browserLoaded(aBrowser);
       });
       break;
     case kNewWin:
       return Task.spawn(function*() {
         let newWin = yield BrowserTestUtils.waitForNewWindow();
         let newBrowser = newWin.gBrowser.selectedBrowser;
         yield BrowserTestUtils.browserLoaded(newBrowser);
-        is(newBrowser.currentURI.spec, "about:robots", "Should be at about:robots");
+        is(newBrowser.currentURI.spec, expectedSpec, "Should be at dummy.html");
         yield BrowserTestUtils.closeWindow(newWin);
       });
       break;
     case kNewTab:
       return Task.spawn(function*() {
         let newTab = yield BrowserTestUtils.waitForNewTab(gBrowser);
-        is(newTab.linkedBrowser.currentURI.spec, "about:robots",
-           "Should be at about:robots");
+        is(newTab.linkedBrowser.currentURI.spec, expectedSpec,
+           "Should be at dummy.html");
         yield BrowserTestUtils.removeTab(newTab);
       });
       break;
     default:
       ok(false, "prepareForResult can't handle an expectation of " + aExpectation)
       return;
   }
 
--- a/dom/tests/browser/browser_test_toolbars_visibility.js
+++ b/dom/tests/browser/browser_test_toolbars_visibility.js
@@ -1,12 +1,14 @@
 // Tests that toolbars have proper visibility when opening a new window
 // in either content or chrome context.
 
-const CONTENT_PAGE = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html";
+const ROOT = "http://www.example.com/browser/dom/tests/browser/";
+const CONTENT_PAGE = ROOT + "test_new_window_from_content_child.html";
+const TARGET_PAGE = ROOT + "dummy.html";
 
 /**
  * This function retrieves the visibility state of the toolbars of a
  * window within the content context.
  *
  * @param aBrowser (<xul:browser>)
  *        The browser to query for toolbar visibility states
  * @returns Promise
@@ -194,27 +196,27 @@ add_task(function*() {
  * A window opened with default parameters should have all toolbars visible.
  *
  * A window opened with "location=no, personalbar=no, toolbar=no, scrollbars=no,
  * menubar=no, status=no", should not have any toolbar visible.
  */
 add_task(function* () {
   // First open a default window from this chrome context
   let defaultWindowPromise = BrowserTestUtils.waitForNewWindow();
-  window.open("about:robots", "_blank");
+  window.open(TARGET_PAGE, "_blank");
   let defaultWindow = yield defaultWindowPromise;
 
   // Check that all toolbars are visible
   let toolbars = getToolbarsFromWindowChrome(defaultWindow);
   testDefaultToolbars(toolbars);
 
   // Now lets open a window with toolbars hidden from this chrome context
   let features = "location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no";
   let popupWindowPromise = BrowserTestUtils.waitForNewWindow();
-  window.open("about:robots", "_blank", features);
+  window.open(TARGET_PAGE, "_blank", features);
   let popupWindow = yield popupWindowPromise;
 
   // Test none of the tooolbars are visible
   let hiddenToolbars = getToolbarsFromWindowChrome(popupWindow);
   testNonDefaultChromeToolbars(hiddenToolbars);
 
   // Cleanup
   yield BrowserTestUtils.closeWindow(defaultWindow);
copy from browser/base/content/test/general/dummy_page.html
copy to dom/tests/browser/dummy.html
--- a/dom/tests/browser/test_new_window_from_content_child.html
+++ b/dom/tests/browser/test_new_window_from_content_child.html
@@ -3,23 +3,23 @@
   <meta charset="utf-8">
   <title>Test popup window opening behaviour</title>
 </head>
 <body>
   <p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p>
   <p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p>
   <p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p>
   <p><a id="winOpenNoURLNonDefault" href="#" onclick="return openBlankWindow('location=no, toolbar=no, height=100, width=100');">Open a blank new window via window.open with non-default features.</a></p>
-  <p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p>
+  <p><a id="targetBlank" href="dummy.html" target="_blank">Open a new window via target="_blank".</a></p>
 </body>
 </html>
 
 <script>
 function openWindow(aFeatures="") {
-  window.open("about:robots", "_blank", aFeatures);
+  window.open("dummy.html", "_blank", aFeatures);
   return false;
 }
 
 function openBlankWindow(aFeatures="") {
   window.open("", "_blank", aFeatures);
   return false;
 }
 </script>
--- a/mobile/android/components/AboutRedirector.js
+++ b/mobile/android/components/AboutRedirector.js
@@ -53,17 +53,16 @@ var modules = {
   },
   downloads: {
     uri: "chrome://browser/content/aboutDownloads.xhtml",
     privileged: true
   },
   reader: {
     uri: "chrome://global/content/reader/aboutReader.html",
     privileged: false,
-    dontLink: true,
     hide: true
   },
   feedback: {
     uri: "chrome://browser/content/aboutFeedback.xhtml",
     privileged: true
   },
   privatebrowsing: {
     uri: "chrome://browser/content/aboutPrivateBrowsing.xhtml",
@@ -97,18 +96,16 @@ AboutRedirector.prototype = {
   },
 
   // nsIAboutModule
   getURIFlags: function(aURI) {
     let flags;
     let moduleInfo = this._getModuleInfo(aURI);
     if (moduleInfo.hide)
       flags = Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
-    if (moduleInfo.dontLink)
-      flags = flags | Ci.nsIAboutModule.MAKE_UNLINKABLE;
 
     return flags | Ci.nsIAboutModule.ALLOW_SCRIPT;
   },
 
   newChannel: function(aURI, aLoadInfo) {
     let moduleInfo = this._getModuleInfo(aURI);
 
     var ios = Cc["@mozilla.org/network/io-service;1"].
--- a/netwerk/protocol/about/nsAboutBlank.cpp
+++ b/netwerk/protocol/about/nsAboutBlank.cpp
@@ -35,16 +35,17 @@ nsAboutBlank::NewChannel(nsIURI* aURI,
     return rv;
 }
 
 NS_IMETHODIMP
 nsAboutBlank::GetURIFlags(nsIURI *aURI, uint32_t *result)
 {
     *result = nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
               nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
+              nsIAboutModule::MAKE_LINKABLE |
               nsIAboutModule::HIDE_FROM_ABOUTABOUT;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAboutBlank::GetIndexedDBOriginPostfix(nsIURI *aURI, nsAString &result)
 {
     SetDOMStringToNull(result);
--- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp
@@ -32,17 +32,17 @@ static bool IsSafeForUntrustedContent(ns
   return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0;
 }
 
 static bool IsSafeToLinkForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) {
   uint32_t flags;
   nsresult rv = aModule->GetURIFlags(aURI, &flags);
   NS_ENSURE_SUCCESS(rv, false);
 
-  return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) && !(flags & nsIAboutModule::MAKE_UNLINKABLE);
+  return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) && (flags & nsIAboutModule::MAKE_LINKABLE);
 }
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler,
     nsIProtocolHandlerWithDynamicFlags, nsISupportsWeakReference)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIProtocolHandler methods:
@@ -81,19 +81,19 @@ nsAboutProtocolHandler::GetFlagsForURI(n
       // Swallow this and just tell the consumer the default:
       return NS_OK;
     }
     uint32_t aboutModuleFlags = 0;
     rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags);
     // This should never happen, so pass back the error:
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // If marked as safe, and not marked unlinkable, pass 'safe' flags.
+    // If marked as safe, and marked linkable, pass 'safe' flags.
     if ((aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) &&
-        !(aboutModuleFlags & nsIAboutModule::MAKE_UNLINKABLE)) {
+        (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE)) {
         *aFlags = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
             URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAboutProtocolHandler::NewURI(const nsACString &aSpec,
--- a/netwerk/protocol/about/nsIAboutModule.idl
+++ b/netwerk/protocol/about/nsIAboutModule.idl
@@ -18,23 +18,23 @@ interface nsIAboutModule : nsISupports
      *
      * @param aURI the uri of the new channel
      * @param aLoadInfo the loadinfo of the new channel
      */
     nsIChannel newChannel(in nsIURI aURI,
                           in nsILoadInfo aLoadInfo);
 
     /**
-     * A flag that indicates whether a URI is safe for untrusted
-     * content.  If it is, web pages and so forth will be allowed to
-     * link to this about: URI (unless MAKE_UNLINKABLE is also specified),
-     * and the about: protocol handler will enforce that the principal
-     * of channels created for it be based on their originalURI or URI
-     * (depending on the channel flags), by setting their "owner" to null.
-     * Otherwise, only chrome will be able to link to it.
+     * A flag that indicates whether a URI should be run with content
+     * privileges. If it is, the about: protocol handler will enforce that
+     * the principal of channels created for it be based on their
+     * originalURI or URI (depending on the channel flags), by setting
+     * their "owner" to null.
+     * If content needs to be able to link to this URI, specify
+     * URI_CONTENT_LINKABLE as well.
      */
     const unsigned long URI_SAFE_FOR_UNTRUSTED_CONTENT = (1 << 0);
 
     /**
      * A flag that indicates whether script should be enabled for the
      * given about: URI even if it's disabled in general.
      */
     const unsigned long ALLOW_SCRIPT = (1 << 1);
@@ -56,22 +56,27 @@ interface nsIAboutModule : nsISupports
     const unsigned long URI_CAN_LOAD_IN_CHILD = (1 << 4);
 
     /**
      * A flag that indicates that this URI must be loaded in a child process
      */
     const unsigned long URI_MUST_LOAD_IN_CHILD = (1 << 5);
 
     /**
-     * A flag that indicates that this URI should be unlinkable despite being
-     * safe for untrusted content.
+     * Obsolete. This flag no longer has any effect and will be removed in future.
      */
     const unsigned long MAKE_UNLINKABLE = (1 << 6);
 
     /**
+     * A flag that indicates that this URI should be linkable from content.
+     * Ignored unless URI_SAFE_FOR_UNTRUSTED_CONTENT is also specified.
+     */
+    const unsigned long MAKE_LINKABLE = (1 << 7);
+
+    /**
      * A method to get the flags that apply to a given about: URI.  The URI
      * passed in is guaranteed to be one of the URIs that this module
      * registered to deal with.
      */
     unsigned long getURIFlags(in nsIURI aURI);
 
     /**
      * Returns the Indexed DB origin's postfix used for the given about: URI.