Bug 1053725 - When one domain is whitelisted for file:// URI access, whitelist all subdomains. r=bz
authorBobby Holley <bobbyholley@gmail.com>
Mon, 08 Sep 2014 22:22:22 -0700
changeset 228780 654b0c2a09135aeed35f1527572a078e4d688fbf
parent 228779 6db078d61361d2bd86ec6a10bc21c8c0fa5b8cfc
child 228781 cc192030c28fa60a6db2041c852ea82a1b89a2c0
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1053725
milestone35.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 1053725 - When one domain is whitelisted for file:// URI access, whitelist all subdomains. r=bz
caps/nsScriptSecurityManager.cpp
caps/tests/mochitest/test_bug995943.xul
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -28,16 +28,17 @@
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsError.h"
 #include "nsDOMCID.h"
 #include "nsIXPConnect.h"
 #include "nsTextFormatter.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
+#include "nsIEffectiveTLDService.h"
 #include "nsIProperties.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsIFileURL.h"
 #include "nsIZipReader.h"
 #include "nsIXPConnect.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsPIDOMWindow.h"
@@ -575,16 +576,45 @@ DenyAccessIfURIHasFlags(nsIURI* aURI, ui
 
     if (uriHasFlags) {
         return NS_ERROR_DOM_BAD_URI;
     }
 
     return NS_OK;
 }
 
+static bool
+EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
+{
+    // Make a clone of the incoming URI, because we're going to mutate it.
+    nsCOMPtr<nsIURI> probe;
+    nsresult rv = aProbeArg->Clone(getter_AddRefs(probe));
+    NS_ENSURE_SUCCESS(rv, false);
+
+    nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
+    NS_ENSURE_TRUE(tldService, false);
+    while (true) {
+        if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
+            return true;
+        }
+
+        nsAutoCString host, newHost;
+        nsresult rv = probe->GetHost(host);
+        NS_ENSURE_SUCCESS(rv, false);
+
+        rv = tldService->GetNextSubDomain(host, newHost);
+        if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
+            return false;
+        }
+        NS_ENSURE_SUCCESS(rv, false);
+        rv = probe->SetHost(newHost);
+        NS_ENSURE_SUCCESS(rv, false);
+    }
+}
+
 NS_IMETHODIMP
 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
                                                    nsIURI *aTargetURI,
                                                    uint32_t aFlags)
 {
     NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
     // If someone passes a flag that we don't understand, we should
     // fail, because they may need a security check that we don't
@@ -791,17 +821,17 @@ nsScriptSecurityManager::CheckLoadURIWit
     rv = NS_URIChainHasFlags(targetBaseURI,
                              nsIProtocolHandler::URI_IS_LOCAL_FILE,
                              &hasFlags);
     NS_ENSURE_SUCCESS(rv, rv);
     if (hasFlags) {
         // Allow domains that were whitelisted in the prefs. In 99.9% of cases,
         // this array is empty.
         for (size_t i = 0; i < mFileURIWhitelist.Length(); ++i) {
-            if (SecurityCompareURIs(mFileURIWhitelist[i], sourceURI)) {
+            if (EqualOrSubdomain(sourceURI, mFileURIWhitelist[i])) {
                 return NS_OK;
             }
         }
 
         // resource: and chrome: are equivalent, securitywise
         // That's bogus!!  Fix this.  But watch out for
         // the view-source stylesheet?
         bool sourceIsChrome;
--- a/caps/tests/mochitest/test_bug995943.xul
+++ b/caps/tests/mochitest/test_bug995943.xul
@@ -77,23 +77,28 @@ https://bugzilla.mozilla.org/show_bug.cg
                             ['capability.policy.somepolicy.sites', 'http://example.com']]))
     .then(checkLoadFileURI.bind(null, 'http://example.com', true))
     .then(popPrefs)
     .then(checkLoadFileURI.bind(null, 'http://example.com', false))
     .then(
       pushPrefs.bind(null, [['capability.policy.policynames', ',somepolicy, someotherpolicy, '],
                             ['capability.policy.somepolicy.checkloaduri.enabled', 'allaccess'],
                             ['capability.policy.someotherpolicy.checkloaduri.enabled', 'nope'],
-                            ['capability.policy.somepolicy.sites', ' http://example.org   https://example.com test1.example.com'],
+                            ['capability.policy.somepolicy.sites', ' http://example.org   test1.example.com https://test2.example.com '],
                             ['capability.policy.someotherpolicy.sites', 'http://example.net ']]))
     .then(checkLoadFileURI.bind(null, 'http://example.org', true))
-    .then(checkLoadFileURI.bind(null, 'http://example.com', false))
+    .then(checkLoadFileURI.bind(null, 'http://test2.example.com', false))
+    .then(checkLoadFileURI.bind(null, 'https://test2.example.com', true))
+    .then(checkLoadFileURI.bind(null, 'http://sub1.test2.example.com', false))
+    .then(checkLoadFileURI.bind(null, 'https://sub1.test2.example.com', true))
     .then(checkLoadFileURI.bind(null, 'http://example.net', false))
     .then(checkLoadFileURI.bind(null, 'http://test1.example.com', true))
     .then(checkLoadFileURI.bind(null, 'https://test1.example.com', true))
+    .then(checkLoadFileURI.bind(null, 'http://sub1.test1.example.com', true))
+    .then(checkLoadFileURI.bind(null, 'https://sub1.test1.example.com', true))
     .then(pushPrefs.bind(null, [['capability.policy.someotherpolicy.checkloaduri.enabled', 'allAccess']]))
     .then(checkLoadFileURI.bind(null, 'http://example.net', true))
     .then(popPrefs)
     .then(popPrefs)
     .then(checkLoadFileURI.bind(null, 'http://example.net', false))
     .then(SimpleTest.finish.bind(SimpleTest));
 
   }