Bug 1335475 - Deny plugins from non-HTTP/HTTPS origins. r=bytesized,qdot
authorBenjamin Smedberg <benjamin@smedbergs.us>
Tue, 07 Mar 2017 09:34:03 -0500
changeset 358483 8068fb1cc45e8af91a58c2a37565536b25bcf615
parent 358482 17a2effb01e243c5e1df6bc852d68b38329bc28a
child 358484 e12dcb4be8551c14073c891a4c9f790e0d790215
push id31827
push usercbook@mozilla.com
push dateTue, 16 May 2017 10:34:19 +0000
treeherdermozilla-central@49365d675cbb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbytesized, qdot
bugs1335475
milestone55.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 1335475 - Deny plugins from non-HTTP/HTTPS origins. r=bytesized,qdot MozReview-Commit-ID: 3kPeycfMWVw
dom/base/nsDocument.cpp
dom/plugins/test/mochitest/browser.ini
dom/plugins/test/mochitest/browser_bug1335475.js
dom/plugins/test/mochitest/plugin_test.html
modules/libpref/init/all.js
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -13230,33 +13230,55 @@ ArrayContainsTable(const nsTArray<nsCStr
  * For more information, see
  * toolkit/components/url-classifier/flash-block-lists.rst
  */
 FlashClassification
 nsDocument::PrincipalFlashClassification()
 {
   nsresult rv;
 
-  // If flash blocking is disabled, it is equivalent to all sites being
-  // on neither list.
-  if (!Preferences::GetBool("plugins.flashBlock.enabled")) {
+  bool httpOnly = Preferences::GetBool("plugins.http_https_only", true);
+  bool flashBlock = Preferences::GetBool("plugins.flashBlock.enabled", false);
+
+  // If neither pref is on, skip the null-principal and principal URI checks.
+  if (!httpOnly && !flashBlock) {
     return FlashClassification::Unknown;
   }
 
   nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
   if (principal->GetIsNullPrincipal()) {
     return FlashClassification::Denied;
   }
 
   nsCOMPtr<nsIURI> classificationURI;
   rv = principal->GetURI(getter_AddRefs(classificationURI));
   if (NS_FAILED(rv) || !classificationURI) {
     return FlashClassification::Denied;
   }
 
+  if (httpOnly) {
+    // Only allow plugins for documents from an HTTP/HTTPS origin. This should
+    // allow dependent data: URIs to load plugins, but not:
+    // * chrome documents
+    // * "bare" data: loads
+    // * FTP/gopher/file
+    nsAutoCString scheme;
+    rv = classificationURI->GetScheme(scheme);
+    if (NS_WARN_IF(NS_FAILED(rv)) ||
+        !(scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
+      return FlashClassification::Denied;
+    }
+  }
+
+  // If flash blocking is disabled, it is equivalent to all sites being
+  // on neither list.
+  if (!flashBlock) {
+    return FlashClassification::Unknown;
+  }
+
   nsAutoCString allowTables, allowExceptionsTables,
                 denyTables, denyExceptionsTables,
                 subDocDenyTables, subDocDenyExceptionsTables,
                 tables;
   Preferences::GetCString("urlclassifier.flashAllowTable", &allowTables);
   MaybeAddTableToTableList(allowTables, tables);
   Preferences::GetCString("urlclassifier.flashAllowExceptTable",
                           &allowExceptionsTables);
--- a/dom/plugins/test/mochitest/browser.ini
+++ b/dom/plugins/test/mochitest/browser.ini
@@ -8,8 +8,9 @@ support-files =
 [browser_bug1163570.js]
 skip-if = true # Bug 1249878
 [browser_bug1196539.js]
 skip-if = (!e10s || os != "win")
 [browser_tabswitchbetweenplugins.js]
 skip-if = (!e10s || os != "win")
 [browser_pluginscroll.js]
 skip-if = (true || !e10s || os != "win") # Bug 1213631
+[browser_bug1335475.js]
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/browser_bug1335475.js
@@ -0,0 +1,64 @@
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+add_task(function*() {
+  is(navigator.plugins.length, 0,
+     "plugins should not be available to chrome-privilege pages");
+  ok(!("application/x-test" in navigator.mimeTypes),
+     "plugins should not be available to chrome-privilege pages");
+
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, function*(browser) {
+    // about:blank triggered from a toplevel load should not inherit permissions
+    yield ContentTask.spawn(browser, null, function*() {
+      is(content.window.navigator.plugins.length, 0,
+         "plugins should not be available to null-principal about:blank");
+      ok(!("application/x-test" in content.window.navigator.mimeTypes),
+         "plugins should not be available to null-principal about:blank");
+    });
+
+    let promise = BrowserTestUtils.browserLoaded(browser);
+    browser.loadURI(gTestRoot + "plugin_test.html");
+    yield promise;
+
+    yield ContentTask.spawn(browser, null, function*() {
+      ok(content.window.navigator.plugins.length > 0,
+         "plugins should be available to HTTP-loaded pages");
+      ok("application/x-test" in content.window.navigator.mimeTypes,
+         "plugins should be available to HTTP-loaded pages");
+
+      let subwindow = content.document.getElementById("subf").contentWindow;
+
+      ok("application/x-test" in subwindow.navigator.mimeTypes,
+         "plugins should be available to an about:blank subframe loaded from a site");
+    });
+
+    // navigate from the HTTP page to an about:blank page which ought to
+    // inherit permissions
+    promise = BrowserTestUtils.browserLoaded(browser);
+    yield ContentTask.spawn(browser, null, function*() {
+      content.document.getElementById("aboutlink").click();
+    });
+    yield promise;
+
+    yield ContentTask.spawn(browser, null, function*() {
+      is(content.window.location.href, "about:blank", "sanity-check about:blank load");
+      ok("application/x-test" in content.window.navigator.mimeTypes,
+         "plugins should be available when a site triggers an about:blank load");
+    });
+
+    // navigate to the file: URI, which shouldn't allow plugins. This might
+    // be wrapped in jar:, but that shouldn't matter for this test
+    promise = BrowserTestUtils.browserLoaded(browser);
+    let converteduri = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry).convertChromeURL(Services.io.newURI(rootDir + "plugin_test.html"));
+    browser.loadURI(converteduri.spec);
+    yield promise;
+
+    yield ContentTask.spawn(browser, null, function*() {
+      ok(!("application/x-test" in content.window.navigator.mimeTypes),
+         "plugins should not be available to file: URI content");
+    });
+  });
+
+  // As much as it would be nice, this doesn't actually check ftp:// because
+  // we don't have a synthetic server.
+});
--- a/dom/plugins/test/mochitest/plugin_test.html
+++ b/dom/plugins/test/mochitest/plugin_test.html
@@ -2,10 +2,15 @@
 <html>
 <head>
 <meta charset="utf-8">
 </head>
 <body>
   <embed id="testplugin" type="application/x-test" drawmode="solid" color="ff00ff00" wmode="window"
          style="position:absolute; top:50px; left:50px; width:500px; height:250px">
 <div style="display:block; height:3000px;"></div>
+
+<iframe id="subf" src="about:blank" width="300" height="300"></iframe>
+
+<a href="about:blank" id="aboutlink">Navigate to about:blank</a>
+
 </body>
 </html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5285,16 +5285,17 @@ pref("browser.safebrowsing.provider.mozi
 
 pref("urlclassifier.flashAllowTable", "test-flashallow-simple,allow-flashallow-digest256");
 pref("urlclassifier.flashAllowExceptTable", "testexcept-flashallow-simple,except-flashallow-digest256");
 pref("urlclassifier.flashTable", "test-flash-simple,block-flash-digest256");
 pref("urlclassifier.flashExceptTable", "testexcept-flash-simple,except-flash-digest256");
 pref("urlclassifier.flashSubDocTable", "test-flashsubdoc-simple,block-flashsubdoc-digest256");
 pref("urlclassifier.flashSubDocExceptTable", "testexcept-flashsubdoc-simple,except-flashsubdoc-digest256");
 
+pref("plugins.http_https_only", true);
 pref("plugins.flashBlock.enabled", false);
 
 // Allow users to ignore Safe Browsing warnings.
 pref("browser.safebrowsing.allowOverride", true);
 
 #ifdef MOZILLA_OFFICIAL
 // Normally the "client ID" sent in updates is appinfo.name, but for
 // official Firefox releases from Mozilla we use a special identifier.