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 bc51c190590a ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 26 Feb 2019 17:37:46 +0000
changeset 519089 b79ec111bf41921912f9ab73091cbe093c7dd371
parent 519088 858d08371107c0d06f02e57acc65f6edb8b85803
child 519090 d8ee13b6a17d3cbfa50e721089ebd5e2360594bd
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [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); }
@@ -242,32 +236,33 @@ JSObject* BroadcastChannel::WrapObject(J
     }
 
     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(); });
@@ -275,26 +270,25 @@ JSObject* BroadcastChannel::WrapObject(J
     // 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();
+        }
+      };
+    });
+  }
+});