Bug 1918690: Check canvas permission in RandomizePixels function. a=pascalc
Differential Revision: https://phabricator.services.mozilla.com/D255970
This commit is contained in:
committed by
pchevrel@mozilla.com
parent
8f6956fb31
commit
922992a8c2
@@ -2144,8 +2144,9 @@ UniquePtr<uint8_t[]> CanvasRenderingContext2D::GetImageBuffer(
|
||||
|
||||
if (ret && ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
nsRFPService::RandomizePixels(
|
||||
GetCookieJarSettings(), ret.get(), out_imageSize->width,
|
||||
out_imageSize->height, out_imageSize->width * out_imageSize->height * 4,
|
||||
GetCookieJarSettings(), PrincipalOrNull(), ret.get(),
|
||||
out_imageSize->width, out_imageSize->height,
|
||||
out_imageSize->width * out_imageSize->height * 4,
|
||||
SurfaceFormat::A8R8G8B8_UINT32);
|
||||
}
|
||||
|
||||
@@ -6407,9 +6408,10 @@ nsresult CanvasRenderingContext2D::GetImageDataArray(
|
||||
// holder.
|
||||
|
||||
const IntSize size = readback->GetSize();
|
||||
nsRFPService::RandomizePixels(
|
||||
GetCookieJarSettings(), rawData.mData, size.width, size.height,
|
||||
size.height * size.width * 4, SurfaceFormat::A8R8G8B8_UINT32);
|
||||
nsRFPService::RandomizePixels(GetCookieJarSettings(), PrincipalOrNull(),
|
||||
rawData.mData, size.width, size.height,
|
||||
size.height * size.width * 4,
|
||||
SurfaceFormat::A8R8G8B8_UINT32);
|
||||
}
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
|
||||
@@ -322,10 +322,6 @@ ImageExtraction ImageExtractionResult(dom::HTMLCanvasElement* aCanvasElement,
|
||||
}
|
||||
|
||||
if (ownerDoc->ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
if (GetCanvasExtractDataPermission(aPrincipal) ==
|
||||
nsIPermissionManager::ALLOW_ACTION) {
|
||||
return ImageExtraction::Unrestricted;
|
||||
}
|
||||
return ImageExtraction::Randomize;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,10 +59,16 @@ bool HasDrawWindowPrivilege(JSContext* aCx, JSObject* aObj);
|
||||
// Check if the context has permission to use OffscreenCanvas.
|
||||
bool IsOffscreenCanvasEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
// Check if the principal has "canvas" permission.
|
||||
uint32_t GetCanvasExtractDataPermission(nsIPrincipal& aPrincipal);
|
||||
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
bool IsImageExtractionAllowed(dom::Document* aDocument, JSContext* aCx,
|
||||
nsIPrincipal& aPrincipal);
|
||||
|
||||
bool IsImageExtractionAllowed(dom::OffscreenCanvas* aOffscreenCanvas,
|
||||
JSContext* aCx, nsIPrincipal& aPrincipal);
|
||||
|
||||
uint32_t GetCanvasExtractDataPermission(nsIPrincipal& aPrincipal);
|
||||
|
||||
enum class ImageExtraction {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "HostWebGLContext.h"
|
||||
#include "js/PropertyAndElement.h" // JS_DefineElement
|
||||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "mozilla/dom/CanvasUtils.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "mozilla/StaticPrefs_webgl.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "TexUnpackBlob.h"
|
||||
#include "WebGLFormats.h"
|
||||
#include "WebGLMethodDispatcher.h"
|
||||
@@ -1344,7 +1346,8 @@ UniquePtr<uint8_t[]> ClientWebGLContext::GetImageBuffer(
|
||||
|
||||
if (ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
return gfxUtils::GetImageBufferWithRandomNoise(
|
||||
dataSurface, premultAlpha, GetCookieJarSettings(), out_format);
|
||||
dataSurface, premultAlpha, GetCookieJarSettings(), PrincipalOrNull(),
|
||||
out_format);
|
||||
}
|
||||
|
||||
return gfxUtils::GetImageBuffer(dataSurface, premultAlpha, out_format);
|
||||
@@ -1365,7 +1368,7 @@ ClientWebGLContext::GetInputStream(const char* mimeType,
|
||||
if (ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
return gfxUtils::GetInputStreamWithRandomNoise(
|
||||
dataSurface, premultAlpha, mimeType, encoderOptions,
|
||||
GetCookieJarSettings(), out_stream);
|
||||
GetCookieJarSettings(), PrincipalOrNull(), out_stream);
|
||||
}
|
||||
|
||||
return gfxUtils::GetInputStream(dataSurface, premultAlpha, mimeType,
|
||||
|
||||
@@ -195,8 +195,8 @@ mozilla::UniquePtr<uint8_t[]> ImageBitmapRenderingContext::GetImageBuffer(
|
||||
|
||||
if (ret && ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
nsRFPService::RandomizePixels(
|
||||
GetCookieJarSettings(), ret.get(), data->GetSize().width,
|
||||
data->GetSize().height,
|
||||
GetCookieJarSettings(), PrincipalOrNull(), ret.get(),
|
||||
data->GetSize().width, data->GetSize().height,
|
||||
data->GetSize().width * data->GetSize().height * 4,
|
||||
gfx::SurfaceFormat::A8R8G8B8_UINT32);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ImageBitmap.h"
|
||||
#include "ImageBitmapRenderingContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "WebGLChild.h"
|
||||
|
||||
@@ -503,8 +504,11 @@ already_AddRefed<Promise> OffscreenCanvas::ConvertToBlob(
|
||||
|
||||
RefPtr<EncodeCompleteCallback> callback =
|
||||
CreateEncodeCompleteCallback(promise);
|
||||
bool usePlaceholder =
|
||||
ShouldResistFingerprinting(RFPTarget::CanvasImageExtractionPrompt);
|
||||
|
||||
bool usePlaceholder = mCurrentContext && mCurrentContext->PrincipalOrNull() &&
|
||||
!CanvasUtils::IsImageExtractionAllowed(
|
||||
this, nsContentUtils::GetCurrentJSContext(),
|
||||
*mCurrentContext->PrincipalOrNull());
|
||||
CanvasRenderingContextHelper::ToBlob(callback, type, encodeOptions,
|
||||
/* aUsingCustomOptions */ false,
|
||||
usePlaceholder, aRv);
|
||||
@@ -545,8 +549,10 @@ already_AddRefed<Promise> OffscreenCanvas::ToBlob(JSContext* aCx,
|
||||
|
||||
RefPtr<EncodeCompleteCallback> callback =
|
||||
CreateEncodeCompleteCallback(promise);
|
||||
bool usePlaceholder =
|
||||
ShouldResistFingerprinting(RFPTarget::CanvasImageExtractionPrompt);
|
||||
bool usePlaceholder = mCurrentContext && mCurrentContext->PrincipalOrNull() &&
|
||||
!CanvasUtils::IsImageExtractionAllowed(
|
||||
this, nsContentUtils::GetCurrentJSContext(),
|
||||
*mCurrentContext->PrincipalOrNull());
|
||||
CanvasRenderingContextHelper::ToBlob(aCx, callback, aType, aParams,
|
||||
usePlaceholder, aRv);
|
||||
|
||||
|
||||
@@ -577,9 +577,21 @@ UniquePtr<uint8_t[]> OffscreenCanvasDisplayHelper::GetImageBuffer(
|
||||
}
|
||||
|
||||
if (resistFingerprinting) {
|
||||
nsIPrincipal* principal;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mCanvasElement) {
|
||||
principal = mCanvasElement->NodePrincipal();
|
||||
}
|
||||
if (mOffscreenCanvas) {
|
||||
principal = mOffscreenCanvas->GetParentObject()
|
||||
? mOffscreenCanvas->GetParentObject()->PrincipalOrNull()
|
||||
: nullptr;
|
||||
}
|
||||
}
|
||||
nsRFPService::RandomizePixels(
|
||||
cookieJarSettings, imageBuffer.get(), dataSurface->GetSize().width,
|
||||
dataSurface->GetSize().height,
|
||||
cookieJarSettings, principal, imageBuffer.get(),
|
||||
dataSurface->GetSize().width, dataSurface->GetSize().height,
|
||||
dataSurface->GetSize().width * dataSurface->GetSize().height * 4,
|
||||
gfx::SurfaceFormat::A8R8G8B8_UINT32);
|
||||
}
|
||||
|
||||
@@ -326,9 +326,10 @@ mozilla::UniquePtr<uint8_t[]> CanvasContext::GetImageBuffer(
|
||||
*out_imageSize = dataSurface->GetSize();
|
||||
|
||||
if (ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
gfxUtils::GetImageBufferWithRandomNoise(
|
||||
dataSurface,
|
||||
/* aIsAlphaPremultiplied */ true, GetCookieJarSettings(), &*out_format);
|
||||
gfxUtils::GetImageBufferWithRandomNoise(dataSurface,
|
||||
/* aIsAlphaPremultiplied */ true,
|
||||
GetCookieJarSettings(),
|
||||
PrincipalOrNull(), &*out_format);
|
||||
}
|
||||
|
||||
return gfxUtils::GetImageBuffer(dataSurface, /* aIsAlphaPremultiplied */ true,
|
||||
@@ -347,9 +348,9 @@ NS_IMETHODIMP CanvasContext::GetInputStream(const char* aMimeType,
|
||||
RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
|
||||
|
||||
if (ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
|
||||
gfxUtils::GetInputStreamWithRandomNoise(
|
||||
return gfxUtils::GetInputStreamWithRandomNoise(
|
||||
dataSurface, /* aIsAlphaPremultiplied */ true, aMimeType,
|
||||
aEncoderOptions, GetCookieJarSettings(), aStream);
|
||||
aEncoderOptions, GetCookieJarSettings(), PrincipalOrNull(), aStream);
|
||||
}
|
||||
|
||||
return gfxUtils::GetInputStream(dataSurface, /* aIsAlphaPremultiplied */ true,
|
||||
|
||||
@@ -1613,13 +1613,14 @@ UniquePtr<uint8_t[]> gfxUtils::GetImageBuffer(gfx::DataSourceSurface* aSurface,
|
||||
/* static */
|
||||
UniquePtr<uint8_t[]> gfxUtils::GetImageBufferWithRandomNoise(
|
||||
gfx::DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
|
||||
nsICookieJarSettings* aCookieJarSettings, int32_t* outFormat) {
|
||||
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal,
|
||||
int32_t* outFormat) {
|
||||
UniquePtr<uint8_t[]> imageBuffer =
|
||||
GetImageBuffer(aSurface, aIsAlphaPremultiplied, outFormat);
|
||||
|
||||
nsRFPService::RandomizePixels(
|
||||
aCookieJarSettings, imageBuffer.get(), aSurface->GetSize().width,
|
||||
aSurface->GetSize().height,
|
||||
aCookieJarSettings, aPrincipal, imageBuffer.get(),
|
||||
aSurface->GetSize().width, aSurface->GetSize().height,
|
||||
aSurface->GetSize().width * aSurface->GetSize().height * 4,
|
||||
SurfaceFormat::A8R8G8B8_UINT32);
|
||||
|
||||
@@ -1651,7 +1652,8 @@ nsresult gfxUtils::GetInputStream(gfx::DataSourceSurface* aSurface,
|
||||
nsresult gfxUtils::GetInputStreamWithRandomNoise(
|
||||
gfx::DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
|
||||
const char* aMimeType, const nsAString& aEncoderOptions,
|
||||
nsICookieJarSettings* aCookieJarSettings, nsIInputStream** outStream) {
|
||||
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal,
|
||||
nsIInputStream** outStream) {
|
||||
nsCString enccid("@mozilla.org/image/encoder;2?type=");
|
||||
enccid += aMimeType;
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
|
||||
@@ -1667,8 +1669,8 @@ nsresult gfxUtils::GetInputStreamWithRandomNoise(
|
||||
}
|
||||
|
||||
nsRFPService::RandomizePixels(
|
||||
aCookieJarSettings, imageBuffer.get(), aSurface->GetSize().width,
|
||||
aSurface->GetSize().height,
|
||||
aCookieJarSettings, aPrincipal, imageBuffer.get(),
|
||||
aSurface->GetSize().width, aSurface->GetSize().height,
|
||||
aSurface->GetSize().width * aSurface->GetSize().height * 4,
|
||||
SurfaceFormat::A8R8G8B8_UINT32);
|
||||
|
||||
|
||||
@@ -400,7 +400,8 @@ class gfxUtils {
|
||||
|
||||
static mozilla::UniquePtr<uint8_t[]> GetImageBufferWithRandomNoise(
|
||||
DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
|
||||
nsICookieJarSettings* aCookieJarSettings, int32_t* outFormat);
|
||||
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal,
|
||||
int32_t* outFormat);
|
||||
|
||||
static nsresult GetInputStream(DataSourceSurface* aSurface,
|
||||
bool aIsAlphaPremultiplied,
|
||||
@@ -411,7 +412,8 @@ class gfxUtils {
|
||||
static nsresult GetInputStreamWithRandomNoise(
|
||||
DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
|
||||
const char* aMimeType, const nsAString& aEncoderOptions,
|
||||
nsICookieJarSettings* aCookieJarSettings, nsIInputStream** outStream);
|
||||
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal,
|
||||
nsIInputStream** outStream);
|
||||
|
||||
static void RemoveShaderCacheFromDiskIfNecessary();
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "mozilla/dom/MediaDeviceInfoBinding.h"
|
||||
#include "mozilla/fallible.h"
|
||||
#include "mozilla/XorShift128PlusRNG.h"
|
||||
#include "mozilla/dom/CanvasUtils.h"
|
||||
|
||||
#include "nsAboutProtocolUtils.h"
|
||||
#include "nsBaseHashtable.h"
|
||||
@@ -1708,8 +1709,9 @@ nsresult nsRFPService::GenerateCanvasKeyFromImageData(
|
||||
|
||||
// static
|
||||
nsresult nsRFPService::RandomizePixels(nsICookieJarSettings* aCookieJarSettings,
|
||||
uint8_t* aData, uint32_t aWidth,
|
||||
uint32_t aHeight, uint32_t aSize,
|
||||
nsIPrincipal* aPrincipal, uint8_t* aData,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
uint32_t aSize,
|
||||
gfx::SurfaceFormat aSurfaceFormat) {
|
||||
NS_ENSURE_ARG_POINTER(aData);
|
||||
|
||||
@@ -1721,6 +1723,11 @@ nsresult nsRFPService::RandomizePixels(nsICookieJarSettings* aCookieJarSettings,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aPrincipal && CanvasUtils::GetCanvasExtractDataPermission(*aPrincipal) ==
|
||||
nsIPermissionManager::ALLOW_ACTION) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Don't randomize if all pixels are uniform.
|
||||
static constexpr size_t bytesPerPixel = 4;
|
||||
MOZ_ASSERT(aSize == aWidth * aHeight * bytesPerPixel,
|
||||
|
||||
@@ -342,8 +342,9 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
|
||||
// The method to add random noises to the image data based on the random key
|
||||
// of the given cookieJarSettings.
|
||||
static nsresult RandomizePixels(nsICookieJarSettings* aCookieJarSettings,
|
||||
uint8_t* aData, uint32_t aWidth,
|
||||
uint32_t aHeight, uint32_t aSize,
|
||||
nsIPrincipal* aPrincipal, uint8_t* aData,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
uint32_t aSize,
|
||||
mozilla::gfx::SurfaceFormat aSurfaceFormat);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user