Bug 1315905 - Cleanup Necko http security check - part 1, r=valentin
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 17 Nov 2016 14:52:16 +0100
changeset 323088 aa99928b7bb8e9c60ab1ae341d2ae4fea4a5254e
parent 323087 0f59393d3669fb192fb9178651fdf301983ab4de
child 323089 9c8cc3af1870bb33831923b0b3fa3ab4373d6f72
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersvalentin
bugs1315905
milestone53.0a1
Bug 1315905 - Cleanup Necko http security check - part 1, r=valentin
caps/BasePrincipal.cpp
caps/BasePrincipal.h
dom/base/ChromeUtils.cpp
dom/base/ChromeUtils.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -187,16 +187,28 @@ OriginAttributes::CreateSuffix(nsACStrin
 // In debug builds, check the whole string for illegal characters too (just in case).
 #ifdef DEBUG
   nsAutoCString str;
   str.Assign(aStr);
   MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
 #endif
 }
 
+void
+OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const
+{
+  OriginAttributes attrs = *this;
+
+  if (!attrs.mFirstPartyDomain.IsEmpty()) {
+    attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_");
+  }
+
+  attrs.CreateSuffix(aStr);
+}
+
 namespace {
 
 class MOZ_STACK_CLASS PopulateFromSuffixIterator final
   : public URLParams::ForEachIterator
 {
 public:
   explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes)
     : mOriginAttributes(aOriginAttributes)
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -43,22 +43,26 @@ public:
   {
     return !(*this == aOther);
   }
 
   // Serializes/Deserializes non-default values into the suffix format, i.e.
   // |!key1=value1&key2=value2|. If there are no non-default attributes, this
   // returns an empty string.
   void CreateSuffix(nsACString& aStr) const;
+
+  // Don't use this method for anything else than debugging!
+  void CreateAnonymizedSuffix(nsACString& aStr) const;
+
   MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr);
 
   // Populates the attributes from a string like
   // |uri!key1=value1&key2=value2| and returns the uri without the suffix.
   MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin,
-                          nsACString& aOriginNoSuffix);
+                                       nsACString& aOriginNoSuffix);
 
   // Helper function to match mIsPrivateBrowsing to existing private browsing
   // flags. Once all other flags are removed, this can be removed too.
   void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);
 
   void SetFromGenericAttributes(const GenericOriginAttributes& aAttrs);
 
   // check if "privacy.firstparty.isolate" is enabled.
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -170,16 +170,23 @@ ChromeUtils::FillNonDefaultOriginAttribu
 }
 
 
 /* static */ bool
 ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
                                      const dom::OriginAttributesDictionary& aA,
                                      const dom::OriginAttributesDictionary& aB)
 {
+  return IsOriginAttributesEqual(aA, aB);
+}
+
+/* static */ bool
+ChromeUtils::IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
+                                     const dom::OriginAttributesDictionary& aB)
+{
   return aA.mAddonId == aB.mAddonId &&
          aA.mAppId == aB.mAppId &&
          aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
          aA.mUserContextId == aB.mUserContextId &&
          aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
 }
 
 /* static */ bool
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -84,16 +84,20 @@ public:
                                  dom::OriginAttributesDictionary& aNewAttrs);
 
   static bool
   IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
                           const dom::OriginAttributesDictionary& aA,
                           const dom::OriginAttributesDictionary& aB);
 
   static bool
+  IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
+                          const dom::OriginAttributesDictionary& aB);
+
+  static bool
   IsOriginAttributesEqualIgnoringAddonId(const dom::OriginAttributesDictionary& aA,
                                          const dom::OriginAttributesDictionary& aB);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ChromeUtils__
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -19,16 +19,17 @@
 #include "mozilla/Unused.h"
 #ifdef NECKO_PROTOCOL_rtsp
 #include "mozilla/net/RtspControllerParent.h"
 #include "mozilla/net/RtspChannelParent.h"
 #endif
 #include "mozilla/net/DNSRequestParent.h"
 #include "mozilla/net/ChannelDiverterParent.h"
 #include "mozilla/net/IPCTransportProvider.h"
+#include "mozilla/dom/ChromeUtils.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/network/TCPSocketParent.h"
 #include "mozilla/dom/network/TCPServerSocketParent.h"
 #include "mozilla/dom/network/UDPSocketParent.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/LoadContext.h"
