mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1833876. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D179483
This commit is contained in:
parent
f2e760e8f6
commit
71792018b4
@ -465,8 +465,12 @@ class AdjustedTargetForFilter {
|
||||
|
||||
const gfx::FilterDescription& filter = mCtx->CurrentState().filter;
|
||||
MOZ_RELEASE_ASSERT(!filter.mPrimitives.IsEmpty());
|
||||
if (filter.mPrimitives.LastElement().IsTainted() && mCtx->mCanvasElement) {
|
||||
mCtx->mCanvasElement->SetWriteOnly();
|
||||
if (filter.mPrimitives.LastElement().IsTainted()) {
|
||||
if (mCtx->mCanvasElement) {
|
||||
mCtx->mCanvasElement->SetWriteOnly();
|
||||
} else if (mCtx->mOffscreenCanvas) {
|
||||
mCtx->mOffscreenCanvas->SetWriteOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5795,9 +5799,10 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
|
||||
|
||||
// Check only if we have a canvas element; if we were created with a docshell,
|
||||
// then it's special internal use.
|
||||
// FIXME(aosmond): OffscreenCanvas security check??!
|
||||
if (IsWriteOnly() ||
|
||||
(mCanvasElement && !mCanvasElement->CallerCanRead(aCx))) {
|
||||
(mCanvasElement && !mCanvasElement->CallerCanRead(aSubjectPrincipal)) ||
|
||||
(mOffscreenCanvas &&
|
||||
!mOffscreenCanvas->CallerCanRead(aSubjectPrincipal))) {
|
||||
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
|
||||
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
@ -6317,6 +6322,8 @@ void CanvasRenderingContext2D::SetWriteOnly() {
|
||||
mWriteOnly = true;
|
||||
if (mCanvasElement) {
|
||||
mCanvasElement->SetWriteOnly();
|
||||
} else if (mOffscreenCanvas) {
|
||||
mOffscreenCanvas->SetWriteOnly();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,7 +373,8 @@ void DoDrawImageSecurityCheck(dom::OffscreenCanvas* aOffscreenCanvas,
|
||||
return;
|
||||
}
|
||||
|
||||
if (aOffscreenCanvas->IsWriteOnly()) {
|
||||
nsIPrincipal* expandedReader = aOffscreenCanvas->GetExpandedReader();
|
||||
if (aOffscreenCanvas->IsWriteOnly() && !expandedReader) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -401,6 +402,24 @@ void DoDrawImageSecurityCheck(dom::OffscreenCanvas* aOffscreenCanvas,
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
|
||||
// This is a resource from an extension content script principal.
|
||||
|
||||
if (expandedReader && expandedReader->Subsumes(aPrincipal)) {
|
||||
// This canvas already allows reading from this principal.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!expandedReader) {
|
||||
// Allow future reads from this same princial only.
|
||||
aOffscreenCanvas->SetWriteOnly(aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got here, this must be the *second* extension tainting
|
||||
// the canvas. Fall through to mark it WriteOnly for everyone.
|
||||
}
|
||||
|
||||
aOffscreenCanvas->SetWriteOnly();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "ImageBitmap.h"
|
||||
#include "ImageBitmapRenderingContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "WebGLChild.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
@ -34,32 +35,40 @@ namespace mozilla::dom {
|
||||
OffscreenCanvasCloneData::OffscreenCanvasCloneData(
|
||||
OffscreenCanvasDisplayHelper* aDisplay, uint32_t aWidth, uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend, layers::TextureType aTextureType,
|
||||
bool aNeutered, bool aIsWriteOnly)
|
||||
bool aNeutered, bool aIsWriteOnly, nsIPrincipal* aExpandedReader)
|
||||
: mDisplay(aDisplay),
|
||||
mWidth(aWidth),
|
||||
mHeight(aHeight),
|
||||
mCompositorBackendType(aCompositorBackend),
|
||||
mTextureType(aTextureType),
|
||||
mNeutered(aNeutered),
|
||||
mIsWriteOnly(aIsWriteOnly) {}
|
||||
mIsWriteOnly(aIsWriteOnly),
|
||||
mExpandedReader(aExpandedReader) {}
|
||||
|
||||
OffscreenCanvasCloneData::~OffscreenCanvasCloneData() = default;
|
||||
OffscreenCanvasCloneData::~OffscreenCanvasCloneData() {
|
||||
NS_ReleaseOnMainThread("OffscreenCanvasCloneData::mExpandedReader",
|
||||
mExpandedReader.forget());
|
||||
}
|
||||
|
||||
OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
layers::TextureType aTextureType,
|
||||
OffscreenCanvasDisplayHelper* aDisplay)
|
||||
uint32_t aHeight)
|
||||
: DOMEventTargetHelper(aGlobal), mWidth(aWidth), mHeight(aHeight) {}
|
||||
|
||||
OffscreenCanvas::OffscreenCanvas(
|
||||
nsIGlobalObject* aGlobal, uint32_t aWidth, uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend, layers::TextureType aTextureType,
|
||||
already_AddRefed<OffscreenCanvasDisplayHelper> aDisplay)
|
||||
: DOMEventTargetHelper(aGlobal),
|
||||
mNeutered(false),
|
||||
mIsWriteOnly(false),
|
||||
mWidth(aWidth),
|
||||
mHeight(aHeight),
|
||||
mCompositorBackendType(aCompositorBackend),
|
||||
mTextureType(aTextureType),
|
||||
mDisplay(aDisplay) {}
|
||||
|
||||
OffscreenCanvas::~OffscreenCanvas() = default;
|
||||
OffscreenCanvas::~OffscreenCanvas() {
|
||||
NS_ReleaseOnMainThread("OffscreenCanvas::mExpandedReader",
|
||||
mExpandedReader.forget());
|
||||
}
|
||||
|
||||
JSObject* OffscreenCanvas::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
@ -88,9 +97,8 @@ already_AddRefed<OffscreenCanvas> OffscreenCanvas::Constructor(
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<OffscreenCanvas> offscreenCanvas = new OffscreenCanvas(
|
||||
global, aWidth, aHeight, layers::LayersBackend::LAYERS_NONE,
|
||||
layers::TextureType::Unknown, nullptr);
|
||||
RefPtr<OffscreenCanvas> offscreenCanvas =
|
||||
new OffscreenCanvas(global, aWidth, aHeight);
|
||||
return offscreenCanvas.forget();
|
||||
}
|
||||
|
||||
@ -275,7 +283,7 @@ void OffscreenCanvas::CommitFrameToCompositor() {
|
||||
OffscreenCanvasCloneData* OffscreenCanvas::ToCloneData() {
|
||||
return new OffscreenCanvasCloneData(mDisplay, mWidth, mHeight,
|
||||
mCompositorBackendType, mTextureType,
|
||||
mNeutered, mIsWriteOnly);
|
||||
mNeutered, mIsWriteOnly, mExpandedReader);
|
||||
}
|
||||
|
||||
already_AddRefed<ImageBitmap> OffscreenCanvas::TransferToImageBitmap(
|
||||
@ -463,6 +471,29 @@ already_AddRefed<gfx::SourceSurface> OffscreenCanvas::GetSurfaceSnapshot(
|
||||
return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
|
||||
}
|
||||
|
||||
void OffscreenCanvas::SetWriteOnly(RefPtr<nsIPrincipal>&& aExpandedReader) {
|
||||
NS_ReleaseOnMainThread("OffscreenCanvas::mExpandedReader",
|
||||
mExpandedReader.forget());
|
||||
mExpandedReader = std::move(aExpandedReader);
|
||||
mIsWriteOnly = true;
|
||||
}
|
||||
|
||||
bool OffscreenCanvas::CallerCanRead(nsIPrincipal& aPrincipal) const {
|
||||
if (!mIsWriteOnly) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If mExpandedReader is set, this canvas was tainted only by
|
||||
// mExpandedReader's resources. So allow reading if the subject
|
||||
// principal subsumes mExpandedReader.
|
||||
if (mExpandedReader && aPrincipal.Subsumes(mExpandedReader)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return nsContentUtils::PrincipalHasPermission(aPrincipal,
|
||||
nsGkAtoms::all_urlsPermission);
|
||||
}
|
||||
|
||||
bool OffscreenCanvas::ShouldResistFingerprinting(RFPTarget aTarget) const {
|
||||
return nsContentUtils::ShouldResistFingerprinting(GetOwnerGlobal(), aTarget);
|
||||
}
|
||||
@ -473,10 +504,13 @@ already_AddRefed<OffscreenCanvas> OffscreenCanvas::CreateFromCloneData(
|
||||
MOZ_ASSERT(aData);
|
||||
RefPtr<OffscreenCanvas> wc = new OffscreenCanvas(
|
||||
aGlobal, aData->mWidth, aData->mHeight, aData->mCompositorBackendType,
|
||||
aData->mTextureType, aData->mDisplay);
|
||||
aData->mTextureType, aData->mDisplay.forget());
|
||||
if (aData->mNeutered) {
|
||||
wc->SetNeutered();
|
||||
}
|
||||
if (aData->mIsWriteOnly) {
|
||||
wc->SetWriteOnly(std::move(aData->mExpandedReader));
|
||||
}
|
||||
return wc.forget();
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ struct OffscreenCanvasCloneData final {
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
layers::TextureType aTextureType, bool aNeutered,
|
||||
bool aIsWriteOnly);
|
||||
bool aIsWriteOnly, nsIPrincipal* aExpandedReader);
|
||||
~OffscreenCanvasCloneData();
|
||||
|
||||
RefPtr<OffscreenCanvasDisplayHelper> mDisplay;
|
||||
@ -58,6 +58,7 @@ struct OffscreenCanvasCloneData final {
|
||||
layers::TextureType mTextureType;
|
||||
bool mNeutered;
|
||||
bool mIsWriteOnly;
|
||||
RefPtr<nsIPrincipal> mExpandedReader;
|
||||
};
|
||||
|
||||
class OffscreenCanvas final : public DOMEventTargetHelper,
|
||||
@ -70,10 +71,12 @@ class OffscreenCanvas final : public DOMEventTargetHelper,
|
||||
IMPL_EVENT_HANDLER(contextlost);
|
||||
IMPL_EVENT_HANDLER(contextrestored);
|
||||
|
||||
OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth, uint32_t aHeight);
|
||||
|
||||
OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth, uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
layers::TextureType aTextureType,
|
||||
OffscreenCanvasDisplayHelper* aDisplay);
|
||||
already_AddRefed<OffscreenCanvasDisplayHelper> aDisplay);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const { return GetOwnerGlobal(); }
|
||||
|
||||
@ -146,10 +149,20 @@ class OffscreenCanvas final : public DOMEventTargetHelper,
|
||||
|
||||
bool MayNeuter() const { return !mNeutered && !mCurrentContext; }
|
||||
|
||||
void SetWriteOnly() { mIsWriteOnly = true; }
|
||||
nsIPrincipal* GetExpandedReader() const { return mExpandedReader; }
|
||||
|
||||
void SetWriteOnly(RefPtr<nsIPrincipal>&& aExpandedReader);
|
||||
|
||||
void SetWriteOnly(nsIPrincipal* aExpandedReader = nullptr) {
|
||||
RefPtr<nsIPrincipal> expandedReader(aExpandedReader);
|
||||
SetWriteOnly(std::move(expandedReader));
|
||||
}
|
||||
|
||||
bool IsWriteOnly() const { return mIsWriteOnly; }
|
||||
|
||||
// Determines if the caller should be able to read the content.
|
||||
bool CallerCanRead(nsIPrincipal& aPrincipal) const;
|
||||
|
||||
layers::LayersBackend GetCompositorBackendType() const {
|
||||
return mCompositorBackendType;
|
||||
}
|
||||
@ -169,17 +182,19 @@ class OffscreenCanvas final : public DOMEventTargetHelper,
|
||||
UpdateContext(nullptr, JS::NullHandleValue, dummy);
|
||||
}
|
||||
|
||||
bool mNeutered;
|
||||
bool mIsWriteOnly;
|
||||
bool mNeutered = false;
|
||||
bool mIsWriteOnly = false;
|
||||
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint32_t mWidth = 0;
|
||||
uint32_t mHeight = 0;
|
||||
|
||||
layers::LayersBackend mCompositorBackendType;
|
||||
layers::TextureType mTextureType;
|
||||
layers::LayersBackend mCompositorBackendType =
|
||||
layers::LayersBackend::LAYERS_NONE;
|
||||
layers::TextureType mTextureType = layers::TextureType::Unknown;
|
||||
|
||||
RefPtr<OffscreenCanvasDisplayHelper> mDisplay;
|
||||
RefPtr<CancelableRunnable> mPendingCommit;
|
||||
RefPtr<nsIPrincipal> mExpandedReader;
|
||||
Maybe<OffscreenCanvasDisplayData> mPendingUpdate;
|
||||
};
|
||||
|
||||
|
@ -763,7 +763,7 @@ void HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv) {
|
||||
// mWriteOnly check is redundant, but optimizes for the common case.
|
||||
if (mWriteOnly && !CallerCanRead(aCx)) {
|
||||
if (mWriteOnly && !CallerCanRead(aSubjectPrincipal)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@ -948,7 +948,7 @@ void HTMLCanvasElement::ToBlob(JSContext* aCx, BlobCallback& aCallback,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv) {
|
||||
// mWriteOnly check is redundant, but optimizes for the common case.
|
||||
if (mWriteOnly && !CallerCanRead(aCx)) {
|
||||
if (mWriteOnly && !CallerCanRead(aSubjectPrincipal)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@ -1010,9 +1010,9 @@ OffscreenCanvas* HTMLCanvasElement::TransferControlToOffscreen(
|
||||
MakeRefPtr<OffscreenCanvasDisplayHelper>(this, sz.width, sz.height);
|
||||
mOffscreenCanvas =
|
||||
new OffscreenCanvas(win->AsGlobal(), sz.width, sz.height, backend,
|
||||
textureType, mOffscreenDisplay);
|
||||
textureType, do_AddRef(mOffscreenDisplay));
|
||||
if (mWriteOnly) {
|
||||
mOffscreenCanvas->SetWriteOnly();
|
||||
mOffscreenCanvas->SetWriteOnly(mExpandedReader);
|
||||
}
|
||||
|
||||
if (!mContextObserver) {
|
||||
@ -1053,25 +1053,23 @@ void HTMLCanvasElement::SetWriteOnly(
|
||||
mExpandedReader = aExpandedReader;
|
||||
mWriteOnly = true;
|
||||
if (mOffscreenCanvas) {
|
||||
mOffscreenCanvas->SetWriteOnly();
|
||||
mOffscreenCanvas->SetWriteOnly(aExpandedReader);
|
||||
}
|
||||
}
|
||||
|
||||
bool HTMLCanvasElement::CallerCanRead(JSContext* aCx) const {
|
||||
bool HTMLCanvasElement::CallerCanRead(nsIPrincipal& aPrincipal) const {
|
||||
if (!mWriteOnly) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIPrincipal* prin = nsContentUtils::SubjectPrincipal(aCx);
|
||||
|
||||
// If mExpandedReader is set, this canvas was tainted only by
|
||||
// mExpandedReader's resources. So allow reading if the subject
|
||||
// principal subsumes mExpandedReader.
|
||||
if (mExpandedReader && prin->Subsumes(mExpandedReader)) {
|
||||
if (mExpandedReader && aPrincipal.Subsumes(mExpandedReader)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return nsContentUtils::PrincipalHasPermission(*prin,
|
||||
return nsContentUtils::PrincipalHasPermission(aPrincipal,
|
||||
nsGkAtoms::all_urlsPermission);
|
||||
}
|
||||
|
||||
|
@ -373,7 +373,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
|
||||
RefPtr<nsIPrincipal> mExpandedReader;
|
||||
|
||||
// Determines if the caller should be able to read the content.
|
||||
bool CallerCanRead(JSContext* aCx) const;
|
||||
bool CallerCanRead(nsIPrincipal& aPrincipal) const;
|
||||
|
||||
bool IsPrintCallbackDone();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user