Bug 685518 part 1. Look at the image CORS mode for drawImage into a canvas 2d context. r=roc

This commit is contained in:
Boris Zbarsky 2011-09-09 17:58:35 -04:00
parent cdbf62540d
commit fde72dbe8b
7 changed files with 53 additions and 31 deletions

View File

@ -65,7 +65,8 @@ namespace CanvasUtils {
void
DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
nsIPrincipal *aPrincipal,
PRBool forceWriteOnly)
PRBool forceWriteOnly,
PRBool CORSUsed)
{
// Callers should ensure that mCanvasElement is non-null before calling this
if (!aCanvasElement) {
@ -85,6 +86,10 @@ DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
if (aPrincipal == nsnull)
return;
// No need to do a security check if the image used CORS for the load
if (CORSUsed)
return;
PRBool subsumes;
nsresult rv =
aCanvasElement->NodePrincipal()->Subsumes(aPrincipal, &subsumes);

View File

@ -74,7 +74,8 @@ inline PRBool CheckSaneSubrectSize(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h,
void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
nsIPrincipal *aPrincipal,
PRBool forceWriteOnly);
PRBool forceWriteOnly,
PRBool CORSUsed);
void LogMessage (const nsCString& errorString);
void LogMessagef (const char *fmt, ...);

View File

@ -3584,19 +3584,13 @@ WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
// validated for cross-domain use.
// if res.mPrincipal == null, no need for the origin check. See DoDrawImageSecurityCheck.
// this case happens in the mochitest for images served from mochi.test:8888
if (res.mPrincipal) {
if (res.mPrincipal && !res.mCORSUsed) {
PRBool subsumes;
nsresult rv = HTMLCanvasElement()->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
if (NS_FAILED(rv) || !subsumes) {
PRInt32 corsmode;
if (!res.mImageRequest || NS_FAILED(res.mImageRequest->GetCORSMode(&corsmode))) {
corsmode = imgIRequest::CORS_NONE;
}
if (corsmode == imgIRequest::CORS_NONE) {
LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
"See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
return NS_ERROR_DOM_SECURITY_ERR;
}
LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
"See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
return NS_ERROR_DOM_SECURITY_ERR;
}
}

View File

@ -246,26 +246,30 @@ public:
nsCanvasPattern(gfxPattern* pat,
nsIPrincipal* principalForSecurityCheck,
PRBool forceWriteOnly)
PRBool forceWriteOnly,
PRBool CORSUsed)
: mPattern(pat),
mPrincipal(principalForSecurityCheck),
mForceWriteOnly(forceWriteOnly)
mForceWriteOnly(forceWriteOnly),
mCORSUsed(CORSUsed)
{
}
gfxPattern* GetPattern() {
gfxPattern* GetPattern() const {
return mPattern;
}
nsIPrincipal* Principal() { return mPrincipal; }
PRBool GetForceWriteOnly() { return mForceWriteOnly; }
nsIPrincipal* Principal() const { return mPrincipal; }
PRBool GetForceWriteOnly() const { return mForceWriteOnly; }
PRBool GetCORSUsed() const { return mCORSUsed; }
NS_DECL_ISUPPORTS
protected:
nsRefPtr<gfxPattern> mPattern;
nsCOMPtr<nsIPrincipal> mPrincipal;
PRPackedBool mForceWriteOnly;
const PRPackedBool mForceWriteOnly;
const PRPackedBool mCORSUsed;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPattern, NS_CANVASPATTERN_PRIVATE_IID)
@ -994,7 +998,8 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle,
if (mCanvasElement)
CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
pattern->Principal(),
pattern->GetForceWriteOnly());
pattern->GetForceWriteOnly(),
pattern->GetCORSUsed());
gfxPattern* gpat = pattern->GetPattern();
@ -1842,7 +1847,8 @@ nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image,
thebespat->SetExtend(extend);
nsRefPtr<nsCanvasPattern> pat = new nsCanvasPattern(thebespat, res.mPrincipal,
res.mIsWriteOnly);
res.mIsWriteOnly,
res.mCORSUsed);
if (!pat)
return NS_ERROR_OUT_OF_MEMORY;
@ -3438,7 +3444,9 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
if (mCanvasElement) {
CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
res.mPrincipal, res.mIsWriteOnly);
res.mPrincipal,
res.mIsWriteOnly,
res.mCORSUsed);
}
if (res.mImageRequest) {

View File

@ -306,20 +306,23 @@ public:
nsCanvasPatternAzure(SourceSurface* aSurface,
RepeatMode aRepeat,
nsIPrincipal* principalForSecurityCheck,
PRBool forceWriteOnly)
PRBool forceWriteOnly,
PRBool CORSUsed)
: mSurface(aSurface)
, mRepeat(aRepeat)
, mPrincipal(principalForSecurityCheck)
, mForceWriteOnly(forceWriteOnly)
, mCORSUsed(CORSUsed)
{
}
NS_DECL_ISUPPORTS
RefPtr<SourceSurface> mSurface;
RepeatMode mRepeat;
const RepeatMode mRepeat;
nsCOMPtr<nsIPrincipal> mPrincipal;
PRPackedBool mForceWriteOnly;
const PRPackedBool mForceWriteOnly;
const PRPackedBool mCORSUsed;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPatternAzure, NS_CANVASPATTERNAZURE_PRIVATE_IID)
@ -798,7 +801,8 @@ protected:
if (aCtx->mCanvasElement) {
CanvasUtils::DoDrawImageSecurityCheck(aCtx->HTMLCanvasElement(),
state.patternStyles[aStyle]->mPrincipal,
state.patternStyles[aStyle]->mForceWriteOnly);
state.patternStyles[aStyle]->mForceWriteOnly,
state.patternStyles[aStyle]->mCORSUsed);
}
ExtendMode mode;
@ -1912,8 +1916,7 @@ nsCanvasRenderingContext2DAzure::CreatePattern(nsIDOMHTMLElement *image,
}
// Special case for Canvas, which could be an Azure canvas!
nsCOMPtr<nsINode> node = do_QueryInterface(image);
if (canvas && node) {
if (canvas) {
if (canvas->CountContexts() == 1) {
nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
@ -1922,7 +1925,7 @@ nsCanvasRenderingContext2DAzure::CreatePattern(nsIDOMHTMLElement *image,
RefPtr<SourceSurface> srcSurf = srcCanvas->GetSurfaceSnapshot();
nsRefPtr<nsCanvasPatternAzure> pat =
new nsCanvasPatternAzure(srcSurf, repeatMode, node->NodePrincipal(), canvas->IsWriteOnly());
new nsCanvasPatternAzure(srcSurf, repeatMode, content->NodePrincipal(), canvas->IsWriteOnly(), PR_FALSE);
*_retval = pat.forget().get();
return NS_OK;
@ -1949,7 +1952,8 @@ nsCanvasRenderingContext2DAzure::CreatePattern(nsIDOMHTMLElement *image,
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
nsRefPtr<nsCanvasPatternAzure> pat =
new nsCanvasPatternAzure(srcSurf, repeatMode, res.mPrincipal, res.mIsWriteOnly);
new nsCanvasPatternAzure(srcSurf, repeatMode, res.mPrincipal,
res.mIsWriteOnly, res.mCORSUsed);
*_retval = pat.forget().get();
return NS_OK;
@ -3700,7 +3704,8 @@ nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1,
if (mCanvasElement) {
CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
res.mPrincipal, res.mIsWriteOnly);
res.mPrincipal, res.mIsWriteOnly,
res.mCORSUsed);
}
if (res.mImageRequest) {

View File

@ -4118,6 +4118,11 @@ nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement,
ctx->Paint();
}
PRInt32 corsmode;
if (NS_SUCCEEDED(imgRequest->GetCORSMode(&corsmode))) {
result.mCORSUsed = (corsmode != imgIRequest::CORS_NONE);
}
result.mSurface = gfxsurf;
result.mSize = gfxIntSize(imgWidth, imgHeight);
result.mPrincipal = principal.forget();

View File

@ -1349,7 +1349,9 @@ public:
};
struct SurfaceFromElementResult {
SurfaceFromElementResult() : mIsWriteOnly(PR_TRUE), mIsStillLoading(PR_FALSE) {}
SurfaceFromElementResult() :
// Use safe default values here
mIsWriteOnly(PR_TRUE), mIsStillLoading(PR_FALSE), mCORSUsed(PR_FALSE) {}
/* mSurface will contain the resulting surface, or will be NULL on error */
nsRefPtr<gfxASurface> mSurface;
@ -1364,6 +1366,8 @@ public:
/* Whether the element was still loading. Some consumers need to handle
this case specially. */
PRPackedBool mIsStillLoading;
/* Whether the element used CORS when loading. */
PRPackedBool mCORSUsed;
};
static SurfaceFromElementResult SurfaceFromElement(nsIDOMElement *aElement,