DomainPolicy.cpp (6142B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=4 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "DomainPolicy.h" 8 #include "mozilla/dom/ContentParent.h" 9 #include "mozilla/ipc/URIUtils.h" 10 #include "nsIURIMutator.h" 11 #include "nsScriptSecurityManager.h" 12 13 namespace mozilla { 14 15 using namespace ipc; 16 using namespace dom; 17 18 NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy) 19 20 static nsresult BroadcastDomainSetChange(DomainSetType aSetType, 21 DomainSetChangeType aChangeType, 22 nsIURI* aDomain = nullptr) { 23 MOZ_ASSERT(XRE_IsParentProcess(), 24 "DomainPolicy should only be exposed to the chrome process."); 25 26 nsTArray<ContentParent*> parents; 27 ContentParent::GetAll(parents); 28 if (!parents.Length()) { 29 return NS_OK; 30 } 31 32 for (uint32_t i = 0; i < parents.Length(); i++) { 33 (void)parents[i]->SendDomainSetChanged(aSetType, aChangeType, aDomain); 34 } 35 return NS_OK; 36 } 37 38 DomainPolicy::DomainPolicy() 39 : mBlocklist(new DomainSet(BLOCKLIST)), 40 mSuperBlocklist(new DomainSet(SUPER_BLOCKLIST)), 41 mAllowlist(new DomainSet(ALLOWLIST)), 42 mSuperAllowlist(new DomainSet(SUPER_ALLOWLIST)) { 43 if (XRE_IsParentProcess()) { 44 BroadcastDomainSetChange(NO_TYPE, ACTIVATE_POLICY); 45 } 46 } 47 48 DomainPolicy::~DomainPolicy() { 49 // The SSM holds a strong ref to the DomainPolicy until Deactivate() is 50 // invoked, so we should never hit the destructor until that happens. 51 MOZ_ASSERT(!mBlocklist && !mSuperBlocklist && !mAllowlist && 52 !mSuperAllowlist); 53 } 54 55 NS_IMETHODIMP 56 DomainPolicy::GetBlocklist(nsIDomainSet** aSet) { 57 nsCOMPtr<nsIDomainSet> set = mBlocklist.get(); 58 set.forget(aSet); 59 return NS_OK; 60 } 61 62 NS_IMETHODIMP 63 DomainPolicy::GetSuperBlocklist(nsIDomainSet** aSet) { 64 nsCOMPtr<nsIDomainSet> set = mSuperBlocklist.get(); 65 set.forget(aSet); 66 return NS_OK; 67 } 68 69 NS_IMETHODIMP 70 DomainPolicy::GetAllowlist(nsIDomainSet** aSet) { 71 nsCOMPtr<nsIDomainSet> set = mAllowlist.get(); 72 set.forget(aSet); 73 return NS_OK; 74 } 75 76 NS_IMETHODIMP 77 DomainPolicy::GetSuperAllowlist(nsIDomainSet** aSet) { 78 nsCOMPtr<nsIDomainSet> set = mSuperAllowlist.get(); 79 set.forget(aSet); 80 return NS_OK; 81 } 82 83 NS_IMETHODIMP 84 DomainPolicy::Deactivate() { 85 // Clear the hashtables first to free up memory, since script might 86 // hold the doomed sets alive indefinitely. 87 mBlocklist->Clear(); 88 mSuperBlocklist->Clear(); 89 mAllowlist->Clear(); 90 mSuperAllowlist->Clear(); 91 92 // Null them out. 93 mBlocklist = nullptr; 94 mSuperBlocklist = nullptr; 95 mAllowlist = nullptr; 96 mSuperAllowlist = nullptr; 97 98 // Inform the SSM. 99 nsScriptSecurityManager* ssm = 100 nsScriptSecurityManager::GetScriptSecurityManager(); 101 if (ssm) { 102 ssm->DeactivateDomainPolicy(); 103 } 104 if (XRE_IsParentProcess()) { 105 BroadcastDomainSetChange(NO_TYPE, DEACTIVATE_POLICY); 106 } 107 return NS_OK; 108 } 109 110 void DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone) { 111 aClone->active() = true; 112 mBlocklist->CloneSet(&aClone->blocklist()); 113 mSuperBlocklist->CloneSet(&aClone->superBlocklist()); 114 mAllowlist->CloneSet(&aClone->allowlist()); 115 mSuperAllowlist->CloneSet(&aClone->superAllowlist()); 116 } 117 118 static void CopyURIs(const nsTArray<RefPtr<nsIURI>>& aDomains, 119 nsIDomainSet* aSet) { 120 for (uint32_t i = 0; i < aDomains.Length(); i++) { 121 if (NS_WARN_IF(!aDomains[i])) { 122 continue; 123 } 124 aSet->Add(aDomains[i]); 125 } 126 } 127 128 void DomainPolicy::ApplyClone(const DomainPolicyClone* aClone) { 129 CopyURIs(aClone->blocklist(), mBlocklist); 130 CopyURIs(aClone->allowlist(), mAllowlist); 131 CopyURIs(aClone->superBlocklist(), mSuperBlocklist); 132 CopyURIs(aClone->superAllowlist(), mSuperAllowlist); 133 } 134 135 static already_AddRefed<nsIURI> GetCanonicalClone(nsIURI* aURI) { 136 nsCOMPtr<nsIURI> clone; 137 nsresult rv = 138 NS_MutateURI(aURI).SetUserPass(""_ns).SetPathQueryRef(""_ns).Finalize( 139 clone); 140 NS_ENSURE_SUCCESS(rv, nullptr); 141 return clone.forget(); 142 } 143 144 NS_IMPL_ISUPPORTS(DomainSet, nsIDomainSet) 145 146 NS_IMETHODIMP 147 DomainSet::Add(nsIURI* aDomain) { 148 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); 149 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); 150 mHashTable.Insert(clone); 151 if (XRE_IsParentProcess()) { 152 return BroadcastDomainSetChange(mType, ADD_DOMAIN, aDomain); 153 } 154 155 return NS_OK; 156 } 157 158 NS_IMETHODIMP 159 DomainSet::Remove(nsIURI* aDomain) { 160 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); 161 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); 162 mHashTable.Remove(clone); 163 if (XRE_IsParentProcess()) { 164 return BroadcastDomainSetChange(mType, REMOVE_DOMAIN, aDomain); 165 } 166 167 return NS_OK; 168 } 169 170 NS_IMETHODIMP 171 DomainSet::Clear() { 172 mHashTable.Clear(); 173 if (XRE_IsParentProcess()) { 174 return BroadcastDomainSetChange(mType, CLEAR_DOMAINS); 175 } 176 177 return NS_OK; 178 } 179 180 NS_IMETHODIMP 181 DomainSet::Contains(nsIURI* aDomain, bool* aContains) { 182 *aContains = false; 183 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); 184 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); 185 *aContains = mHashTable.Contains(clone); 186 return NS_OK; 187 } 188 189 NS_IMETHODIMP 190 DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains) { 191 *aContains = false; 192 nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); 193 NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); 194 nsAutoCString domain; 195 nsresult rv = clone->GetHost(domain); 196 NS_ENSURE_SUCCESS(rv, rv); 197 while (true) { 198 // Check the current domain. 199 if (mHashTable.Contains(clone)) { 200 *aContains = true; 201 return NS_OK; 202 } 203 204 // Chop off everything before the first dot, or break if there are no 205 // dots left. 206 int32_t index = domain.Find("."); 207 if (index == kNotFound) break; 208 domain.Assign(Substring(domain, index + 1)); 209 rv = NS_MutateURI(clone).SetHost(domain).Finalize(clone); 210 NS_ENSURE_SUCCESS(rv, rv); 211 } 212 213 // No match. 214 return NS_OK; 215 } 216 217 void DomainSet::CloneSet(nsTArray<RefPtr<nsIURI>>* aDomains) { 218 AppendToArray(*aDomains, mHashTable); 219 } 220 221 } /* namespace mozilla */