Bug 1525245 - Stabilize cookiePolicy/cookiePermission for live documents - part 5 - BroadcastChannel must be blocked when cookie jar access is denied to avoid communication between live and new documents, r=Ehsan
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 08 Mar 2019 09:01:32 +0000
changeset 463119 e3309d98e9bd4bde6eccd8346d4b725210d67fc3
parent 463118 7d3090c3f30b5c156182420c405dc61974f07714
child 463120 174b0477055a682d34a0b5e1d5a978b767aa4c34
push id80001
push useramarchesini@mozilla.com
push dateFri, 08 Mar 2019 09:38:56 +0000
treeherderautoland@3cddc7cd4da5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1525245
milestone67.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 1525245 - Stabilize cookiePolicy/cookiePermission for live documents - part 5 - BroadcastChannel must be blocked when cookie jar access is denied to avoid communication between live and new documents, r=Ehsan Differential Revision: https://phabricator.services.mozilla.com/D18953
dom/broadcastchannel/BroadcastChannel.cpp
netwerk/cookie/test/browser/browser.ini
netwerk/cookie/test/browser/browser_broadcastChannel.js
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -62,25 +62,23 @@ nsIPrincipal* GetPrincipalFromThreadSafe
   }
 
   return wp->GetPrincipal();
 }
 
 class InitializeRunnable final : public WorkerMainThreadRunnable {
  public:
   InitializeRunnable(ThreadSafeWorkerRef* aWorkerRef, nsACString& aOrigin,
-                     PrincipalInfo& aPrincipalInfo, bool* aThirdPartyWindow,
-                     ErrorResult& aRv)
+                     PrincipalInfo& aPrincipalInfo, ErrorResult& aRv)
       : WorkerMainThreadRunnable(
             aWorkerRef->Private(),
             NS_LITERAL_CSTRING("BroadcastChannel :: Initialize")),
         mWorkerRef(aWorkerRef),
         mOrigin(aOrigin),
         mPrincipalInfo(aPrincipalInfo),
-        mThirdPartyWindow(aThirdPartyWindow),
         mRv(aRv) {
     MOZ_ASSERT(mWorkerRef);
   }
 
   bool MainThreadRun() override {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsIPrincipal* principal = GetPrincipalFromThreadSafeWorkerRef(mWorkerRef);
@@ -106,27 +104,23 @@ class InitializeRunnable final : public 
     }
 
     // Window doesn't exist for some kind of workers (eg: SharedWorkers)
     nsPIDOMWindowInner* window = wp->GetWindow();
     if (!window) {
       return true;
     }
 
-    *mThirdPartyWindow =
-        nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, nullptr);
-
     return true;
   }
 
  private:
   RefPtr<ThreadSafeWorkerRef> mWorkerRef;
   nsACString& mOrigin;
   PrincipalInfo& mPrincipalInfo;
-  bool* mThirdPartyWindow;
   ErrorResult& mRv;
 };
 
 class CloseRunnable final : public nsIRunnable, public nsICancelableRunnable {
  public:
   NS_DECL_ISUPPORTS
 
   explicit CloseRunnable(BroadcastChannel* aBC) : mBC(aBC) { MOZ_ASSERT(mBC); }
@@ -243,32 +237,33 @@ already_AddRefed<BroadcastChannel> Broad
     }
 
     nsIPrincipal* principal = incumbent->PrincipalOrNull();
     if (!principal) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
 
+    // We want to allow opaque origins.
+    if (!principal->GetIsNullPrincipal() &&
+        nsContentUtils::StorageAllowedForWindow(window) <=
+            nsContentUtils::StorageAccess::eDeny) {
+      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+      return nullptr;
+    }
+
     aRv = principal->GetOrigin(origin);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     aRv = PrincipalToPrincipalInfo(principal, &principalInfo);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
