Project: chromium Issues People Development process History Sign in
New issue
Advanced search Search tips
Issue 615851 Security: Timing attack on denormalized floating point arithmetic in SVG filters circumvents same-origin policy
Starred by 1 user Reported by roelandk...@gmail.com, May 30 2016 Back to list
Status: Fixed
Owner:
Closed: Oct 27
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 2
Type: Bug-Security



Sign in to add a comment
VULNERABILITY DETAILS
Arithmetic with denormalized floating point values results in characteristic timing behavior. Multiple SVG filters perform calculation between pixel values and floating point parameters. If the provided parameters are denormalized, execution time is measurably faster if pixel values of zero are multiplied with the denormalized parameter, compared to multiplication of a pixel value larger than zero. This allows an attacker to construct a timing channel to read pixels from images and iframes containing content from other sources, by measuring the timing difference between operations on black and nonblack pixels. Other filters can be used to change any specific color or color range to black, so any information or color can be read from other pages.

Based on their definitions, I believe the following filters to be vulnerable:
feColorMatrix
feComponentTransfer
feComposite
feConvolveMatrix
feDisplacementMap

Timing channels using SVG filters have been discovered before. Other than vulnerabilities described in http://www.contextis.com/documents/2/Browser_Timing_Attacks.pdf, this attack isn't based on control flow through execution paths of different length, but it is based on specific values which CPUs handle differently.

A similar attack has been described in "On Subnormal Floating Point and Abnormal Timing", but the researchers believed Chrome wasn't vulnerable to this attack. My exploit demonstrates that it actually is.

To fix this vulnerability, simply make sure calculation isn't applied on denormalized values. This should not cause any practical issues because denormalized numbers really aren't required for filters operations, so they can safely be rounded to zero.

VERSION
Chrome Version: 51.0.2704.63 stable
Operating System: Windows 8.1, no service pack
CPU: Intel Core i5-4200U CPU @ 1.60Ghz 2.30Ghz (useful because timing attack)

REPRODUCTION CASE
An exploit is attached which demonstrates the vulnerability. It reconstructs an external image of 10 by 10 pixels, which is easy to visually verify for faults. Reconstruction on my test machine results in about 0-2 faulty reads, and takes about 10 seconds for 100 pixels, this could be made at least twice as fast at the cost of some accuracy. Using the technique described in the Context paper to read characters, this means at least 2-4 characters per second can be read. This exploit is based on feConvolveMatrix, as it is very easy with this filter to perform many arithmetic operations. However, I think any of the above listed filters can be used to construct an exploit like this.
 
exploit.html
7.3 KB View Download
Comment 1 by meacer@chromium.org, May 31 2016
Components: Blink>SVG Privacy
Labels: Security_Severity-Medium Security_Impact-Stable OS-All Pri-1
Owner: senorblanco@chromium.org
Status: Assigned
Thanks for the report, adding some labels based on bug 586820 since the bugs are similar.

senorblanco: Can you please take a look?
Comment 2 by meacer@chromium.org, May 31 2016
Labels: M-51
Project Member Comment 3 by sheriffbot@chromium.org, Jun 14 2016
senorblanco: Uh oh! This issue still open and hasn't been updated in the last 15 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Project Member Comment 4 by sheriffbot@chromium.org, Jun 29 2016
senorblanco: Uh oh! This issue still open and hasn't been updated in the last 29 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Project Member Comment 5 by sheriffbot@chromium.org, Jul 21 2016
Labels: -M-51 M-52
Has this vulnerability been confirmed yet, or is there anything else preventing progress on a bug fix?
Thanks for your report. I can reproduce the problem. There's nothing preventing progress except developer time.
This seems to have been "fixed" (or at least, made much harder to reproduce) by recent changes. Bisect says:

You are probably looking for a change made after 395198 (known bad), but no later than 395210 (first known good).
CHANGELOG URL:
  https://chromium.googlesource.com/chromium/src/+log/0a493d5420854a4c252c974c23b92917562133c9..87ee877992e41f3037a23a164abf4689c1ba603c
Cc: sunnyps@chromium.org mtklein@chromium.org
I'm suspecting https://chromium.googlesource.com/chromium/src/+/36a74489ec5e4fb898a7984398ad79b3798f70d7 ("Enable main frame before activation on waterfall") has changed the timing enough to "fix" this. However, it looks like there may still be some signal in the noise, so I'll continue to pursue a fix on the Skia side.


Think it's time to pull out the big guns and turn off denorms?

This ought to do the trick on x86, making denorm inputs act as zero (DAZ) and anything that produces denorm produce zero instead (FTZ):
    _mm_setcsr(_mm_getcsr() | 0x8040);
Yeah, that would probably be the easiest fix. I wasn't sure how it might affect things outside filters, though. Could wrap the filter entry points to set it / restore it, but then I'm not sure about thread safety.

Also, is there an equivalent for ARM?
Reading ARM's docs* and the Android NDK's fenv.h, it looks like that we can use fesetenv() and fegetenv() to toggle bit 24 of the fpscr, something like this:

fenv_t original, flush_to_zero;
(void)fegetenv(&original);
flush_to_zero = original | (1<<24);
(void)fesetenv(&flush_to_zero);
...
(void)fesetenv(&original);

* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0379d/Bcfhfbga.html


I don't know authoritatively how MXCSR works re threading, but a quick test shows that it behaves like any other register, so I wouldn't expect threading issues:

