Bug 379959: Add checks to loadBindingDocument. r/sr=jst

git-svn-id: svn://10.0.0.236/trunk@227915 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jonas%sicking.cc
2007-06-12 21:56:07 +00:00
parent 9699a79528
commit 51a63ab07f
8 changed files with 163 additions and 68 deletions

View File

@@ -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();

View File

@@ -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<nsIURI> 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<nsIURI> 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);
}

View File

@@ -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<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
mCharacterSet.get(),
NS_STATIC_CAST(nsIDocument *, this)->GetBaseURI());
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc;
mBindingManager->LoadBindingDocument(this, uri, getter_AddRefs(doc));
if (doc) {
CallQueryInterface(doc, aResult);
}
mBindingManager->LoadBindingDocument(this, uri);
return NS_OK;
}

View File

@@ -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<nsIXBLService> 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;
}

View File

@@ -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();

View File

@@ -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<nsXBLBinding> 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<nsIXBLDocumentInfo> 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<nsIURI> oldURI;
nsresult rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); // The original URI
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> 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<nsIInterfaceRequestor> sameOriginChecker = new nsSameOriginChecker;
NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
channel->SetNotificationCallbacks(sameOriginChecker);
nsCOMPtr<nsIStreamListener> listener;
rv = doc->StartDocumentLoad("loadAsInteractiveData",
channel,

View File

@@ -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<nsIDOMDocument> 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<nsIDOMElement> rootElem;
sourceDocument->GetDocumentElement(getter_AddRefs(rootElem));

View File

@@ -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);
};