Bug 341604 - modify CheckMayLoad to allow sandboxed workers to load blob and data URIs r=jst

This commit is contained in:
Ian Melven 2012-08-20 11:34:33 -07:00
parent 0fbebce11b
commit 01a802da01
21 changed files with 103 additions and 60 deletions

View File

@ -21,7 +21,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSPrincipals(JSPrincipals);
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
[scriptable, uuid(6df7d16d-5b26-42a1-b1f7-069d46c37aa8)]
[scriptable, uuid(825ffce8-962d-11e1-aef3-8f2b6188709b)]
interface nsIPrincipal : nsISerializable
{
/**
@ -173,7 +173,13 @@ interface nsIPrincipal : nsISerializable
* located at the given URI under the same-origin policy. This means that
* codebase principals are only allowed to load resources from the same
* domain, the system principal is allowed to load anything, and null
* principals are not allowed to load anything.
* principals are not allowed to load anything. This is changed slightly
* by the optional flag allowIfInheritsPrincipal (which defaults to false)
* which allows the load of a data: URI (which inherits the principal of
* its loader) or a URI with the same principal as its loader (eg. a
* Blob URI).
* In these cases, with allowIfInheritsPrincipal set to true, the URI can
* be loaded by a null principal.
*
* If the load is allowed this function does nothing. If the load is not
* allowed the function throws NS_ERROR_DOM_BAD_URI.
@ -187,9 +193,13 @@ interface nsIPrincipal : nsISerializable
* @param uri The URI about to be loaded.
* @param report If true, will report a warning to the console service
* if the load is not allowed.
* @param allowIfInheritsPrincipal If true, the load is allowed if the
* loadee inherits the principal of the
* loader.
* @throws NS_ERROR_DOM_BAD_URI if the load is not allowed.
*/
void checkMayLoad(in nsIURI uri, in boolean report);
void checkMayLoad(in nsIURI uri, in boolean report,
in boolean allowIfInheritsPrincipal);
/**
* The subject name for the certificate. This actually identifies the

View File

@ -15,6 +15,7 @@
#include "nsIPrincipal.h"
#include "nsJSPrincipals.h"
#include "nsCOMPtr.h"
#include "nsPrincipal.h"
class nsIURI;

View File

@ -13,6 +13,9 @@
#include "nsJSPrincipals.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "nsIProtocolHandler.h"
#include "nsNetUtil.h"
#include "nsScriptSecurityManager.h"
class nsIObjectInputStream;
class nsIObjectOutputStream;
@ -123,7 +126,7 @@ public:
NS_IMETHOD GetOrigin(char** aOrigin);
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
NS_IMETHOD GetAppStatus(PRUint16* aAppStatus);
NS_IMETHOD GetAppId(PRUint32* aAppStatus);
@ -158,6 +161,23 @@ public:
virtual void GetScriptLocation(nsACString& aStr) MOZ_OVERRIDE;
void SetURI(nsIURI* aURI);
static bool IsPrincipalInherited(nsIURI* aURI) {
// return true if the loadee URI has
// the URI_INHERITS_SECURITY_CONTEXT flag set.
bool doesInheritSecurityContext;
nsresult rv =
NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&doesInheritSecurityContext);
if (NS_SUCCEEDED(rv) && doesInheritSecurityContext) {
return true;
}
return false;
}
/**
* Computes the puny-encoded origin of aURI.
*/
@ -202,7 +222,7 @@ public:
NS_IMETHOD GetOrigin(char** aOrigin);
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
NS_IMETHOD GetAppStatus(PRUint16* aAppStatus);
NS_IMETHOD GetAppId(PRUint32* aAppStatus);

View File

@ -292,8 +292,26 @@ nsNullPrincipal::SubsumesIgnoringDomain(nsIPrincipal *aOther, bool *aResult)
}
NS_IMETHODIMP
nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport)
{
nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal)
{
if (aAllowIfInheritsPrincipal) {
if (nsPrincipal::IsPrincipalInherited(aURI)) {
return NS_OK;
}
// Also allow the load if the principal of the URI being checked is exactly
// us ie this.
nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
if (uriPrinc) {
nsCOMPtr<nsIPrincipal> principal;
uriPrinc->GetPrincipal(getter_AddRefs(principal));
if (principal && principal == this) {
return NS_OK;
}
}
}
if (aReport) {
nsScriptSecurityManager::ReportError(
nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mURI, aURI);

View File

@ -846,8 +846,16 @@ URIIsLocalFile(nsIURI *aURI)
}
NS_IMETHODIMP
nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport)
nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal)
{
if (aAllowIfInheritsPrincipal) {
// If the caller specified to allow loads of URIs that inherit
// our principal, allow the load if this URI inherits its principal
if (nsPrincipal::IsPrincipalInherited(aURI)) {
return NS_OK;
}
}
if (!nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
URIIsLocalFile(aURI)) {
@ -1432,11 +1440,11 @@ nsExpandedPrincipal::SubsumesIgnoringDomain(nsIPrincipal* aOther, bool* aResult)
}
NS_IMETHODIMP
nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport)
nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport, bool aAllowIfInheritsPrincipal)
{
nsresult rv;
for (uint32_t i = 0; i < mPrincipals.Length(); ++i){
rv = mPrincipals[i]->CheckMayLoad(uri, aReport);
rv = mPrincipals[i]->CheckMayLoad(uri, aReport, aAllowIfInheritsPrincipal);
if (NS_SUCCEEDED(rv))
return rv;
}

View File

@ -1394,7 +1394,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) {
return aPrincipal->CheckMayLoad(targetBaseURI, true);
return aPrincipal->CheckMayLoad(targetBaseURI, true, false);
}
//-- get the source scheme