#include <assert.h>
#include <immintrin.h>
#include <string.h>
#include <thread>

volatile uint32_t zero    = 0x00000000;
volatile uint32_t denorm  = 0x00000001;
volatile uint32_t doubled = 0x00000002;

static float pun(uint32_t bits) {
    float f;
    memcpy(&f, &bits, 4);
    return f;
}

static void normal() {
    while (true) {
        assert (pun(denorm) + pun(denorm) == pun(doubled));
        assert (pun(doubled) != pun(zero));
    }
}

static void flush_denorm() {
    while (true) {
        _mm_setcsr(_mm_getcsr() | 0x8040);
        assert (pun(denorm) + pun(denorm) == pun(doubled));
        assert (pun(doubled) == pun(zero));
        _mm_setcsr(_mm_getcsr() ^ 0x8040);
    }
}

int main() {
    std::thread t1(normal), t2(flush_denorm);
    t1.join();
    t2.join();
    return 0;
}

Cc: piman@chromium.org
Here's a slight tweak that repros in the software renderer (although horizontally flipped, for some reason).

Run with --disable-main-frame-before-activation --disable-gpu
denorm_exploit_software_renderer.html
7.3 KB View Download
Project Member Comment 15 by bugdroid1@chromium.org, Jul 26 2016
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/014a9a0ea7260b37773adb545b7cabbff80423b9

commit 014a9a0ea7260b37773adb545b7cabbff80423b9
Author: senorblanco <senorblanco@chromium.org>
Date: Tue Jul 26 16:18:46 2016

cc: disable denorm handling before calling into Skia's filter code.

Set the "denorms-are-zero" and "flush-to-zero" CSR flags prior to
calling into Skia's filter code.

BUG= 615851 
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_blink_rel

Review-Url: https://codereview.chromium.org/2179003003
Cr-Commit-Position: refs/heads/master@{#407823}

[modify] https://crrev.com/014a9a0ea7260b37773adb545b7cabbff80423b9/cc/base/math_util.cc
[modify] https://crrev.com/014a9a0ea7260b37773adb545b7cabbff80423b9/cc/base/math_util.h
[modify] https://crrev.com/014a9a0ea7260b37773adb545b7cabbff80423b9/cc/output/software_renderer.cc
[modify] https://crrev.com/014a9a0ea7260b37773adb545b7cabbff80423b9/cc/playback/raster_source.cc

Labels: -Pri-1 Pri-2
The fix for x86 (and x86_64) has landed (above). The fix for ARM (using fesetenv) *should* work according to the docs, but doesn't, so I haven't landed it yet.

Note that I had to explicitly compile in --disable-main-frame-before-activation into my Chrome/Android build in order to repro, so I'm going to lower the priority of this.
What ARM device are you testing on?  ARMv7 NEON always treats denorm as zero.  This filter is implemented in NEON, right?  Or is it some serial code that's the vector?
I don't think feConvolveMatrix (aka SkMatrixConvolutionImageFilter) has been SIMDified (either or SSE or NEON).
Ah, gotcha.
I'm still stumped as to why the ARM fix doesn't work. I tried it on Nexus 7 (2013) and Nexus 6P, and the problem still repros. My guess that it's perhaps because ARM has the "flush-to-zero" mode, but not an equivalent of "denorms-are-zero".

So I've put up a skia fix to force all incoming float filter attributes to zero: https://codereview.chromium.org/2198263002/
Project Member Comment 21 by sheriffbot@chromium.org, Sep 1
Labels: -M-52 M-53
Hi, any progress on the fix?
The x86 fix is in as of the change in c#15, but there has been no progress on the ARM fix.

However, I believe that it is no longer reproducible on ARM even without my fix due to main frame before activation having been enabled. If you can still repro it on any platform, please let me know and I'll raise the priority of this work.

Thanks again for your report.
Labels: Security_bugs-keptopen
Project Member Comment 25 by sheriffbot@chromium.org, Oct 13
Labels: -M-53 M-54
No I haven't been able to reproduce it. Perhaps close the issue and/or forward to the panel for finishing steps? Would be nice to have a CVE-identifier to refer to it.
Labels: -Security_bugs-keptopen
Status: Fixed
Labels: reward-topanel
Project Member Comment 29 by sheriffbot@chromium.org, Oct 28
Labels: -Restrict-View-SecurityTeam Restrict-View-SecurityNotify
Project Member Comment 30 by sheriffbot@chromium.org, Oct 30
Labels: Merge-Request-55
Labels: -Merge-Request-55 Merge-Review-55 Hotlist-Merge-Review
[Automated comment] Commit may have occurred before M55 branch point (10/6/2016), needs manual review.
Cc: awhalley@chromium.org
Labels: -Merge-Review-55
CL listed at #15 landed on July 26th and M55 was branched on 10/6/2016. So no merged is needed here. Removing "Merge-Review-55" label.

+awhalley@, please re-request M55 merge if needed. Thank you.


Labels: -Hotlist-Merge-Review
Labels: -reward-topanel -Security_Severity-Medium reward-NA Security_Severity-Low Release-0-M55
The panel declined to reward along the same lines as before, but this should get a CVE in M55 release notes.
Labels: CVE-2016-5224
Project Member Comment 36 by sheriffbot@chromium.org, Feb 3
Labels: -Restrict-View-SecurityNotify allpublic
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Sign in to add a comment