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 66a4a5cb3fc7 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 27 Feb 2019 19:56:20 +0000
changeset 519386 476af2d7efe5b93b1a4c75695e1d1753071a6c83
parent 519385 43ad14e323a106dbf939d692dc87454bd065ba55
child 519387 6b92fb3666d156c8547378eec6c6b2713d820046
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();
+        }
+      };
+    });
+  }
+});