View File

@ -115,7 +115,7 @@ nsSystemPrincipal::SubsumesIgnoringDomain(nsIPrincipal *other, bool *result)
}
NS_IMETHODIMP
nsSystemPrincipal::CheckMayLoad(nsIURI* uri, bool aReport)
nsSystemPrincipal::CheckMayLoad(nsIURI* uri, bool aReport, bool aAllowIfInheritsPrincipal)
{
return NS_OK;
}

View File

@ -1704,7 +1704,7 @@ public:
static already_AddRefed<nsIDocument>
GetDocumentFromScriptContext(nsIScriptContext *aScriptContext);
static bool CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel);
static bool CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal);
/**
* The method checks whether the caller can access native anonymous content.

View File

@ -1064,7 +1064,7 @@ nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
}
// Documents must list a manifest from the same origin
rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true);
rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true, false);
if (NS_FAILED(rv)) {
action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
}

View File

@ -4606,7 +4606,7 @@ nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
return NS_OK;
}
return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true);
return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true, false);
}
bool
@ -5756,9 +5756,9 @@ nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel
NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
nsresult rv = oldPrincipal->CheckMayLoad(newURI, false);
nsresult rv = oldPrincipal->CheckMayLoad(newURI, false, false);
if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
}
return rv;
@ -5929,13 +5929,13 @@ nsContentUtils::GetDocumentFromScriptContext(nsIScriptContext *aScriptContext)
/* static */
bool
nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel)
nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal)
{
nsCOMPtr<nsIURI> channelURI;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
NS_ENSURE_SUCCESS(rv, false);
return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false));
return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false, aAllowIfInheritsPrincipal));
}
nsContentTypeParser::nsContentTypeParser(const nsAString& aString)
@ -6722,7 +6722,7 @@ nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
// based on its own codebase later.
//
if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false)) &&
NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) &&
// One more check here. CheckMayLoad will always return true for the
// system principal, but we do NOT want to inherit in that case.
!IsSystemPrincipal(aLoadingPrincipal)) {

View File

@ -743,10 +743,10 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, bool aAllowDataURI)
}
if (!mHasBeenCrossSite &&
NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, false)) &&
NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, false, false)) &&
(originalURI == uri ||
NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(originalURI,
false)))) {
false, false)))) {
return NS_OK;
}

View File