@@ -41,16 +42,17 @@
 #include "nsIAuthPromptCallback.h"
 #include "nsPrincipal.h"
 #include "nsINetworkPredictor.h"
 #include "nsINetworkPredictorVerifier.h"
 #include "nsISpeculativeConnect.h"
 
 using mozilla::DocShellOriginAttributes;
 using mozilla::NeckoOriginAttributes;
+using mozilla::dom::ChromeUtils;
 using mozilla::dom::ContentParent;
 using mozilla::dom::TabContext;
 using mozilla::dom::TabParent;
 using mozilla::net::PTCPSocketParent;
 using mozilla::dom::TCPSocketParent;
 using mozilla::net::PTCPServerSocketParent;
 using mozilla::dom::TCPServerSocketParent;
 using mozilla::net::PUDPSocketParent;
@@ -135,69 +137,71 @@ GetRequestingPrincipal(const FTPChannelC
   if (aArgs.type() != FTPChannelCreationArgs::TFTPChannelOpenArgs) {
     return nullptr;
   }
 
   const FTPChannelOpenArgs& args = aArgs.get_FTPChannelOpenArgs();
   return GetRequestingPrincipal(args.loadInfo());
 }
 
-// Bug 1289001 - If GetValidatedAppInfo returns an error string, that usually
-// leads to a content crash with very little info about the cause.
+// Bug 1289001 - If GetValidatedOriginAttributes returns an error string, that
+// usually leads to a content crash with very little info about the cause.
 // We prefer to crash on the parent, so we get the reason in the crash report.
 static MOZ_NORETURN MOZ_COLD
 void CrashWithReason(const char * reason)
 {
 #ifndef RELEASE_OR_BETA
   MOZ_CRASH_ANNOTATE(reason);
   MOZ_REALLY_CRASH();
 #endif
 }
 
 const char*
