- Revision
- 214125
- Author
- s...@apple.com
- Date
- 2017-03-17 14:51:03 -0700 (Fri, 17 Mar 2017)
Log Message
Time channel attack on SVG Filters
https://bugs.webkit.org/show_bug.cgi?id=118689
Reviewed by Simon Fraser.
Source/WebCore:
The time channel attack can happen if the attacker applies FEColorMatrix
or FEConvolveMatrix and provides a matrix which is filled with subnormal
floating point values. Performing floating-point operations on subnormals
is very expensive unless the pixel in the source graphics is black (or
zero). By measuring the time a filter takes to be applied, the attacker
can know whether the pixel he wants to steal from an iframe is black or
white. By repeating the same process on all the pixels in the iframe, the
attacker can reconstruct the whole page of the iframe.
To fix this issue, the values in the matrices of these filters will clamped
to FLT_MIN. We do not want to consume too much time calculating filtered
pixels because of such tiny values. The difference between applying FLT_MIN
and applying a subnormal should not be even noticeable. Normalizing the
floating-point matrices should happen only at the beginning of the filter
platformApplySoftware().
* platform/graphics/filters/FEColorMatrix.cpp:
(WebCore::FEColorMatrix::platformApplySoftware):
* platform/graphics/filters/FEConvolveMatrix.cpp:
(WebCore::FEConvolveMatrix::fastSetInteriorPixels):
(WebCore::FEConvolveMatrix::fastSetOuterPixels):
(WebCore::FEConvolveMatrix::platformApplySoftware):
* platform/graphics/filters/FEConvolveMatrix.h:
* platform/graphics/filters/FilterEffect.h:
(WebCore::FilterEffect::normalizedFloats):
Source/WTF:
Performing arithmetic operations on subnormal floating-point numbers is
very expensive. Normalizing the floating-point number to the minimum normal
value should accelerate the calculations and there won't be a noticeable
difference in the result since all the subnormal values and the minimum
normal value are all very close to zero.
* wtf/MathExtras.h:
(normalizedFloat):
Modified Paths
Diff
Modified: trunk/Source/WTF/ChangeLog (214124 => 214125)
--- trunk/Source/WTF/ChangeLog 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WTF/ChangeLog 2017-03-17 21:51:03 UTC (rev 214125)
@@ -1,3 +1,19 @@
+2017-03-17 Said Abou-Hallawa <sabouhall...@apple.com>
+
+ Time channel attack on SVG Filters
+ https://bugs.webkit.org/show_bug.cgi?id=118689
+
+ Reviewed by Simon Fraser.
+
+ Performing arithmetic operations on subnormal floating-point numbers is
+ very expensive. Normalizing the floating-point number to the minimum normal
+ value should accelerate the calculations and there won't be a noticeable
+ difference in the result since all the subnormal values and the minimum
+ normal value are all very close to zero.
+
+ * wtf/MathExtras.h:
+ (normalizedFloat):
+
2017-03-11 Filip Pizlo <fpi...@apple.com>
Air should be powerful enough to support Tmp-splitting
Modified: trunk/Source/WTF/wtf/MathExtras.h (214124 => 214125)
--- trunk/Source/WTF/wtf/MathExtras.h 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WTF/wtf/MathExtras.h 2017-03-17 21:51:03 UTC (rev 214125)
@@ -209,6 +209,15 @@
return x > static_cast<float>(std::numeric_limits<int>::min()) && x < static_cast<float>(std::numeric_limits<int>::max());
}
+inline float normalizedFloat(float value)
+{
+ if (value > 0 && value < std::numeric_limits<float>::min())
+ return std::numeric_limits<float>::min();
+ if (value < 0 && value > -std::numeric_limits<float>::min())
+ return -std::numeric_limits<float>::min();
+ return value;
+}
+
template<typename T> inline bool hasOneBitSet(T value)
{
return !((value - 1) & value) && value;
Modified: trunk/Source/WebCore/ChangeLog (214124 => 214125)
--- trunk/Source/WebCore/ChangeLog 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WebCore/ChangeLog 2017-03-17 21:51:03 UTC (rev 214125)
@@ -1,3 +1,36 @@
+2017-03-17 Said Abou-Hallawa <sabouhall...@apple.com>
+
+ Time channel attack on SVG Filters
+ https://bugs.webkit.org/show_bug.cgi?id=118689
+
+ Reviewed by Simon Fraser.
+
+ The time channel attack can happen if the attacker applies FEColorMatrix
+ or FEConvolveMatrix and provides a matrix which is filled with subnormal
+ floating point values. Performing floating-point operations on subnormals
+ is very expensive unless the pixel in the source graphics is black (or
+ zero). By measuring the time a filter takes to be applied, the attacker
+ can know whether the pixel he wants to steal from an iframe is black or
+ white. By repeating the same process on all the pixels in the iframe, the
+ attacker can reconstruct the whole page of the iframe.
+
+ To fix this issue, the values in the matrices of these filters will clamped
+ to FLT_MIN. We do not want to consume too much time calculating filtered
+ pixels because of such tiny values. The difference between applying FLT_MIN
+ and applying a subnormal should not be even noticeable. Normalizing the
+ floating-point matrices should happen only at the beginning of the filter
+ platformApplySoftware().
+
+ * platform/graphics/filters/FEColorMatrix.cpp:
+ (WebCore::FEColorMatrix::platformApplySoftware):
+ * platform/graphics/filters/FEConvolveMatrix.cpp:
+ (WebCore::FEConvolveMatrix::fastSetInteriorPixels):
+ (WebCore::FEConvolveMatrix::fastSetOuterPixels):
+ (WebCore::FEConvolveMatrix::platformApplySoftware):
+ * platform/graphics/filters/FEConvolveMatrix.h:
+ * platform/graphics/filters/FilterEffect.h:
+ (WebCore::FilterEffect::normalizedFloats):
+
2017-03-17 Jer Noble <jer.no...@apple.com>
Explicitly resize the audio buffer in RealtimeOutgoingAudioSource.
Modified: trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp (214124 => 214125)
--- trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp 2017-03-17 21:51:03 UTC (rev 214125)
@@ -153,21 +153,22 @@
IntRect imageRect(IntPoint(), resultImage->logicalSize());
RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect);
+ Vector<float> values = normalizedFloats(m_values);
switch (m_type) {
case FECOLORMATRIX_TYPE_UNKNOWN:
break;
case FECOLORMATRIX_TYPE_MATRIX:
- effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), m_values);
+ effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), values);
break;
case FECOLORMATRIX_TYPE_SATURATE:
- effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), m_values);
+ effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), values);
break;
case FECOLORMATRIX_TYPE_HUEROTATE:
- effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), m_values);
+ effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), values);
break;
case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
- effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), m_values);
+ effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), values);
setIsAlphaImage(true);
break;
}
Modified: trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp (214124 => 214125)
--- trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp 2017-03-17 21:51:03 UTC (rev 214125)
@@ -267,7 +267,7 @@
for (int y = yEnd + 1; y > yStart; --y) {
for (int x = clipRight + 1; x > 0; --x) {
- int kernelValue = m_kernelMatrix.size() - 1;
+ int kernelValue = paintingData.kernelMatrix.size() - 1;
int kernelPixel = startKernelPixel;
int width = m_kernelSize.width();
@@ -278,11 +278,11 @@
totals[3] = 0;
while (kernelValue >= 0) {
- totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel++));
- totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel++));
- totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel++));
+ totals[0] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel++));
+ totals[1] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel++));
+ totals[2] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel++));
if (!preserveAlphaValues)
- totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel));
+ totals[3] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(kernelPixel));
++kernelPixel;
--kernelValue;
if (!--width) {
@@ -347,7 +347,7 @@
for (int y = height; y > 0; --y) {
for (int x = width; x > 0; --x) {
- int kernelValue = m_kernelMatrix.size() - 1;
+ int kernelValue = paintingData.kernelMatrix.size() - 1;
int kernelPixelX = startKernelPixelX;
int kernelPixelY = startKernelPixelY;
int width = m_kernelSize.width();
@@ -361,12 +361,12 @@
while (kernelValue >= 0) {
int pixelIndex = getPixelValue(paintingData, kernelPixelX, kernelPixelY);
if (pixelIndex >= 0) {
- totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex));
- totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex + 1));
- totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex + 2));
+ totals[0] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex));
+ totals[1] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex + 1));
+ totals[2] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex + 2));
}
if (!preserveAlphaValues && pixelIndex >= 0)
- totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex + 3));
+ totals[3] += paintingData.kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->item(pixelIndex + 3));
++kernelPixelX;
--kernelValue;
if (!--width) {
@@ -436,6 +436,7 @@
paintingData.width = paintSize.width();
paintingData.height = paintSize.height();
paintingData.bias = m_bias * 255;
+ paintingData.kernelMatrix = normalizedFloats(m_kernelMatrix);
// Drawing fully covered pixels
int clipRight = paintSize.width() - m_kernelSize.width();
Modified: trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h (214124 => 214125)
--- trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h 2017-03-17 21:51:03 UTC (rev 214125)
@@ -83,6 +83,7 @@
int width;
int height;
float bias;
+ Vector<float> kernelMatrix;
};
FEConvolveMatrix(Filter&, const IntSize&, float, float,
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h (214124 => 214125)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2017-03-17 21:31:49 UTC (rev 214124)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2017-03-17 21:51:03 UTC (rev 214125)
@@ -26,6 +26,7 @@
#include "FloatRect.h"
#include "IntRect.h"
#include <runtime/Uint8ClampedArray.h>
+#include <wtf/MathExtras.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
@@ -170,6 +171,14 @@
void forceValidPreMultipliedPixels();
void clipAbsolutePaintRect();
+
+ static Vector<float> normalizedFloats(const Vector<float>& values)
+ {
+ Vector<float> normalizedValues(values.size());
+ for (size_t i = 0; i < values.size(); ++i)
+ normalizedValues[i] = normalizedFloat(values[i]);
+ return normalizedValues;
+ }
private:
std::unique_ptr<ImageBuffer> m_imageBufferResult;