From 8d29182cf055a03b37475f65a70b6abf321f96d9 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 27 Sep 2017 11:06:31 +0200 Subject: Add canvas data poisoning option. Tag #61. --- dom/canvas/CanvasRenderingContext2D.cpp | 73 ++++++++++++++++++++++++++------- modules/libpref/init/all.js | 4 ++ 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 2ed39627e..b0a430fe4 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -68,6 +68,8 @@ #include "CanvasImageCache.h" #include +#include +#include #include "jsapi.h" #include "jsfriendapi.h" @@ -2083,6 +2085,18 @@ CanvasRenderingContext2D::GetInputStream(const char* aMimeType, return NS_ERROR_FAILURE; } + bool PoisonData = Preferences::GetBool("canvas.poisondata",false); + if (PoisonData) { + srand(time(NULL)); + // Image buffer is always a packed BGRA array (BGRX -> BGR[FF]) + // so always 4-byte pixels. + // GetImageBuffer => SurfaceToPackedBGRA [=> ConvertBGRXToBGRA] + for (int32_t j = 0; j < mWidth * mHeight * 4; ++j) { + if (imageBuffer[j] !=0 && imageBuffer[j] != 255) + imageBuffer[j] += rand() % 3 - 1; + } + } + return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer.get(), format, encoder, aEncoderOptions, aStream); @@ -5698,6 +5712,14 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx, return imageData.forget(); } +inline uint8_t PoisonValue(uint8_t v) +{ + if (v==0 || v==255) + return v; //don't fuzz edges to prevent overflow/underflow + + return v + rand() %3 -1; +} + nsresult CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, int32_t aX, @@ -5712,6 +5734,10 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, MOZ_ASSERT(aWidth && aHeight); + bool PoisonData = Preferences::GetBool("canvas.poisondata",false); + if (PoisonData) + srand(time(NULL)); + CheckedInt len = CheckedInt(aWidth) * aHeight * 4; if (!len.isValid()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; @@ -5784,21 +5810,31 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4; + uint8_t a,r,g,b; + if (mOpaque) { for (int32_t j = 0; j < dstWriteRect.height; ++j) { for (int32_t i = 0; i < dstWriteRect.width; ++i) { // XXX Is there some useful swizzle MMX we can use here? #if MOZ_LITTLE_ENDIAN - uint8_t b = *src++; - uint8_t g = *src++; - uint8_t r = *src++; + b = *src++; + g = *src++; + r = *src++; src++; #else src++; - uint8_t r = *src++; - uint8_t g = *src++; - uint8_t b = *src++; + r = *src++; + g = *src++; + b = *src++; #endif + + // Poison data for trackers if enabled + if (PoisonData) { + PoisonValue(r); + PoisonValue(g); + PoisonValue(b); + } + *dst++ = r; *dst++ = g; *dst++ = b; @@ -5812,16 +5848,25 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, for (int32_t i = 0; i < dstWriteRect.width; ++i) { // XXX Is there some useful swizzle MMX we can use here? #if MOZ_LITTLE_ENDIAN - uint8_t b = *src++; - uint8_t g = *src++; - uint8_t r = *src++; - uint8_t a = *src++; + b = *src++; + g = *src++; + r = *src++; + a = *src++; #else - uint8_t a = *src++; - uint8_t r = *src++; - uint8_t g = *src++; - uint8_t b = *src++; + a = *src++; + r = *src++; + g = *src++; + b = *src++; #endif + + // Poison data for trackers if enabled + if (PoisonData) { + PoisonValue(a); + PoisonValue(r); + PoisonValue(g); + PoisonValue(b); + } + // Convert to non-premultiplied color *dst++ = gfxUtils::sUnpremultiplyTable[a * 256 + r]; *dst++ = gfxUtils::sUnpremultiplyTable[a * 256 + g]; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 62aedead2..d51172f42 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4448,6 +4448,10 @@ pref("image.multithreaded_decoding.limit", -1); // cache. pref("canvas.image.cache.limit", 0); +// Allow track-fobics to deliberately poison canvas data for +// toDataURL() and getImageData() +pref("canvas.poisondata", false); + // WebGL prefs #ifdef ANDROID // Disable MSAA on mobile. -- cgit v1.2.3