-NeckoParent::GetValidatedAppInfo(const SerializedLoadContext& aSerialized,
-                                 PContentParent* aContent,
-                                 nsIPrincipal* aRequestingPrincipal,
-                                 DocShellOriginAttributes& aAttrs)
+NeckoParent::GetValidatedOriginAttributes(const SerializedLoadContext& aSerialized,
+                                          PContentParent* aContent,
+                                          nsIPrincipal* aRequestingPrincipal,
+                                          DocShellOriginAttributes& aAttrs)
 {
   if (!aSerialized.IsNotNull()) {
     if (UsingNeckoIPCSecurity()) {
-      CrashWithReason("GetValidatedAppInfo | SerializedLoadContext from child is null");
+      CrashWithReason("GetValidatedOriginAttributes | SerializedLoadContext from child is null");
       return "SerializedLoadContext from child is null";
     }
 
     // If serialized is null, we cannot validate anything. We have to assume
     // that this requests comes from a SystemPrincipal.
     aAttrs = DocShellOriginAttributes(NECKO_NO_APP_ID, false);
     return nullptr;
   }
 
   nsTArray<TabContext> contextArray =
     static_cast<ContentParent*>(aContent)->GetManagedTabContext();
 
+  nsAutoCString serializedSuffix;
+  aSerialized.mOriginAttributes.CreateAnonymizedSuffix(serializedSuffix);
+
   nsAutoCString debugString;
   for (uint32_t i = 0; i < contextArray.Length(); i++) {
-    TabContext tabContext = contextArray[i];
-    bool inBrowserElement = aSerialized.mOriginAttributes.mInIsolatedMozBrowser;
+    const TabContext& tabContext = contextArray[i];
 
-    if (aSerialized.mOriginAttributes.mUserContextId != tabContext.OriginAttributesRef().mUserContextId) {
+    if (!ChromeUtils::IsOriginAttributesEqual(aSerialized.mOriginAttributes,
+                                              tabContext.OriginAttributesRef())) {
       debugString.Append("(");
-      debugString.AppendInt(aSerialized.mOriginAttributes.mUserContextId);
+      debugString.Append(serializedSuffix);
       debugString.Append(",");
-      debugString.AppendInt(tabContext.OriginAttributesRef().mUserContextId);
+
+      nsAutoCString tabSuffix;
+      tabContext.OriginAttributesRef().CreateAnonymizedSuffix(tabSuffix);
+      debugString.Append(tabSuffix);
+
       debugString.Append(")");
       continue;
     }
-    aAttrs = DocShellOriginAttributes();
-    aAttrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
-    aAttrs.mInIsolatedMozBrowser = inBrowserElement;
-    aAttrs.mUserContextId = aSerialized.mOriginAttributes.mUserContextId;
-    aAttrs.mPrivateBrowsingId = aSerialized.mOriginAttributes.mPrivateBrowsingId;
-    aAttrs.mFirstPartyDomain = aSerialized.mOriginAttributes.mFirstPartyDomain;
 
+    aAttrs = aSerialized.mOriginAttributes;
     return nullptr;
   }
 
   // This may be a ServiceWorker: when a push notification is received, FF wakes
   // up the corrisponding service worker so that it can manage the PushEvent. At
   // that time we probably don't have any valid tabcontext, but still, we want
   // to support http channel requests coming from that ServiceWorker.
   if (aRequestingPrincipal) {
@@ -208,29 +212,24 @@ NeckoParent::GetValidatedAppInfo(const S
     if (swm &&
         swm->MayHaveActiveServiceWorkerInstance(static_cast<ContentParent*>(aContent),
                                                 aRequestingPrincipal)) {
       aAttrs = aSerialized.mOriginAttributes;
       return nullptr;
     }
   }
 
-  if (contextArray.IsEmpty()) {
-    if (UsingNeckoIPCSecurity()) {
-      CrashWithReason("GetValidatedAppInfo | ContentParent does not have any PBrowsers");
-      return "ContentParent does not have any PBrowsers";
-    }
-
-    // We are running xpcshell tests
+  if (!UsingNeckoIPCSecurity()) {
+    // We are running some tests
     aAttrs = aSerialized.mOriginAttributes;
     return nullptr;
   }
 
   nsAutoCString errorString;
-  errorString.Append("GetValidatedAppInfo | App does not have permission -");
+  errorString.Append("GetValidatedOriginAttributes | App does not have permission -");
   errorString.Append(debugString);
 
   // Leak the buffer on the heap to make sure that it lives long enough, as
   // MOZ_CRASH_ANNOTATE expects the pointer passed to it to live to the end of
   // the program.
   char * error = strdup(errorString.BeginReading());
   CrashWithReason(error);
   return "App does not have permission";
@@ -239,18 +238,18 @@ NeckoParent::GetValidatedAppInfo(const S
 const char *
 NeckoParent::CreateChannelLoadContext(const PBrowserOrId& aBrowser,
                                       PContentParent* aContent,
                                       const SerializedLoadContext& aSerialized,
                                       nsIPrincipal* aRequestingPrincipal,
                                       nsCOMPtr<nsILoadContext> &aResult)
 {
   DocShellOriginAttributes attrs;
-  const char* error = GetValidatedAppInfo(aSerialized, aContent,
-                                          aRequestingPrincipal, attrs);
+  const char* error = GetValidatedOriginAttributes(aSerialized, aContent,
+                                                   aRequestingPrincipal, attrs);
   if (error) {
     return error;
   }
 
   // if !UsingNeckoIPCSecurity(), we may not have a LoadContext to set. This is
   // the common case for most xpcshell tests.
   if (aSerialized.IsNotNull()) {
     attrs.SyncAttributesWithPrivateBrowsing(aSerialized.mOriginAttributes.mPrivateBrowsingId > 0);
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -30,20 +30,20 @@ class NeckoParent
   : public PNeckoParent
 {
 public:
   NeckoParent();
   virtual ~NeckoParent();
 
   MOZ_MUST_USE
   static const char *
-  GetValidatedAppInfo(const SerializedLoadContext& aSerialized,
-                      PContentParent* aBrowser,
-                      nsIPrincipal* aRequestingPrincipal,
-                      mozilla::DocShellOriginAttributes& aAttrs);
+  GetValidatedOriginAttributes(const SerializedLoadContext& aSerialized,
+                               PContentParent* aBrowser,
+                               nsIPrincipal* aRequestingPrincipal,
+                               mozilla::DocShellOriginAttributes& aAttrs);
 
   /*
    * Creates LoadContext for parent-side of an e10s channel.
    *
    * PContentParent corresponds to the process that is requesting the load.
    *
    * Returns null if successful, or an error string if failed.
    */