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
☠☠ backed out by ca64604d4b78 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 07 Mar 2019 10:16:13 +0000
changeset 462860 abe4482fa1378d17d17534d1b18f7c4e2f86baef
parent 462859 b3920c0bcf8412089cc25c5e316b9f66f29b4112
child 462861 c2a13a7480e1226f57fd4e3956547437efc3e6e1
push id79881
push useramarchesini@mozilla.com
push dateThu, 07 Mar 2019 10:41:26 +0000
treeherderautoland@3fd27215698f [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();
+        }
+      };
+    });
+  }
+});