diff --git a/mozilla/content/base/public/nsContentUtils.h b/mozilla/content/base/public/nsContentUtils.h index 2b9f4ce22eb..2d4304ee709 100644 --- a/mozilla/content/base/public/nsContentUtils.h +++ b/mozilla/content/base/public/nsContentUtils.h @@ -1015,6 +1015,39 @@ public: * FALSE. */ static void NotifyInstalledMenuKeyboardListener(PRBool aInstalling); + + /** + * Do security checks before loading a resource. Does the following checks: + * nsIScriptSecurityManager::CheckLoadURIWithPrincipal + * NS_CheckContentLoadPolicy + * nsIScriptSecurityManager::CheckSameOriginURI + * + * You will still need to do at least SameOrigin checks before on redirects. + * + * @param aURIToLoad URI that is getting loaded. + * @param aLoadingPrincipal Principal of the resource that is initiating + * the load + * @param aCheckLoadFlags Flags to be passed to + * nsIScriptSecurityManager::CheckLoadURIWithPrincipal + * NOTE: If this contains ALLOW_CHROME the + * CheckSameOriginURI check will be skipped if + * aURIToLoad is a chrome uri. + * @param aAllowData Set to true to skip CheckSameOriginURI check when + aURIToLoad is a data uri. + * @param aContentPolicyType Type \ + * @param aContext Context |- to be passed to + * @param aMimeGuess Mimetype | NS_CheckContentLoadPolicy + * @param aExtra Extra / + */ + static nsresult CheckSecurityBeforeLoad(nsIURI* aURIToLoad, + nsIPrincipal* aLoadingPrincipal, + PRUint32 aCheckLoadFlags, + PRBool aAllowData, + PRUint32 aContentPolicyType, + nsISupports* aContext, + const nsACString& aMimeGuess = EmptyCString(), + nsISupports* aExtra = nsnull); + private: static PRBool InitializeEventTable(); diff --git a/mozilla/content/base/src/nsContentUtils.cpp b/mozilla/content/base/src/nsContentUtils.cpp index 65f2a318782..db892dbe743 100644 --- a/mozilla/content/base/src/nsContentUtils.cpp +++ b/mozilla/content/base/src/nsContentUtils.cpp @@ -137,6 +137,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsMutationEvent.h" #include "nsIKBStateControl.h" #include "nsIMEStateManager.h" +#include "nsContentErrors.h" #ifdef IBMBIDI #include "nsIBidiKeyboard.h" @@ -3552,3 +3553,56 @@ nsContentUtils::NotifyInstalledMenuKeyboardListener(PRBool aInstalling) { nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); } + +static PRBool SchemeIs(nsIURI* aURI, const char* aScheme) +{ + nsCOMPtr baseURI = NS_GetInnermostURI(aURI); + NS_ENSURE_TRUE(baseURI, PR_FALSE); + + PRBool isScheme = PR_FALSE; + return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme; +} + +/* static */ +nsresult +nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad, + nsIPrincipal* aLoadingPrincipal, + PRUint32 aCheckLoadFlags, + PRBool aAllowData, + PRUint32 aContentPolicyType, + nsISupports* aContext, + const nsACString& aMimeGuess, + nsISupports* aExtra) +{ + nsCOMPtr loadingURI; + nsresult rv = aLoadingPrincipal->GetURI(getter_AddRefs(loadingURI)); + NS_ENSURE_SUCCESS(rv, rv); + + // CheckLoadURIWithPrincipal + rv = sSecurityManager-> + CheckLoadURIWithPrincipal(aLoadingPrincipal, aURIToLoad, aCheckLoadFlags); + NS_ENSURE_SUCCESS(rv, rv); + + // Content Policy + PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; + rv = NS_CheckContentLoadPolicy(aContentPolicyType, + aURIToLoad, + loadingURI, + aContext, + aMimeGuess, + aExtra, + &shouldLoad, + GetContentPolicy()); + NS_ENSURE_SUCCESS(rv, rv); + if (NS_CP_REJECTED(shouldLoad)) { + return NS_ERROR_CONTENT_BLOCKED; + } + + // Same Origin + if ((aAllowData && SchemeIs(aURIToLoad, "data")) || + ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) && + SchemeIs(aURIToLoad, "chrome"))) { + return NS_OK; + } + return sSecurityManager->CheckSameOriginURI(loadingURI, aURIToLoad); +} diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index 2cb1ea3bed0..61e40db7edc 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -154,6 +154,7 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID); #include "nsIXPConnect.h" #include "nsCycleCollector.h" #include "nsCCUncollectableMarker.h" +#include "nsIContentPolicy.h" #ifdef MOZ_LOGGING // so we can get logging even in release builds @@ -3430,23 +3431,16 @@ nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsAString& aURI) } NS_IMETHODIMP -nsDocument::LoadBindingDocument(const nsAString& aURI, - nsIDOMDocument** aResult) +nsDocument::LoadBindingDocument(const nsAString& aURI) { nsCOMPtr uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI, mCharacterSet.get(), NS_STATIC_CAST(nsIDocument *, this)->GetBaseURI()); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr doc; - mBindingManager->LoadBindingDocument(this, uri, getter_AddRefs(doc)); - if (doc) { - CallQueryInterface(doc, aResult); - } - + mBindingManager->LoadBindingDocument(this, uri); + return NS_OK; } diff --git a/mozilla/content/xbl/src/nsBindingManager.cpp b/mozilla/content/xbl/src/nsBindingManager.cpp index c5a95412a7c..5ebf6e28860 100644 --- a/mozilla/content/xbl/src/nsBindingManager.cpp +++ b/mozilla/content/xbl/src/nsBindingManager.cpp @@ -766,19 +766,11 @@ nsBindingManager::RemoveLayeredBinding(nsIContent* aContent, nsIURI* aURL) nsresult nsBindingManager::LoadBindingDocument(nsIDocument* aBoundDoc, - nsIURI* aURL, - nsIDocument** aResult) + nsIURI* aURL) { NS_PRECONDITION(aURL, "Must have a URI to load!"); - nsCAutoString otherScheme; - aURL->GetScheme(otherScheme); - - nsCAutoString scheme; - aBoundDoc->GetDocumentURI()->GetScheme(scheme); - // First we need to load our binding. - *aResult = nsnull; nsresult rv; nsCOMPtr xblService = do_GetService("@mozilla.org/xbl;1", &rv); @@ -792,11 +784,6 @@ nsBindingManager::LoadBindingDocument(nsIDocument* aBoundDoc, if (!info) return NS_ERROR_FAILURE; - // XXXbz Why is this based on a scheme comparison? Shouldn't this - // be a real security check??? - if (!strcmp(scheme.get(), otherScheme.get())) - info->GetDocument(aResult); // Addref happens here. - return NS_OK; } diff --git a/mozilla/content/xbl/src/nsBindingManager.h b/mozilla/content/xbl/src/nsBindingManager.h index 79c5918d5bd..d3e6a76f377 100755 --- a/mozilla/content/xbl/src/nsBindingManager.h +++ b/mozilla/content/xbl/src/nsBindingManager.h @@ -156,8 +156,7 @@ public: nsresult AddLayeredBinding(nsIContent* aContent, nsIURI* aURL); nsresult RemoveLayeredBinding(nsIContent* aContent, nsIURI* aURL); - nsresult LoadBindingDocument(nsIDocument* aBoundDoc, nsIURI* aURL, - nsIDocument** aResult); + nsresult LoadBindingDocument(nsIDocument* aBoundDoc, nsIURI* aURL); nsresult AddToAttachedQueue(nsXBLBinding* aBinding); void ProcessAttachedQueue(); diff --git a/mozilla/content/xbl/src/nsXBLService.cpp b/mozilla/content/xbl/src/nsXBLService.cpp index 38baa9b06c0..917ce17fa52 100644 --- a/mozilla/content/xbl/src/nsXBLService.cpp +++ b/mozilla/content/xbl/src/nsXBLService.cpp @@ -522,42 +522,21 @@ nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL, PRBool aAugmentFl } } - // Security check - remote pages can't load local bindings, except from chrome - nsIURI *docURI = document->GetDocumentURI(); - PRBool isChrome = PR_FALSE; - rv = docURI->SchemeIs("chrome", &isChrome); - - // Not everything with a chrome URI has a system principal. See bug 160042. - if (NS_FAILED(rv) || !isChrome) { - rv = nsContentUtils::GetSecurityManager()-> - CheckLoadURIWithPrincipal(document->NodePrincipal(), aURL, - nsIScriptSecurityManager::ALLOW_CHROME); - if (NS_FAILED(rv)) - return rv; - } - - // Content policy check. We have to be careful to not pass aContent as the - // context here. Otherwise, if there is a JS-implemented content policy, we - // will attempt to wrap the content node, which will try to load XBL bindings - // for it, if any. Since we're not done loading this binding yet, that will - // reenter this method and we'll end up creating a binding and then - // immediately clobbering it in our table. That makes things very confused, - // leading to misbehavior and crashes. - PRInt16 decision = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER, - aURL, - docURI, - document, // context - EmptyCString(), // mime guess - nsnull, // extra - &decision, - nsContentUtils::GetContentPolicy()); - - if (NS_SUCCEEDED(rv) && !NS_CP_ACCEPTED(decision)) - rv = NS_ERROR_NOT_AVAILABLE; - - if (NS_FAILED(rv)) - return rv; + // Security check - Enforce same-origin policy, except to chrome. + // We have to be careful to not pass aContent as the context here. + // Otherwise, if there is a JS-implemented content policy, we will attempt + // to wrap the content node, which will try to load XBL bindings for it, if + // any. Since we're not done loading this binding yet, that will reenter + // this method and we'll end up creating a binding and then immediately + // clobbering it in our table. That makes things very confused, leading to + // misbehavior and crashes. + rv = nsContentUtils::CheckSecurityBeforeLoad(aURL, + document->NodePrincipal(), + nsIScriptSecurityManager::ALLOW_CHROME, + PR_TRUE, + nsIContentPolicy::TYPE_OTHER, + document); + NS_ENSURE_SUCCESS(rv, rv); PRBool ready; nsRefPtr newBinding; @@ -986,7 +965,16 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, { NS_PRECONDITION(aBindingURI, "Must have a binding URI"); - nsresult rv = NS_OK; + nsresult rv; + if (aBoundDocument) { + rv = nsContentUtils:: + CheckSecurityBeforeLoad(aBindingURI, aBoundDocument->NodePrincipal(), + nsIScriptSecurityManager::ALLOW_CHROME, + PR_TRUE, + nsIContentPolicy::TYPE_OTHER, + aBoundDocument); + NS_ENSURE_SUCCESS(rv, rv); + } *aResult = nsnull; nsCOMPtr info; @@ -1097,6 +1085,43 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, return NS_OK; } +class nsSameOriginChecker : public nsIChannelEventSink, + public nsIInterfaceRequestor +{ + NS_DECL_ISUPPORTS + NS_DECL_NSICHANNELEVENTSINK + NS_DECL_NSIINTERFACEREQUESTOR +}; + +NS_IMPL_ISUPPORTS2(nsSameOriginChecker, + nsIChannelEventSink, + nsIInterfaceRequestor) + +NS_IMETHODIMP +nsSameOriginChecker::OnChannelRedirect(nsIChannel *aOldChannel, + nsIChannel *aNewChannel, + PRUint32 aFlags) +{ + NS_PRECONDITION(aNewChannel, "Redirecting to null channel?"); + + nsCOMPtr oldURI; + nsresult rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); // The original URI + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The new URI + NS_ENSURE_SUCCESS(rv, rv); + + return nsContentUtils::GetSecurityManager()-> + CheckSameOriginURI(oldURI, newURI); +} + +NS_IMETHODIMP +nsSameOriginChecker::GetInterface(const nsIID & aIID, void **aResult) +{ + return QueryInterface(aIID, aResult); +} + nsresult nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument, nsIURI* aDocumentURI, nsIURI* aBindingURI, @@ -1131,6 +1156,11 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nsnull, loadGroup); NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr sameOriginChecker = new nsSameOriginChecker; + NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY); + + channel->SetNotificationCallbacks(sameOriginChecker); + nsCOMPtr listener; rv = doc->StartDocumentLoad("loadAsInteractiveData", channel, diff --git a/mozilla/content/xml/document/src/nsXMLPrettyPrinter.cpp b/mozilla/content/xml/document/src/nsXMLPrettyPrinter.cpp index 708733db310..6051519bc42 100644 --- a/mozilla/content/xml/document/src/nsXMLPrettyPrinter.cpp +++ b/mozilla/content/xml/document/src/nsXMLPrettyPrinter.cpp @@ -155,9 +155,7 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument, NS_ASSERTION(xblDoc, "xml document doesn't implement nsIDOMDocumentXBL"); NS_ENSURE_TRUE(xblDoc, NS_ERROR_FAILURE); - nsCOMPtr dummy; - xblDoc->LoadBindingDocument(NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml"), - getter_AddRefs(dummy)); + xblDoc->LoadBindingDocument(NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml")); nsCOMPtr rootElem; sourceDocument->GetDocumentElement(getter_AddRefs(rootElem)); diff --git a/mozilla/dom/public/idl/xbl/nsIDOMDocumentXBL.idl b/mozilla/dom/public/idl/xbl/nsIDOMDocumentXBL.idl index 21c83b97cf1..6a7a9fb78db 100644 --- a/mozilla/dom/public/idl/xbl/nsIDOMDocumentXBL.idl +++ b/mozilla/dom/public/idl/xbl/nsIDOMDocumentXBL.idl @@ -39,7 +39,7 @@ #include "domstubs.idl" -[scriptable, uuid(c7c0ae9b-a0ba-4f4e-9f2c-c18deb62ee8b)] +[scriptable, uuid(1a38762b-4da5-4f61-80fb-9317e198cb92)] interface nsIDOMDocumentXBL : nsISupports { nsIDOMNodeList getAnonymousNodes(in nsIDOMElement elt); @@ -53,5 +53,5 @@ interface nsIDOMDocumentXBL : nsISupports in DOMString bindingURL); nsIDOMElement getBindingParent(in nsIDOMNode node); - nsIDOMDocument loadBindingDocument(in DOMString documentURL); + void loadBindingDocument(in DOMString documentURL); };