Bug 1195172 - Use channel->ascynOpen2 layout/style/FontFaceSet.cpp (r=bz,cam)

This commit is contained in:
Christoph Kerschbaumer 2016-03-01 13:06:13 -08:00
parent b46dc013d9
commit 9ab1648f67
7 changed files with 63 additions and 74 deletions

View File

@ -229,7 +229,8 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
}
case nsIContentPolicy::TYPE_FONT: {
MOZ_ASSERT(false, "contentPolicyType not supported yet");
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
break;
}

View File

@ -7,6 +7,7 @@
#include "gfxUserFontSet.h"
#include "gfxPlatform.h"
#include "nsContentPolicyUtils.h"
#include "nsUnicharUtils.h"
#include "nsNetUtil.h"
#include "nsIJARChannel.h"
@ -1203,6 +1204,13 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI* aSrcURI,
return nullptr;
}
// We have to perform another content policy check here to prevent
// cache poisoning. E.g. a.com loads a font into the cache but
// b.com has a CSP not allowing any fonts to be loaded.
if (!aUserFontEntry->mFontSet->IsFontLoadAllowed(aSrcURI, aPrincipal)) {
return nullptr;
}
// Ignore principal when looking up a data: URI.
nsIPrincipal* principal;
if (IgnorePrincipal(aSrcURI)) {
@ -1217,12 +1225,14 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI* aSrcURI,
return entry->GetFontEntry();
}
// The channel is never openend; to be conservative we use the most
// restrictive security flag: SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS.
nsCOMPtr<nsIChannel> chan;
if (NS_FAILED(NS_NewChannel(getter_AddRefs(chan),
aSrcURI,
aPrincipal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER))) {
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
nsIContentPolicy::TYPE_FONT))) {
return nullptr;
}

View File

@ -262,6 +262,10 @@ public:
nsIPrincipal** aPrincipal,
bool* aBypassCache) = 0;
// check whether content policies allow the given URI to load.
virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal) = 0;
// initialize the process that loads external font data, which upon
// completion will call FontDataDownloadComplete method
virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,

View File

@ -21,6 +21,7 @@
#include "mozilla/Snprintf.h"
#include "mozilla/Telemetry.h"
#include "nsCORSListenerProxy.h"
#include "nsContentPolicyUtils.h"
#include "nsCSSParser.h"
#include "nsDeviceContext.h"
#include "nsFontFaceLoader.h"
@ -597,10 +598,9 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
aFontFaceSrc->mURI,
mDocument,
aUserFontEntry->GetPrincipal(),
nsILoadInfo::SEC_NORMAL,
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
nsIContentPolicy::TYPE_FONT,
loadGroup);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<nsFontFaceLoader> fontLoader =
@ -646,25 +646,9 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
loadGroup);
bool inherits = false;
rv = NS_URIChainHasFlags(aFontFaceSrc->mURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&inherits);
if (NS_SUCCEEDED(rv) && inherits) {
// allow data, javascript, etc URI's
rv = channel->AsyncOpen(streamLoader, nullptr);
} else {
RefPtr<nsCORSListenerProxy> listener =
new nsCORSListenerProxy(streamLoader, aUserFontEntry->GetPrincipal(), false);
// Doesn't matter what data: URI handling we use here, since we
// don't even use a CORS listener proxy for the data: case.
rv = listener->Init(channel, DataURIHandling::Disallow);
if (NS_SUCCEEDED(rv)) {
rv = channel->AsyncOpen(listener, nullptr);
}
if (NS_FAILED(rv)) {
fontLoader->DropChannel(); // explicitly need to break ref cycle
}
rv = channel->AsyncOpen2(streamLoader);
if (NS_FAILED(rv)) {
fontLoader->DropChannel(); // explicitly need to break ref cycle
}
if (NS_SUCCEEDED(rv)) {
@ -1338,13 +1322,6 @@ FontFaceSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
*aPrincipal = aFontFaceSrc->mOriginPrincipal;
}
nsresult rv = nsFontFaceLoader::CheckLoadAllowed(*aPrincipal,
aFontFaceSrc->mURI,
mDocument);
if (NS_FAILED(rv)) {
return rv;
}
*aBypassCache = false;
nsCOMPtr<nsIDocShell> docShell = mDocument->GetDocShell();
@ -1363,7 +1340,28 @@ FontFaceSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
}
}
return rv;
return NS_OK;
}
// @arg aPrincipal: generally this is mDocument->NodePrincipal() but
// might also be the original principal which enables user stylesheets
// to load font files via @font-face rules.
bool
FontFaceSet::IsFontLoadAllowed(nsIURI* aFontLocation, nsIPrincipal* aPrincipal)
{
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
aFontLocation,
aPrincipal,
mDocument,
EmptyCString(), // mime type
nullptr, // aExtra
&shouldLoad,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
}
nsresult
@ -1379,18 +1377,21 @@ FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
// node and a principal. This is because the document where the font is
// being loaded might have a different origin from the principal of the
// stylesheet that initiated the font load.
// Further, we only get here for data: loads, so it doesn't really matter
// whether we use SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS or not, to be more
// restrictive we use SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS.
rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
aFontFaceSrc->mURI,
mDocument,
aFontToLoad->GetPrincipal(),
nsILoadInfo::SEC_NORMAL,
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
nsIContentPolicy::TYPE_FONT);
NS_ENSURE_SUCCESS(rv, rv);
// blocking stream is OK for data URIs
nsCOMPtr<nsIInputStream> stream;
rv = channel->Open(getter_AddRefs(stream));
rv = channel->Open2(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
uint64_t bufferLength64;
@ -1742,6 +1743,14 @@ FontFaceSet::UserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
return mFontFaceSet->CheckFontLoad(aFontFaceSrc, aPrincipal, aBypassCache);
}
/* virtual */ bool
FontFaceSet::UserFontSet::IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal)
{
return mFontFaceSet &&
mFontFaceSet->IsFontLoadAllowed(aFontLocation, aPrincipal);
}
/* virtual */ nsresult
FontFaceSet::UserFontSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
const gfxFontFaceSrc* aFontFaceSrc)

View File

@ -64,6 +64,10 @@ public:
virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
nsIPrincipal** aPrincipal,
bool* aBypassCache) override;
virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal) override;
virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
const gfxFontFaceSrc* aFontFaceSrc) override;
@ -256,6 +260,7 @@ private:
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
nsIPrincipal** aPrincipal,
bool* aBypassCache);
bool IsFontLoadAllowed(nsIURI* aFontLocation, nsIPrincipal* aPrincipal);
bool GetPrivateBrowsing();
nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,

View File

@ -297,43 +297,6 @@ nsFontFaceLoader::Cancel()
mChannel->Cancel(NS_BINDING_ABORTED);
}
/* static */ nsresult
nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext)
{
nsresult rv;
if (!aSourcePrincipal)
return NS_OK;
// check with the security manager
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
rv = secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI,
nsIScriptSecurityManager::STANDARD);
if (NS_FAILED(rv)) {
return rv;
}
// check content policy
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
aTargetURI,
aSourcePrincipal,
aContext,
EmptyCString(), // mime type
nullptr,
&shouldLoad,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
return NS_ERROR_CONTENT_BLOCKED;
}
return NS_OK;
}
uint8_t
nsFontFaceLoader::GetFontDisplay()
{

View File

@ -42,9 +42,6 @@ public:
static void LoadTimerCallback(nsITimer* aTimer, void* aClosure);
static nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext);
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
protected: