Bug 1517089 - Part 10: Implement QuotaManager::IsPrincipalInfoValid; r=asuth
authorJan Varga <jan.varga@gmail.com>
Fri, 08 Feb 2019 21:01:59 +0100
changeset 520803 1169146b040952314971d194587fde84536cf3f1
parent 520802 5adb364e4ddfb240c8d5a02b03f32365bba628d0
child 520804 5b51bc2a466c98cbebe7cadd1098a9cc48951a9e
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)
reviewersasuth
bugs1517089
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 1517089 - Part 10: Implement QuotaManager::IsPrincipalInfoValid; r=asuth Differential Revision: https://phabricator.services.mozilla.com/D19204
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ActorsParent.h"
 
 #include "mozIStorageConnection.h"
 #include "mozIStorageService.h"
+#include "mozIThirdPartyUtil.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIFile.h"
 #include "nsIFileStreams.h"
 #include "nsIObserverService.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIRunnable.h"
@@ -38,16 +39,17 @@
 #include "mozilla/dom/quota/PQuotaParent.h"
 #include "mozilla/dom/quota/PQuotaRequestParent.h"
 #include "mozilla/dom/quota/PQuotaUsageRequestParent.h"
 #include "mozilla/dom/simpledb/ActorsParent.h"
 #include "mozilla/dom/StorageActivityService.h"
 #include "mozilla/dom/StorageDBUpdater.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/net/MozURL.h"
 #include "mozilla/IntegerRange.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TextUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TypeTraits.h"