-
-    if (nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, nullptr) &&
-        nsContentUtils::StorageAllowedForWindow(window) !=
-            nsContentUtils::StorageAccess::eAllow) {
-      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-      return nullptr;
-    }
   } else {
     JSContext* cx = aGlobal.Context();
 
     WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
     MOZ_ASSERT(workerPrivate);
 
     RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
         workerPrivate, "BroadcastChannel", [bc]() { bc->Shutdown(); });
@@ -276,26 +271,25 @@ already_AddRefed<BroadcastChannel> Broad
     // object.
     if (NS_WARN_IF(!workerRef)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef);
 
-    bool thirdPartyWindow = false;
-
-    RefPtr<InitializeRunnable> runnable = new InitializeRunnable(
-        tsr, origin, principalInfo, &thirdPartyWindow, aRv);
+    RefPtr<InitializeRunnable> runnable =
+        new InitializeRunnable(tsr, origin, principalInfo, aRv);
     runnable->Dispatch(Canceling, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
-    if (thirdPartyWindow && !workerPrivate->IsStorageAllowed()) {
+    if (principalInfo.type() != PrincipalInfo::TNullPrincipalInfo &&
+        !workerPrivate->IsStorageAllowed()) {
       aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
       return nullptr;
     }
 
     bc->mWorkerRef = std::move(workerRef);
   }
 
   // Register this component to PBackground.
--- a/netwerk/cookie/test/browser/browser.ini
+++ b/netwerk/cookie/test/browser/browser.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 support-files =
   file_empty.html
   head.js
 
+[browser_broadcastChannel.js]
 [browser_originattributes.js]
 [browser_storage.js]
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_broadcastChannel.js
@@ -0,0 +1,77 @@
+// BroadcastChannel is not considered part of CookieJar. It's not allowed to
+// communicate with other windows with different cookie settings.
+
+CookiePolicyHelper.runTest("BroadcastChannel", {
+  cookieJarAccessAllowed: async _ => {
+    new content.BroadcastChannel("hello");
+    ok(true, "BroadcastChannel be used");
+  },
+
+  cookieJarAccessDenied: async _ => {
+    try {
+      new content.BroadcastChannel("hello");
+      ok(false, "BroadcastChannel cannot be used!");
+    } catch (e) {
+      ok(true, "BroadcastChannel cannot be used!");
+      is(e.name, "SecurityError", "We want a security error message.");
+    }
+  }
+});
+
+CookiePolicyHelper.runTest("BroadcastChannel in workers", {
+  cookieJarAccessAllowed: async _ => {
+    function nonBlockingCode() {
+      new BroadcastChannel("hello");
+      postMessage(true);
+    }
+
+    let blob = new content.Blob([nonBlockingCode.toString() + "; nonBlockingCode();"]);
+    ok(blob, "Blob has been created");
+
+    let blobURL = content.URL.createObjectURL(blob);
+    ok(blobURL, "Blob URL has been created");
+
+    let worker = new content.Worker(blobURL);
+    ok(worker, "Worker has been created");
+
+    await new content.Promise((resolve, reject) => {
+      worker.onmessage = function(e) {
+        if (e) {
+          resolve();
+        } else {
+          reject();
+        }
+      };
+    });
+  },
+
+  cookieJarAccessDenied: async _ => {
+    function blockingCode() {
+      try {
+        new BroadcastChannel("hello");
+        postMessage(false);
+      } catch (e) {
+        postMessage(e.name == "SecurityError");
+      }
+    }
+
+    let blob = new content.Blob([blockingCode.toString() + "; blockingCode();"]);
+    ok(blob, "Blob has been created");
+
+    let blobURL = content.URL.createObjectURL(blob);
+    ok(blobURL, "Blob URL has been created");
+
+    let worker = new content.Worker(blobURL);
+    ok(worker, "Worker has been created");
+
+    await new content.Promise((resolve, reject) => {
+      worker.onmessage = function(e) {
+        if (e) {
+          resolve();
+        } else {
+          reject();
+        }
+      };
+    });
+  }
+});