Title: [195614] trunk
Revision
195614
Author
[email protected]
Date
2016-01-26 13:19:12 -0800 (Tue, 26 Jan 2016)

Log Message

Let SVG images not taint canvases except when containing foreignObjects
https://bugs.webkit.org/show_bug.cgi?id=119639

Patch by Philip Rogers <[email protected]> on 2016-01-26
Reviewed by Brent Fulgham.

Source/WebCore:

r153876 caused SVG images to not taint canvases but the patch allowed
for subimage resources. This can be a problem if a subimage (e.g., data
uri image) contains a foreignObject which can violate security (e.g.,
visited links).

This patch updates SVGImage::hasSingleSecurityOrigin to check if the
image contains any foreignObjects or images that themselves contain
foreignObjects. SVG images without foreignObjects are allowed to not
taint canvases.

Canvas patterns are problematic because an animated SVG image can switch
between tainting and not tainting the canvas. A FIXME has been added to
solve this, and in the meantime we cause SVG images to taint patterns.

Tests: svg/as-image/svg-canvas-pattern-with-link-tainted.html
       svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html
       svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html

* html/canvas/CanvasPattern.cpp:
(WebCore::CanvasPattern::CanvasPattern):
(WebCore::CanvasPattern::~CanvasPattern):
* svg/SVGFEImageElement.cpp:
(WebCore::SVGFEImageElement::~SVGFEImageElement):
(WebCore::SVGFEImageElement::hasSingleSecurityOrigin):
(WebCore::SVGFEImageElement::clearResourceReferences):
* svg/SVGFEImageElement.h:
* svg/SVGImageElement.cpp:
(WebCore::SVGImageElement::create):
(WebCore::SVGImageElement::hasSingleSecurityOrigin):
(WebCore::SVGImageElement::isSupportedAttribute):
* svg/SVGImageElement.h:
* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::hasSingleSecurityOrigin):

LayoutTests:

* svg/as-image/resources/svg-with-feimage-with-link.svg: Added.
* svg/as-image/resources/svg-with-image-with-link.svg: Added.
* svg/as-image/svg-canvas-pattern-with-link-tainted-expected.txt: Added.
* svg/as-image/svg-canvas-pattern-with-link-tainted.html: Added.
* svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted-expected.txt: Added.
* svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html: Added.
* svg/as-image/svg-canvas-svg-with-image-with-link-tainted-expected.txt: Added.
* svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (195613 => 195614)


--- trunk/LayoutTests/ChangeLog	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/LayoutTests/ChangeLog	2016-01-26 21:19:12 UTC (rev 195614)
@@ -1,3 +1,19 @@
+2016-01-26  Philip Rogers  <[email protected]>
+
+        Let SVG images not taint canvases except when containing foreignObjects
+        https://bugs.webkit.org/show_bug.cgi?id=119639
+
+        Reviewed by Brent Fulgham.
+
+        * svg/as-image/resources/svg-with-feimage-with-link.svg: Added.
+        * svg/as-image/resources/svg-with-image-with-link.svg: Added.
+        * svg/as-image/svg-canvas-pattern-with-link-tainted-expected.txt: Added.
+        * svg/as-image/svg-canvas-pattern-with-link-tainted.html: Added.
+        * svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted-expected.txt: Added.
+        * svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html: Added.
+        * svg/as-image/svg-canvas-svg-with-image-with-link-tainted-expected.txt: Added.
+        * svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html: Added.
+
 2016-01-26  Jer Noble  <[email protected]>
 
         Calling video.controls=true during a scrub operation cancels scrub.

Added: trunk/LayoutTests/svg/as-image/resources/svg-with-feimage-with-link.svg (0 => 195614)


--- trunk/LayoutTests/svg/as-image/resources/svg-with-feimage-with-link.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/resources/svg-with-feimage-with-link.svg	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
+    <defs>
+        <filter id="filter">
+            <!-- This data uri image contains a foreignObject and a link. -->
+            <feImage xlink:href="" />
+        </filter>
+    </defs>
+    <rect width="10" height="10" filter="url(#filter)"/>
+</svg>

