Commit 0eea57f8 authored by junov's avatar junov Committed by Commit bot

Make OffscreenCanvas commit() propagate the origin-clean flag.

This change block user code from accessing cross-origin image data
from a placeholder canvas. The placeholder code was modified to
use StaticBitmapImage instead of Image to gain access to the
originClean() method without downcasting.

BUG=673348

Review-Url: https://codereview.chromium.org/2566313002
Cr-Commit-Position: refs/heads/master@{#438172}
parent ea1eb315
<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script>
async_test(t => {
var image = new Image();
// Notice that we don't set the image.crossOrigin property.
image.src = "http://localhost:8000/security/resources/abe-allow-star.php";
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 10;
var offscreen = canvas.transferControlToOffscreen();
var ctx = offscreen.getContext('2d');
ctx.drawImage(image, 0, 0);
ctx.commit();
t.step(function() {
canvas.toDataURL(); // Succeeds by not throwing
});
setTimeout(function() { // sync barrier for commit() propagation
t.step(function() {
assert_throws("SecurityError", function() {
canvas.toDataURL();
}, "Check toDataURL blocked.");
});
ctx.commit(); // Second frame does not reset origin-clean flag.
setTimeout(function() { // sync barrier for commit() propagation
t.step(function() {
assert_throws("SecurityError", function() {
canvas.toDataURL();
});
});
t.done();
}, 0);
}, 0);
}
}, "Verify that the placeholder <canvas> associated with an OffscreenCanvas tainted with cross-origin content cannot be read once commit has propagated.");
</script>
...@@ -642,6 +642,7 @@ ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer, ...@@ -642,6 +642,7 @@ ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer,
if (hasImageBuffer()) { if (hasImageBuffer()) {
snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration, reason); snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration, reason);
} else if (placeholderFrame()) { } else if (placeholderFrame()) {
DCHECK(placeholderFrame()->originClean());
// TODO(ccameron): Canvas should produce sRGB images. // TODO(ccameron): Canvas should produce sRGB images.
// https://crbug.com/672299 // https://crbug.com/672299
snapshot = placeholderFrame()->imageForCurrentFrame( snapshot = placeholderFrame()->imageForCurrentFrame(
...@@ -783,6 +784,8 @@ bool HTMLCanvasElement::originClean() const { ...@@ -783,6 +784,8 @@ bool HTMLCanvasElement::originClean() const {
if (document().settings() && if (document().settings() &&
document().settings()->disableReadingFromCanvas()) document().settings()->disableReadingFromCanvas())
return false; return false;
if (placeholderFrame())
return placeholderFrame()->originClean();
return m_originClean; return m_originClean;
} }
......
...@@ -60,7 +60,7 @@ void OffscreenCanvasRenderingContext2D::commit(ScriptState* scriptState, ...@@ -60,7 +60,7 @@ void OffscreenCanvasRenderingContext2D::commit(ScriptState* scriptState,
return; return;
} }
double commitStartTime = WTF::monotonicallyIncreasingTime(); double commitStartTime = WTF::monotonicallyIncreasingTime();
RefPtr<StaticBitmapImage> image = this->transferToStaticBitmapImage(); RefPtr<StaticBitmapImage> image = transferToStaticBitmapImage();
getOffscreenCanvas()->getOrCreateFrameDispatcher()->dispatchFrame( getOffscreenCanvas()->getOrCreateFrameDispatcher()->dispatchFrame(
std::move(image), commitStartTime); std::move(image), commitStartTime);
} }
......
...@@ -164,7 +164,7 @@ namespace { ...@@ -164,7 +164,7 @@ namespace {
void updatePlaceholderImage(WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher, void updatePlaceholderImage(WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher,
std::unique_ptr<WebTaskRunner> taskRunner, std::unique_ptr<WebTaskRunner> taskRunner,
int placeholderCanvasId, int placeholderCanvasId,
RefPtr<blink::Image> image, RefPtr<blink::StaticBitmapImage> image,
unsigned resourceId) { unsigned resourceId) {
DCHECK(isMainThread()); DCHECK(isMainThread());
OffscreenCanvasPlaceholder* placeholderCanvas = OffscreenCanvasPlaceholder* placeholderCanvas =
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include "platform/CrossThreadFunctional.h" #include "platform/CrossThreadFunctional.h"
#include "platform/WebTaskRunner.h" #include "platform/WebTaskRunner.h"
#include "platform/graphics/Image.h"
#include "platform/graphics/OffscreenCanvasFrameDispatcher.h" #include "platform/graphics/OffscreenCanvasFrameDispatcher.h"
#include "platform/graphics/StaticBitmapImage.h"
#include "wtf/HashMap.h" #include "wtf/HashMap.h"
namespace { namespace {
...@@ -62,7 +62,7 @@ void OffscreenCanvasPlaceholder::unregisterPlaceholder() { ...@@ -62,7 +62,7 @@ void OffscreenCanvasPlaceholder::unregisterPlaceholder() {
} }
void OffscreenCanvasPlaceholder::setPlaceholderFrame( void OffscreenCanvasPlaceholder::setPlaceholderFrame(
RefPtr<Image> newFrame, RefPtr<StaticBitmapImage> newFrame,
WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher, WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher,
std::unique_ptr<WebTaskRunner> taskRunner, std::unique_ptr<WebTaskRunner> taskRunner,
unsigned resourceId) { unsigned resourceId) {
......
...@@ -12,15 +12,15 @@ ...@@ -12,15 +12,15 @@
namespace blink { namespace blink {
class Image;
class OffscreenCanvasFrameDispatcher; class OffscreenCanvasFrameDispatcher;
class StaticBitmapImage;
class WebTaskRunner; class WebTaskRunner;
class PLATFORM_EXPORT OffscreenCanvasPlaceholder { class PLATFORM_EXPORT OffscreenCanvasPlaceholder {
public: public:
~OffscreenCanvasPlaceholder(); ~OffscreenCanvasPlaceholder();
void setPlaceholderFrame(RefPtr<Image>, void setPlaceholderFrame(RefPtr<StaticBitmapImage>,
WeakPtr<OffscreenCanvasFrameDispatcher>, WeakPtr<OffscreenCanvasFrameDispatcher>,
std::unique_ptr<WebTaskRunner>, std::unique_ptr<WebTaskRunner>,
unsigned resourceId); unsigned resourceId);
...@@ -30,14 +30,16 @@ class PLATFORM_EXPORT OffscreenCanvasPlaceholder { ...@@ -30,14 +30,16 @@ class PLATFORM_EXPORT OffscreenCanvasPlaceholder {
void registerPlaceholder(unsigned placeholderId); void registerPlaceholder(unsigned placeholderId);
void unregisterPlaceholder(); void unregisterPlaceholder();
const RefPtr<Image>& placeholderFrame() const { return m_placeholderFrame; } const RefPtr<StaticBitmapImage>& placeholderFrame() const {
return m_placeholderFrame;
}
private: private:
bool isPlaceholderRegistered() const { bool isPlaceholderRegistered() const {
return m_placeholderId != kNoPlaceholderId; return m_placeholderId != kNoPlaceholderId;
} }
RefPtr<Image> m_placeholderFrame; RefPtr<StaticBitmapImage> m_placeholderFrame;
WeakPtr<OffscreenCanvasFrameDispatcher> m_frameDispatcher; WeakPtr<OffscreenCanvasFrameDispatcher> m_frameDispatcher;
std::unique_ptr<WebTaskRunner> m_frameDispatcherTaskRunner; std::unique_ptr<WebTaskRunner> m_frameDispatcherTaskRunner;
unsigned m_placeholderFrameResourceId = 0; unsigned m_placeholderFrameResourceId = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment