nsDataDocumentContentPolicy.cpp (6499B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 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 /* 8 * Content policy implementation that prevents all loads of images, 9 * subframes, etc from documents loaded as data (eg documents loaded 10 * via XMLHttpRequest). 11 */ 12 13 #include "nsDataDocumentContentPolicy.h" 14 15 #include "mozilla/ScopeExit.h" 16 #include "mozilla/dom/Document.h" 17 #include "nsContentPolicyUtils.h" 18 #include "nsContentUtils.h" 19 #include "nsINode.h" 20 #include "nsIProtocolHandler.h" 21 #include "nsIURI.h" 22 #include "nsNetUtil.h" 23 #include "nsScriptSecurityManager.h" 24 25 using namespace mozilla; 26 27 NS_IMPL_ISUPPORTS(nsDataDocumentContentPolicy, nsIContentPolicy) 28 29 // Helper method for ShouldLoad() 30 // Checks a URI for the given flags. Returns true if the URI has the flags, 31 // and false if not (or if we weren't able to tell). 32 static bool HasFlags(nsIURI* aURI, uint32_t aURIFlags) { 33 bool hasFlags; 34 nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags); 35 return NS_SUCCEEDED(rv) && hasFlags; 36 } 37 38 // If you change DataDocumentContentPolicy, make sure to check that 39 // CHECK_PRINCIPAL_AND_DATA in nsContentPolicyUtils is still valid. 40 // nsContentPolicyUtils may not pass all the parameters to ShouldLoad. 41 NS_IMETHODIMP 42 nsDataDocumentContentPolicy::ShouldLoad(nsIURI* aContentLocation, 43 nsILoadInfo* aLoadInfo, 44 int16_t* aDecision) { 45 auto setBlockingReason = mozilla::MakeScopeExit([&]() { 46 if (NS_CP_REJECTED(*aDecision)) { 47 NS_SetRequestBlockingReason( 48 aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_DATA_DOCUMENT); 49 } 50 }); 51 52 ExtContentPolicyType contentType = aLoadInfo->GetExternalContentPolicyType(); 53 nsCOMPtr<nsISupports> requestingContext = aLoadInfo->GetLoadingContext(); 54 55 *aDecision = nsIContentPolicy::ACCEPT; 56 // Look for the document. In most cases, requestingContext is a node. 57 nsCOMPtr<mozilla::dom::Document> doc; 58 nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); 59 if (node) { 60 doc = node->OwnerDoc(); 61 } else { 62 if (nsCOMPtr<nsPIDOMWindowOuter> window = 63 do_QueryInterface(requestingContext)) { 64 doc = window->GetDoc(); 65 } 66 } 67 68 // DTDs are always OK to load 69 if (!doc || contentType == ExtContentPolicy::TYPE_DTD) { 70 return NS_OK; 71 } 72 73 if (doc->IsLoadedAsData()) { 74 bool allowed = [&] { 75 if (!doc->IsStaticDocument()) { 76 // If not a print/print preview doc, then nothing else is allowed for 77 // data documents. 78 return false; 79 } 80 // Let static (print/print preview) documents to load fonts and 81 // images. 82 switch (contentType) { 83 case ExtContentPolicy::TYPE_IMAGE: 84 case ExtContentPolicy::TYPE_IMAGESET: 85 case ExtContentPolicy::TYPE_FONT: 86 case ExtContentPolicy::TYPE_UA_FONT: 87 // This one is a bit sketchy, but nsObjectLoadingContent takes care of 88 // only getting here if it is an image. 89 case ExtContentPolicy::TYPE_OBJECT: 90 return true; 91 default: 92 return false; 93 } 94 }(); 95 96 if (!allowed) { 97 *aDecision = nsIContentPolicy::REJECT_TYPE; 98 return NS_OK; 99 } 100 } 101 102 mozilla::dom::Document* docToCheckForImage = doc->GetDisplayDocument(); 103 if (!docToCheckForImage) { 104 docToCheckForImage = doc; 105 } 106 107 if (docToCheckForImage->IsBeingUsedAsImage()) { 108 // We only allow SVG images to load content from URIs that are local and 109 // also satisfy one of the following conditions: 110 // - URI inherits security context, e.g. data URIs 111 // OR 112 // - URI loadable by subsumers, e.g. blob URIs 113 // Any URI that doesn't meet these requirements will be rejected below. 114 if (!(HasFlags(aContentLocation, 115 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE) && 116 (HasFlags(aContentLocation, 117 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT) || 118 HasFlags(aContentLocation, 119 nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS)))) { 120 *aDecision = nsIContentPolicy::REJECT_TYPE; 121 122 // Report error, if we can. 123 if (node) { 124 nsIPrincipal* requestingPrincipal = node->NodePrincipal(); 125 nsAutoCString sourceSpec; 126 requestingPrincipal->GetAsciiSpec(sourceSpec); 127 nsAutoCString targetSpec; 128 aContentLocation->GetAsciiSpec(targetSpec); 129 nsScriptSecurityManager::ReportError( 130 "ExternalDataError", sourceSpec, targetSpec, 131 requestingPrincipal->OriginAttributesRef().IsPrivateBrowsing()); 132 } 133 } else if ((contentType == ExtContentPolicy::TYPE_IMAGE || 134 contentType == ExtContentPolicy::TYPE_IMAGESET) && 135 doc->GetDocumentURI()) { 136 // Check for (& disallow) recursive image-loads 137 bool isRecursiveLoad; 138 nsresult rv = aContentLocation->EqualsExceptRef(doc->GetDocumentURI(), 139 &isRecursiveLoad); 140 if (NS_FAILED(rv) || isRecursiveLoad) { 141 NS_WARNING("Refusing to recursively load image"); 142 *aDecision = nsIContentPolicy::REJECT_TYPE; 143 } 144 } 145 return NS_OK; 146 } 147 148 // Allow all loads for non-resource documents 149 if (!doc->IsResourceDoc()) { 150 return NS_OK; 151 } 152 153 // For resource documents, blacklist some load types 154 if (contentType == ExtContentPolicy::TYPE_OBJECT || 155 contentType == ExtContentPolicy::TYPE_DOCUMENT || 156 contentType == ExtContentPolicy::TYPE_SUBDOCUMENT || 157 contentType == ExtContentPolicy::TYPE_SCRIPT || 158 contentType == ExtContentPolicy::TYPE_XSLT || 159 contentType == ExtContentPolicy::TYPE_FETCH || 160 contentType == ExtContentPolicy::TYPE_WEB_MANIFEST) { 161 *aDecision = nsIContentPolicy::REJECT_TYPE; 162 } 163 164 // If you add more restrictions here, make sure to check that 165 // CHECK_PRINCIPAL_AND_DATA in nsContentPolicyUtils is still valid. 166 // nsContentPolicyUtils may not pass all the parameters to ShouldLoad 167 168 return NS_OK; 169 } 170 171 NS_IMETHODIMP 172 nsDataDocumentContentPolicy::ShouldProcess(nsIURI* aContentLocation, 173 nsILoadInfo* aLoadInfo, 174 int16_t* aDecision) { 175 return ShouldLoad(aContentLocation, aLoadInfo, aDecision); 176 }