@@ -113,16 +115,17 @@
 #define MB *1024ULL KB
 #define GB *1024ULL MB
 
 namespace mozilla {
 namespace dom {
 namespace quota {
 
 using namespace mozilla::ipc;
+using mozilla::net::MozURL;
 
 // We want profiles to be platform-independent so we always need to replace
 // the same characters on every platform. Windows has the most extensive set
 // of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and
 // FILE_PATH_SEPARATOR.
 const char QuotaManager::kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
 
 namespace {
@@ -5349,16 +5352,117 @@ void QuotaManager::GetStorageId(Persiste
   str.Append(aOrigin);
   str.Append('*');
   str.AppendInt(aClientType);
 
   aDatabaseId = str;
 }
 
 // static
+bool QuotaManager::IsPrincipalInfoValid(const PrincipalInfo& aPrincipalInfo) {
+  switch (aPrincipalInfo.type()) {
+    // A system principal is acceptable.
+    case PrincipalInfo::TSystemPrincipalInfo: {
+      return true;
+    }
+
+    // Validate content principals to ensure that the spec, originNoSuffix and
+    // baseDomain are sane.
+    case PrincipalInfo::TContentPrincipalInfo: {
+      const ContentPrincipalInfo& info =
+          aPrincipalInfo.get_ContentPrincipalInfo();
+
+      // Verify the principal spec parses.
+      RefPtr<MozURL> specURL;
+      nsresult rv = MozURL::Init(getter_AddRefs(specURL), info.spec());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+
+      nsDependentCSubstring scheme = specURL->Scheme();
+
+      // Verify the principal originNoSuffix parses.
+      RefPtr<MozURL> originNoSuffixURL;
+      rv = MozURL::Init(getter_AddRefs(originNoSuffixURL),
+                        info.originNoSuffix());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+
+      // Verify the principal originNoSuffix matches spec. Skip the check for
+      // some special schemes which are not supported by MozURL::Origin yet.
+      if (!scheme.EqualsLiteral("file") &&
+          !scheme.EqualsLiteral("indexeddb") &&
+          !scheme.EqualsLiteral("moz-extension") &&
+          !scheme.EqualsLiteral("moz-safe-about") &&
+          !scheme.EqualsLiteral("resource")) {
+        nsCString originNoSuffix;
+        specURL->Origin(originNoSuffix);
+
+        if (NS_WARN_IF(info.originNoSuffix() != originNoSuffix)) {
+          return false;
+        }
+      }
+
+      if (NS_WARN_IF(info.originNoSuffix().EqualsLiteral(kChromeOrigin))) {
+        return false;
+      }
+
+      // Verify the principal baseDomain exists.
+      if (NS_WARN_IF(info.baseDomain().IsVoid())) {
+        return false;
+      }
+
+      // Verify the principal baseDomain parses.
+      nsCString baseDomainForParsing;
+      if (!scheme.EqualsLiteral("indexeddb") &&
+          !scheme.EqualsLiteral("moz-safe-about")) {
+        baseDomainForParsing = scheme + NS_LITERAL_CSTRING("://");
+      }
+      baseDomainForParsing.Append(info.baseDomain());
+
+      RefPtr<MozURL> baseDomainURL;
+      rv = MozURL::Init(getter_AddRefs(baseDomainURL), baseDomainForParsing);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+
+      // Verify the principal baseDomain matches spec. Skip the check for
+      // some special schemes which are not handled by
+      // mozIThirdPartyUtil::GetBaseDomainFromSchemeHost.
+      if (!scheme.EqualsLiteral("file") &&
+          !scheme.EqualsLiteral("indexeddb") &&
+          !scheme.EqualsLiteral("moz-safe-about")) {
+        nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
+            do_GetService(THIRDPARTYUTIL_CONTRACTID);
+
+        nsCString baseDomain;
+        rv = thirdPartyUtil->GetBaseDomainFromSchemeHost(specURL->Scheme(),
+                                                         specURL->Host(),
+                                                         baseDomain);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return false;
+        }
+
+        if (NS_WARN_IF(info.baseDomain() != baseDomain)) {
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+    default: { break; }
+  }
+
+  // Null and expanded principals are not acceptable.
+  return false;
+}
+
+// static
 nsresult QuotaManager::GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
                                             nsACString* aSuffix,
                                             nsACString* aGroup,
                                             nsACString* aOrigin) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
 
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -31,16 +31,22 @@ class nsITimer;
 class nsIURI;
 class nsPIDOMWindowOuter;
 class nsIRunnable;
 
 namespace mozilla {
 
 class OriginAttributes;
 
+namespace ipc {
+
+class PrincipalInfo;
+
+}  // namespace ipc
+
 }  // namespace mozilla
 
 BEGIN_QUOTA_NAMESPACE
 
 class DirectoryLockImpl;
 class GroupInfo;
 class GroupInfoPair;
 class OriginInfo;
@@ -80,16 +86,17 @@ struct OriginParams {
 };
 
 class QuotaManager final : public BackgroundThreadObject {
   friend class DirectoryLockImpl;
   friend class GroupInfo;
   friend class OriginInfo;
   friend class QuotaObject;
 
+  typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
   typedef nsClassHashtable<nsCStringHashKey, nsTArray<DirectoryLockImpl*>>
       DirectoryLockTable;
 
  public:
   class CreateRunnable;
 
  private:
   class ShutdownRunnable;
@@ -322,16 +329,18 @@ class QuotaManager final : public Backgr
   void GetGroupUsageAndLimit(const nsACString& aGroup, UsageInfo* aUsageInfo);
 
   void NotifyStoragePressure(uint64_t aUsage);
 
   static void GetStorageId(PersistenceType aPersistenceType,
                            const nsACString& aOrigin, Client::Type aClientType,
                            nsACString& aDatabaseId);
 
+  static bool IsPrincipalInfoValid(const PrincipalInfo& aPrincipalInfo);
+
   static nsresult GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
                                        nsACString* aSuffix, nsACString* aGroup,
                                        nsACString* aOrigin);
 
   static nsresult GetInfoFromWindow(nsPIDOMWindowOuter* aWindow,
                                     nsACString* aSuffix, nsACString* aGroup,
                                     nsACString* aOrigin);