Added: trunk/LayoutTests/svg/as-image/resources/svg-with-image-with-link.svg (0 => 195614)


--- trunk/LayoutTests/svg/as-image/resources/svg-with-image-with-link.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/resources/svg-with-image-with-link.svg	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
+    <!-- This data uri image contains a foreignObject and a link. -->
+    <image width="10" height="10" xlink:href=""
+    </image>
+</svg>

Added: trunk/LayoutTests/svg/as-image/svg-canvas-pattern-with-link-tainted-expected.txt (0 => 195614)


--- trunk/LayoutTests/svg/as-image/svg-canvas-pattern-with-link-tainted-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/svg-canvas-pattern-with-link-tainted-expected.txt	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,3 @@
+CONSOLE MESSAGE: line 1: Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
+PASS window.ctx.getImageData(0, 0, 1, 1) threw exception Error: SecurityError: DOM Exception 18.
+

Added: trunk/LayoutTests/svg/as-image/svg-canvas-pattern-with-link-tainted.html (0 => 195614)


--- trunk/LayoutTests/svg/as-image/svg-canvas-pattern-with-link-tainted.html	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/svg-canvas-pattern-with-link-tainted.html	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+</head>
+<body>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        var svg = new Image();
+        svg.src = ""
+
+        svg._onload_ = function() {
+            var canvas = document.createElement("canvas");
+            window.ctx = canvas.getContext("2d");
+
+            ctx.getImageData(0, 0, 1, 1);
+
+            // Wait for the data uri in the image to load.
+            setTimeout(function() {
+                ctx.fillStyle = ctx.createPattern(svg, 'repeat');
+                ctx.fillRect(0, 0, 200, 200);
+
+                shouldThrow("window.ctx.getImageData(0, 0, 1, 1)");
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, 50);
+        };
+    </script>
+</body>
+</html>

Added: trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted-expected.txt (0 => 195614)


--- trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted-expected.txt	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,3 @@
+CONSOLE MESSAGE: line 1: Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
+PASS window.ctx.getImageData(0, 0, 1, 1) threw exception Error: SecurityError: DOM Exception 18.
+

Added: trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html (0 => 195614)


--- trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+</head>
+<body>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        var svg = new Image();
+        svg.src = ""
+
+        svg._onload_ = function() {
+            var canvas = document.createElement("canvas");
+            window.ctx = canvas.getContext("2d");
+
+            ctx.getImageData(0, 0, 1, 1);
+
+            // Wait for the data uri in the image to load.
+            setTimeout(function() {
+                ctx.drawImage(svg, 0, 0);
+
+                shouldThrow("window.ctx.getImageData(0, 0, 1, 1)");
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, 50);
+        };
+    </script>
+</body>
+</html>

Added: trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-image-with-link-tainted-expected.txt (0 => 195614)


--- trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-image-with-link-tainted-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-image-with-link-tainted-expected.txt	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,3 @@
+CONSOLE MESSAGE: line 1: Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
+PASS window.ctx.getImageData(0, 0, 1, 1) threw exception Error: SecurityError: DOM Exception 18.
+

Added: trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html (0 => 195614)


--- trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html	                        (rev 0)
+++ trunk/LayoutTests/svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html	2016-01-26 21:19:12 UTC (rev 195614)
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+</head>
+<body>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        var svg = new Image();
+        svg.src = ""
+
+        svg._onload_ = function() {
+            var canvas = document.createElement("canvas");
+            window.ctx = canvas.getContext("2d");
+
+            ctx.getImageData(0, 0, 1, 1);
+
+            // Wait for the data uri in the image to load.
+            setTimeout(function() {
+                ctx.drawImage(svg, 0, 0);
+
+                shouldThrow("window.ctx.getImageData(0, 0, 1, 1)");
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, 50);
+        };
+    </script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (195613 => 195614)


--- trunk/Source/WebCore/ChangeLog	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/ChangeLog	2016-01-26 21:19:12 UTC (rev 195614)
@@ -1,3 +1,44 @@
+2016-01-26  Philip Rogers  <[email protected]>
+
+        Let SVG images not taint canvases except when containing foreignObjects
+        https://bugs.webkit.org/show_bug.cgi?id=119639
+
+        Reviewed by Brent Fulgham.
+
+        r153876 caused SVG images to not taint canvases but the patch allowed
+        for subimage resources. This can be a problem if a subimage (e.g., data
+        uri image) contains a foreignObject which can violate security (e.g.,
+        visited links).
+
+        This patch updates SVGImage::hasSingleSecurityOrigin to check if the
+        image contains any foreignObjects or images that themselves contain
+        foreignObjects. SVG images without foreignObjects are allowed to not
+        taint canvases.
+
+        Canvas patterns are problematic because an animated SVG image can switch
+        between tainting and not tainting the canvas. A FIXME has been added to
+        solve this, and in the meantime we cause SVG images to taint patterns.
+
+        Tests: svg/as-image/svg-canvas-pattern-with-link-tainted.html
+               svg/as-image/svg-canvas-svg-with-feimage-with-link-tainted.html
+               svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html
+
+        * html/canvas/CanvasPattern.cpp:
+        (WebCore::CanvasPattern::CanvasPattern):
+        (WebCore::CanvasPattern::~CanvasPattern):
+        * svg/SVGFEImageElement.cpp:
+        (WebCore::SVGFEImageElement::~SVGFEImageElement):
+        (WebCore::SVGFEImageElement::hasSingleSecurityOrigin):
+        (WebCore::SVGFEImageElement::clearResourceReferences):
+        * svg/SVGFEImageElement.h:
+        * svg/SVGImageElement.cpp:
+        (WebCore::SVGImageElement::create):
+        (WebCore::SVGImageElement::hasSingleSecurityOrigin):
+        (WebCore::SVGImageElement::isSupportedAttribute):
+        * svg/SVGImageElement.h:
+        * svg/graphics/SVGImage.cpp:
+        (WebCore::SVGImage::hasSingleSecurityOrigin):
+
 2016-01-26  Michael Catanzaro  <[email protected]>
 
         CSSGrammar.y:1742.31-34: warning: unused value: $3

Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (195613 => 195614)


--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2016-01-26 21:19:12 UTC (rev 195614)
@@ -1825,6 +1825,16 @@
         return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
 
     bool originClean = cachedImage->isOriginClean(canvas()->securityOrigin());
+
+    // FIXME: SVG images with animations can switch between clean and dirty (leaking cross-origin
+    // data). We should either:
+    //   1) Take a fixed snapshot of an SVG image when creating a pattern and determine then whether
+    //      the origin is clean.
+    //   2) Dynamically verify the origin checks at draw time, and dirty the canvas accordingly.
+    // To be on the safe side, taint the origin for all patterns containing SVG images for now.
+    if (cachedImage->image()->isSVGImage())
+        originClean = false;
+
     return CanvasPattern::create(cachedImage->imageForRenderer(imageElement->renderer()), repeatX, repeatY, originClean);
 }
 

Modified: trunk/Source/WebCore/svg/SVGFEImageElement.cpp (195613 => 195614)


--- trunk/Source/WebCore/svg/SVGFEImageElement.cpp	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/svg/SVGFEImageElement.cpp	2016-01-26 21:19:12 UTC (rev 195614)
@@ -65,6 +65,14 @@
     clearResourceReferences();
 }
 
+bool SVGFEImageElement::hasSingleSecurityOrigin() const
+{
+    if (!m_cachedImage)
+        return true;
+    auto* image = m_cachedImage->image();
+    return !image || image->hasSingleSecurityOrigin();
+}
+
 void SVGFEImageElement::clearResourceReferences()
 {
     if (m_cachedImage) {

Modified: trunk/Source/WebCore/svg/SVGFEImageElement.h (195613 => 195614)


--- trunk/Source/WebCore/svg/SVGFEImageElement.h	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/svg/SVGFEImageElement.h	2016-01-26 21:19:12 UTC (rev 195614)
@@ -42,6 +42,8 @@
 
     virtual ~SVGFEImageElement();
 
+    bool hasSingleSecurityOrigin() const;
+
 private:
     SVGFEImageElement(const QualifiedName&, Document&);
 

Modified: trunk/Source/WebCore/svg/SVGImageElement.cpp (195613 => 195614)


--- trunk/Source/WebCore/svg/SVGImageElement.cpp	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/svg/SVGImageElement.cpp	2016-01-26 21:19:12 UTC (rev 195614)
@@ -69,6 +69,15 @@
     return adoptRef(*new SVGImageElement(tagName, document));
 }
 
+bool SVGImageElement::hasSingleSecurityOrigin() const
+{
+    auto* renderer = downcast<RenderSVGImage>(this->renderer());
+    if (!renderer || !renderer->imageResource().hasImage())
+        return true;
+    auto* image = renderer->imageResource().cachedImage()->image();
+    return !image || image->hasSingleSecurityOrigin();
+}
+
 bool SVGImageElement::isSupportedAttribute(const QualifiedName& attrName)
 {
     static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;

Modified: trunk/Source/WebCore/svg/SVGImageElement.h (195613 => 195614)


--- trunk/Source/WebCore/svg/SVGImageElement.h	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/svg/SVGImageElement.h	2016-01-26 21:19:12 UTC (rev 195614)
@@ -37,6 +37,8 @@
 public:
     static Ref<SVGImageElement> create(const QualifiedName&, Document&);
 
+    bool hasSingleSecurityOrigin() const;
+
 private:
     SVGImageElement(const QualifiedName&, Document&);
     

Modified: trunk/Source/WebCore/svg/graphics/SVGImage.cpp (195613 => 195614)


--- trunk/Source/WebCore/svg/graphics/SVGImage.cpp	2016-01-26 21:14:33 UTC (rev 195613)
+++ trunk/Source/WebCore/svg/graphics/SVGImage.cpp	2016-01-26 21:19:12 UTC (rev 195614)
@@ -41,8 +41,10 @@
 #include "RenderSVGRoot.h"
 #include "RenderStyle.h"
 #include "SVGDocument.h"
+#include "SVGFEImageElement.h"
 #include "SVGForeignObjectElement.h"
 #include "SVGImageClients.h"
+#include "SVGImageElement.h"
 #include "SVGSVGElement.h"
 #include "Settings.h"
 #include "TextStream.h"
@@ -80,9 +82,20 @@
     if (!rootElement)
         return true;
 
-    // Don't allow foreignObject elements since they can leak information with arbitrary HTML (like spellcheck or control theme).
-    if (descendantsOfType<SVGForeignObjectElement>(*rootElement).first())
-        return false;
+    // FIXME: Once foreignObject elements within SVG images are updated to not leak cross-origin data
+    // (e.g., visited links, spellcheck) we can remove the SVGForeignObjectElement check here and
+    // research if we can remove the Image::hasSingleSecurityOrigin mechanism entirely.
+    for (auto& element : descendantsOfType<SVGElement>(*rootElement)) {
+        if (is<SVGForeignObjectElement>(element))
+            return false;
+        if (is<SVGImageElement>(element)) {
+            if (!downcast<SVGImageElement>(element).hasSingleSecurityOrigin())
+                return false;
+        } else if (is<SVGFEImageElement>(element)) {
+            if (!downcast<SVGFEImageElement>(element).hasSingleSecurityOrigin())
+                return false;
+        }
+    }
 
     // Because SVG image rendering disallows external resources and links,
     // these images effectively are restricted to a single security origin.
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to