@ -1065,18 +1065,12 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS(rv, rv);
// Allow data URIs (let them skip the CheckMayLoad call), since we want
// Allow data URIs and other URI's that inherit their principal by passing
// true as the 3rd argument of CheckMayLoad, since we want
// to allow external resources from data URIs regardless of the difference
// in URI scheme.
bool doesInheritSecurityContext;
rv =
NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&doesInheritSecurityContext);
if (NS_FAILED(rv) || !doesInheritSecurityContext) {
rv = requestingPrincipal->CheckMayLoad(aURI, true);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = requestingPrincipal->CheckMayLoad(aURI, true, true);
NS_ENSURE_SUCCESS(rv, rv);
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,

View File

@ -1713,18 +1713,9 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
return NS_OK;
}
// ...or if this is a same-origin request.
if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel)) {
return NS_OK;
}
// exempt data URIs from the same origin check.
nsCOMPtr<nsIURI> channelURI;
bool dataScheme = false;
if (NS_SUCCEEDED(NS_GetFinalChannelURI(aChannel,
getter_AddRefs(channelURI))) &&
NS_SUCCEEDED(channelURI->SchemeIs("data", &dataScheme)) &&
dataScheme) {
// If this is a same-origin request or the channel's URI inherits
// its principal, it's allowed.
if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel, true)) {
return NS_OK;
}

View File

@ -932,7 +932,7 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) &&
!SchemeIs(aBindingURI, "chrome")) {
rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI,
true);
true, false);
NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
}

View File

@ -333,7 +333,7 @@ nsXMLDocument::Load(const nsAString& aUrl, bool *aReturn)
// chrome document.
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
if (!nsContentUtils::IsSystemPrincipal(principal)) {
rv = principal->CheckMayLoad(uri, false);
rv = principal->CheckMayLoad(uri, false, false);
NS_ENSURE_SUCCESS(rv, rv);
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;

View File

@ -2658,7 +2658,7 @@ nsXULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
bool documentIsChrome = IsChromeURI(mDocumentURI);
if (!documentIsChrome) {
// Make sure we're allowed to load this overlay.
rv = NodePrincipal()->CheckMayLoad(aURI, true);
rv = NodePrincipal()->CheckMayLoad(aURI, true, false);
if (NS_FAILED(rv)) {
*aFailureFromContent = true;
return rv;

View File

@ -1328,7 +1328,7 @@ nsXULTemplateBuilder::LoadDataSourceUrls(nsIDocument* aDocument,
// don't add the uri to the list if the document is not allowed to
// load it
if (!isTrusted && NS_FAILED(docPrincipal->CheckMayLoad(uri, true)))
if (!isTrusted && NS_FAILED(docPrincipal->CheckMayLoad(uri, true, false)))
continue;
uriList->AppendElement(uri, false);

View File

@ -10072,7 +10072,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
if (!principal ||
NS_FAILED(principal->CheckMayLoad(newURI, true))) {
NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
return NS_ERROR_DOM_SECURITY_ERR;
}

View File

@ -300,11 +300,12 @@ public:
rv = uri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
// We exempt data URLs from the same origin check.
if (!scheme.EqualsLiteral("data")) {
rv = principal->CheckMayLoad(uri, false);
NS_ENSURE_SUCCESS(rv, rv);
}
// We pass true as the 3rd argument to checkMayLoad here.
// This allows workers in sandboxed documents to load data URLs
// (and other URLs that inherit their principal from their
// creator.)
rv = principal->CheckMayLoad(uri, false, true);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
@ -487,9 +488,9 @@ public:
rv = finalURI->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
// We exempt data urls again.
if (!scheme.EqualsLiteral("data") &&
NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, false))) {
// We exempt data urls and other URI's that inherit their
// principal again.
if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, false, true))) {
return NS_ERROR_DOM_BAD_URI;
}
}

View File

@ -1545,7 +1545,7 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
if ((NS_SUCCEEDED(rv) && inherit) ||
(nsContentUtils::URIIsLocalFile(aLoadData->mURI) &&
NS_SUCCEEDED(aLoadData->mLoaderPrincipal->
CheckMayLoad(aLoadData->mURI, false)))) {
CheckMayLoad(aLoadData->mURI, false, false)))) {
channel->SetOwner(aLoadData->mLoaderPrincipal);
}
}

View File

@ -890,9 +890,9 @@ RDFXMLDataSourceImpl::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
rv = oldPrincipal->CheckMayLoad(newURI, false);
rv = oldPrincipal->CheckMayLoad(newURI, false, false);
if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
}
if (NS_FAILED(rv))