Bug 1335475 - Deny plugins from non-HTTP/HTTPS origins. r=qdot r=ksteuber
MozReview-Commit-ID: 3kPeycfMWVw
--- 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
@@ -5296,16 +5296,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.