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 323060 aa99928b7bb8e9c60ab1ae341d2ae4fea4a5254e
parent 323059 0f59393d3669fb192fb9178651fdf301983ab4de
child 323061 9c8cc3af1870bb33831923b0b3fa3ab4373d6f72
push id30967
push userphilringnalda@gmail.com
push dateFri, 18 Nov 2016 03:21:38 +0000
treeherdermozilla-central@8e476f8bd52d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1315905
milestone53.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 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.
    */