Backed out changeset 8a48a3a488ab (bug 1621433) for hazard failures on CanvasRenderingContext2D.cpp CLOSED TREE

This commit is contained in:
Csoregi Natalia 2020-05-08 09:39:25 +03:00
Родитель 3333c41522
Коммит 4bb1a50963
7 изменённых файлов: 52 добавлений и 224 удалений

Просмотреть файл

@ -3,9 +3,6 @@
* required for canvas data extraction.
* This tests whether the site permission prompt for canvas data extraction
* works properly.
* When "privacy.resistFingerprinting.randomDataOnCanvasExtract" is true,
* canvas data extraction results in random data, and when it is false, canvas
* data extraction results in all-white data.
*/
"use strict";
@ -51,12 +48,6 @@ function initTab() {
let placeholder = drawCanvas("white");
contentWindow.kPlaceholderData = placeholder.toDataURL();
let canvas = drawCanvas("cyan", "canvas-id-canvas");
contentWindow.kPlacedData = canvas.toDataURL();
is(
canvas.toDataURL(),
contentWindow.kPlacedData,
"privacy.resistFingerprinting = false, canvas data == placed data"
);
isnot(
canvas.toDataURL(),
contentWindow.kPlaceholderData,
@ -64,17 +55,10 @@ function initTab() {
);
}
function enableResistFingerprinting(
randomDataOnCanvasExtract,
autoDeclineNoInput
) {
function enableResistFingerprinting(autoDeclineNoInput) {
return SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
[
"privacy.resistFingerprinting.randomDataOnCanvasExtract",
randomDataOnCanvasExtract,
],
[
"privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts",
autoDeclineNoInput,
@ -91,49 +75,28 @@ function promisePopupHidden() {
return BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
}
function extractCanvasData(randomDataOnCanvasExtract, grantPermission) {
function extractCanvasData(grantPermission) {
let contentWindow = content.wrappedJSObject;
let canvas = contentWindow.document.getElementById("canvas-id-canvas");
let canvasData = canvas.toDataURL();
if (grantPermission) {
isnot(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true, permission granted, canvas data != placeholderdata"
);
} else if (grantPermission === false) {
is(
canvasData,
contentWindow.kPlacedData,
"privacy.resistFingerprinting = true, permission granted, canvas data == placed data"
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true, permission denied, canvas data == placeholderdata"
);
if (!randomDataOnCanvasExtract) {
isnot(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission granted, canvas data != placeholderdata"
);
}
} else if (grantPermission === false) {
isnot(
canvasData,
contentWindow.kPlacedData,
"privacy.resistFingerprinting = true, permission denied, canvas data != placed data"
);
if (!randomDataOnCanvasExtract) {
is(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission denied, canvas data == placeholderdata"
);
}
} else {
isnot(
is(
canvasData,
contentWindow.kPlacedData,
"privacy.resistFingerprinting = true, requesting permission, canvas data != placed data"
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true, requesting permission, canvas data == placeholderdata"
);
if (!randomDataOnCanvasExtract) {
is(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, requesting permission, canvas data == placeholderdata"
);
}
}
}
@ -155,19 +118,11 @@ function testPermission() {
return Services.perms.testPermissionFromPrincipal(kPrincipal, kPermission);
}
async function withNewTabNoInput(
randomDataOnCanvasExtract,
grantPermission,
browser
) {
async function withNewTabNoInput(grantPermission, browser) {
await SpecialPowers.spawn(browser, [], initTab);
await enableResistFingerprinting(randomDataOnCanvasExtract, false);
await enableResistFingerprinting(false);
let popupShown = promisePopupShown();
await SpecialPowers.spawn(
browser,
[randomDataOnCanvasExtract],
extractCanvasData
);
await SpecialPowers.spawn(browser, [], extractCanvasData);
await popupShown;
let popupHidden = promisePopupHidden();
if (grantPermission) {
@ -179,34 +134,28 @@ async function withNewTabNoInput(
await popupHidden;
is(testPermission(), Services.perms.DENY_ACTION, "permission denied");
}
await SpecialPowers.spawn(
browser,
[randomDataOnCanvasExtract, grantPermission],
extractCanvasData
);
await SpecialPowers.spawn(browser, [grantPermission], extractCanvasData);
await SpecialPowers.popPrefEnv();
}
async function doTestNoInput(randomDataOnCanvasExtract, grantPermission) {
async function doTestNoInput(grantPermission) {
await BrowserTestUtils.withNewTab(
kUrl,
withNewTabNoInput.bind(null, randomDataOnCanvasExtract, grantPermission)
withNewTabNoInput.bind(null, grantPermission)
);
Services.perms.removeFromPrincipal(kPrincipal, kPermission);
}
// With auto-declining disabled (not the default)
// Tests clicking "Don't Allow" button of the permission prompt.
add_task(doTestNoInput.bind(null, true, false));
add_task(doTestNoInput.bind(null, false, false));
add_task(doTestNoInput.bind(null, false));
// Tests clicking "Allow" button of the permission prompt.
add_task(doTestNoInput.bind(null, true, true));
add_task(doTestNoInput.bind(null, false, true));
add_task(doTestNoInput.bind(null, true));
async function withNewTabAutoBlockNoInput(randomDataOnCanvasExtract, browser) {
async function withNewTabAutoBlockNoInput(browser) {
await SpecialPowers.spawn(browser, [], initTab);
await enableResistFingerprinting(randomDataOnCanvasExtract, true);
await enableResistFingerprinting(true);
let noShowHandler = () => {
ok(false, "The popup notification should not show in this case.");
@ -220,11 +169,7 @@ async function withNewTabAutoBlockNoInput(randomDataOnCanvasExtract, browser) {
);
// Try to extract canvas data without user inputs.
await SpecialPowers.spawn(
browser,
[randomDataOnCanvasExtract],
extractCanvasData
);
await SpecialPowers.spawn(browser, [], extractCanvasData);
await promisePopupObserver;
info("There should be no popup shown on the panel.");
@ -245,72 +190,38 @@ async function withNewTabAutoBlockNoInput(randomDataOnCanvasExtract, browser) {
await SpecialPowers.popPrefEnv();
}
async function doTestAutoBlockNoInput(randomDataOnCanvasExtract) {
await BrowserTestUtils.withNewTab(
kUrl,
withNewTabAutoBlockNoInput.bind(null, randomDataOnCanvasExtract)
);
}
add_task(async function doTestAutoBlockNoInput() {
await BrowserTestUtils.withNewTab(kUrl, withNewTabAutoBlockNoInput);
});
add_task(doTestAutoBlockNoInput.bind(null, true));
add_task(doTestAutoBlockNoInput.bind(null, false));
function extractCanvasDataUserInput(
randomDataOnCanvasExtract,
grantPermission
) {
function extractCanvasDataUserInput(grantPermission) {
let contentWindow = content.wrappedJSObject;
let canvas = contentWindow.document.getElementById("canvas-id-canvas");
let canvasData = canvas.toDataURL();
if (grantPermission) {
isnot(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true, permission granted, canvas data != placeholderdata"
);
} else if (grantPermission === false) {
is(
canvasData,
contentWindow.kPlacedData,
"privacy.resistFingerprinting = true, permission granted, canvas data == placed data"
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true, permission denied, canvas data == placeholderdata"
);
if (!randomDataOnCanvasExtract) {
isnot(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission granted, canvas data != placeholderdata"
);
}
} else if (grantPermission === false) {
isnot(
canvasData,
contentWindow.kPlacedData,
"privacy.resistFingerprinting = true, permission denied, canvas data != placed data"
);
if (!randomDataOnCanvasExtract) {
is(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission denied, canvas data == placeholderdata"
);
}
} else {
isnot(
is(
canvasData,
contentWindow.kPlacedData,
"privacy.resistFingerprinting = true, requesting permission, canvas data != placed data"
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true, requesting permission, canvas data == placeholderdata"
);
if (!randomDataOnCanvasExtract) {
is(
canvasData,
contentWindow.kPlaceholderData,
"privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, requesting permission, canvas data == placeholderdata"
);
}
}
}
async function withNewTabInput(
randomDataOnCanvasExtract,
grantPermission,
browser
) {
async function withNewTabInput(grantPermission, browser) {
await SpecialPowers.spawn(browser, [], initTab);
await enableResistFingerprinting(randomDataOnCanvasExtract, true);
await enableResistFingerprinting(true);
let popupShown = promisePopupShown();
await SpecialPowers.spawn(browser, [], function(host) {
E10SUtils.wrapHandlingUserInput(content, true, function() {
@ -331,29 +242,23 @@ async function withNewTabInput(
}
await SpecialPowers.spawn(
browser,
[randomDataOnCanvasExtract, grantPermission],
[grantPermission],
extractCanvasDataUserInput
);
await SpecialPowers.popPrefEnv();
}
async function doTestInput(
randomDataOnCanvasExtract,
grantPermission,
autoDeclineNoInput
) {
async function doTestInput(grantPermission, autoDeclineNoInput) {
await BrowserTestUtils.withNewTab(
kUrl,
withNewTabInput.bind(null, randomDataOnCanvasExtract, grantPermission)
withNewTabInput.bind(null, grantPermission)
);
Services.perms.removeFromPrincipal(kPrincipal, kPermission);
}
// With auto-declining enabled (the default)
// Tests clicking "Don't Allow" button of the permission prompt.
add_task(doTestInput.bind(null, true, false));
add_task(doTestInput.bind(null, false, false));
add_task(doTestInput.bind(null, false));
// Tests clicking "Allow" button of the permission prompt.
add_task(doTestInput.bind(null, true, true));
add_task(doTestInput.bind(null, false, true));
add_task(doTestInput.bind(null, true));

Просмотреть файл

@ -6,7 +6,6 @@
#include "ImageEncoder.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/GeneratePlaceholderCanvasData.h"
#include "mozilla/dom/MemoryBlobImpl.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/gfx/2D.h"
@ -384,9 +383,8 @@ nsresult ImageEncoder::ExtractDataInternal(
return NS_ERROR_INVALID_ARG;
}
if (aUsePlaceholder) {
auto size = 4 * aSize.width * aSize.height;
auto* data = map.mData;
GeneratePlaceholderCanvasData(size, &data);
// If placeholder data was requested, return all-white, opaque image data.
memset(map.mData, 0xFF, 4 * aSize.width * aSize.height);
}
rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4,
aSize.width, aSize.height, aSize.width * 4,

Просмотреть файл

@ -17,7 +17,6 @@
#include "mozilla/PresShellInlines.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/GeneratePlaceholderCanvasData.h"
#include "SVGObserverUtils.h"
#include "nsPresContext.h"
@ -5105,8 +5104,9 @@ nsresult CanvasRenderingContext2D::GetImageDataArray(
uint8_t* src =
rawData.mData + srcReadRect.y * srcStride + srcReadRect.x * 4;
// Return all-white, opaque pixel data if no permission.
if (usePlaceholder) {
GeneratePlaceholderCanvasData(len.value(), &data);
memset(data, 0xFF, len.value());
break;
}

Просмотреть файл

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GeneratePlaceholderCanvasData_h
#define mozilla_dom_GeneratePlaceholderCanvasData_h
#include "nsCOMPtr.h"
#include "nsIRandomGenerator.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/StaticPrefs_privacy.h"
#define RANDOM_BYTES_TO_SAMPLE 32
namespace mozilla {
namespace dom {
/**
* When privacy.resistFingerprinting.randomDataOnCanvasExtract is true, tries
* to generate random canvas data by sampling RANDOM_BYTES_TO_SAMPLE bytes and
* then repeating those bytes many times to fill the buffer. If this fails or
* if privacy.resistFingerprinting.randomDataOnCanvasExtract is false, returns
* all-white, opaque pixel data.
*
* @param[in] size Size of output buffer
* @param[out] buffer Output buffer
*/
inline void GeneratePlaceholderCanvasData(uint32_t size, uint8_t** buffer) {
if (!StaticPrefs::privacy_resistFingerprinting_randomDataOnCanvasExtract()) {
memset(*buffer, 0xFF, size);
return;
}
nsresult rv;
nsCOMPtr<nsIRandomGenerator> rg =
do_GetService("@mozilla.org/security/random-generator;1", &rv);
if (NS_FAILED(rv)) {
memset(*buffer, 0xFF, size);
} else {
uint8_t* tmp_buffer;
rv = rg->GenerateRandomBytes(RANDOM_BYTES_TO_SAMPLE, &tmp_buffer);
if (NS_FAILED(rv)) {
memset(*buffer, 0xFF, size);
} else {
auto remaining_to_fill = size;
auto index = 0;
while (remaining_to_fill > 0) {
auto bytes_to_write = (remaining_to_fill > RANDOM_BYTES_TO_SAMPLE)
? RANDOM_BYTES_TO_SAMPLE
: remaining_to_fill;
memcpy((*buffer) + (index * RANDOM_BYTES_TO_SAMPLE), tmp_buffer,
bytes_to_write);
remaining_to_fill -= bytes_to_write;
index++;
}
free(tmp_buffer);
}
}
}
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_GeneratePlaceholderCanvasData_h

Просмотреть файл

@ -53,7 +53,6 @@ EXPORTS.mozilla.dom += [
'CanvasRenderingContext2D.h',
'CanvasRenderingContextHelper.h',
'CanvasUtils.h',
'GeneratePlaceholderCanvasData.h',
'ImageBitmap.h',
'ImageBitmapRenderingContext.h',
'ImageBitmapSource.h',

Просмотреть файл

@ -18,7 +18,6 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/CanvasCaptureMediaStream.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/GeneratePlaceholderCanvasData.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/HTMLCanvasElementBinding.h"
@ -101,9 +100,8 @@ class RequestedFrameRefreshObserver : public nsARefreshObserver {
MOZ_ASSERT(data->GetFormat() == copy->GetFormat());
if (aReturnPlaceholderData) {
auto size = write.GetStride() * copy->GetSize().height;
auto* data = write.GetData();
GeneratePlaceholderCanvasData(size, &data);
// If returning placeholder data, fill the frame copy with white pixels.
memset(write.GetData(), 0xFF, write.GetStride() * copy->GetSize().height);
} else {
memcpy(write.GetData(), read.GetData(),
write.GetStride() * copy->GetSize().height);

Просмотреть файл

@ -8155,13 +8155,6 @@
value: true
mirror: always
# Whether canvas extraction should result in random data. If false, canvas
# extraction results in all-white, opaque pixel data.
- name: privacy.resistFingerprinting.randomDataOnCanvasExtract
type: bool
value: true
mirror: always
# The log level for browser console messages logged in RFPHelper.jsm. Change to
# 'All' and restart to see the messages.
- name: privacy.resistFingerprinting.jsmloglevel