Closed Bug 600025 Opened 9 years ago Closed 9 years ago

CSS timing attack on global history still possible with MozAfterPaint

Categories

(Core :: CSS Parsing and Computation, defect, P3)

defect

Tracking

()

VERIFIED FIXED
Tracking Status
blocking2.0 --- final+

People

(Reporter: zwol, Assigned: dbaron)

References

(Depends on 1 open bug)

Details

(Keywords: privacy, Whiteboard: [will be fixed by bug 608030][softblocker][sg:low][fx4-fixed-bugday])

Attachments

(2 files)

Post-bug 147777, it is not supposed to be possible to read global history via timing attacks, but the web page at the URL above seems to be able to do it under some circumstances.  It uses CSS rules of the form

  div[class*="123"] a:visited { color: green }

in conjunction with HTML of the form

  <div class="xxxxxxx..."><a href="[target site]">blah</a></div>

and a listener for the MozAfterPaint event.  There are 400,000 "x"s (and no number at all) in the classname.

Pre-bug 147777, the MozAfterPaint event fires in <5ms for unvisited links, and 300-600ms for visited links.  The test page is very reliable.

Post-bug 147777, the MozAfterPaint event fires in about 600ms for unvisited links and somewhere between 600 and 1200 ms for visited links.  The test page's calibration procedure does not always work, and sometimes an *un*visited link or two takes the amount of time associated with visited links, but overall, the attack still works.

I have not been able to figure out why the attack still works; it *seems* like the patches for bug 147777 should make the selector take the same amount of time regardless.  It is, perhaps, telling that a variation that times synchronous reflow (by reading reflow-dependent DOM properties) does *not* work; only the MozAfterPaint approach works.
I should have mentioned that this does not always work -- on some builds/OSes/profiles/phases of moon, everything takes the same amount of time.  *confused*
With visited links, perhaps we just have more stuff in the event queue (due to the events that the history thread posts to notify links when lookups complete)?
More precisely, maybe they're managing to measure the time we take to restyle once we discover the link is visited?
Assignee: nobody → dbaron
blocking2.0: --- → final+
In other words, this could be bug 557579?
(In reply to comment #4)
> In other words, this could be bug 557579?
Yeah, likely.  We don't restyle right now if it's not visited.  Always restyling kinda sucks perf wise though :(
(In reply to comment #5)
> Yeah, likely.  We don't restyle right now if it's not visited.  Always
> restyling kinda sucks perf wise though :(
Wouldn't it only be necessary to restyle irrespective of history for links to non-same-origin resources?
Checking the origin is may well be just as expensive as restyling.... Worth measuring, perhaps.
(In reply to comment #3)
> More precisely, maybe they're managing to measure the time we take to restyle
> once we discover the link is visited?

That *sounds* consistent with MozAfterPaint seeing a timing difference but reflow-dependent DOM properties not.  And with MozAfterPaint not always working.

Perhaps a lower-cost fix is to fire MozAfterPaint at the point where we would have done it if there weren't outstanding history queries?  (I have no idea whether this is feasible.)

(In reply to comment #6)
> Wouldn't it only be necessary to restyle irrespective of history for links to
> non-same-origin resources?

I recall the discussion in bug 147777 being generally opposed to having same-origin-ness matter.  With my security researcher hat on, I like that, because it means I can test for this kind of bug without needing two domain names or having to make assumptions on the order of "*everybody* visits facebook.com" ;-)
Changing when MozAfterPaint fires may not be airtight, though; I don't *know* one, but there might be some other sneaky way to detect the restyle.
Here's a test case that counts the number of repaints to determine whether a link is visited on not.
Attached file Original timing PoC
Yeah, I think this is just bug 557579.
Depends on: 557579
We can disable the firing of MozAfterPaint events for some or all invalidates, if we have to. It's not that important an API. But it sounds like that doesn't really solve anything, and the timing of paints can still be picked up via mozRequestAnimationFrame, which is something we definitely *don't* want to break.
Whiteboard: [will be fixed by bug 608030]
Whiteboard: [will be fixed by bug 608030] → [will be fixed by bug 608030][softblocker]
Keywords: privacy
Whiteboard: [will be fixed by bug 608030][softblocker] → [will be fixed by bug 608030][softblocker][sg:low]
Priority: -- → P3
How does mozRequestAnimationFrame expose whether or not we have anything to paint?
Yeah I guess it doesn't. Never mind!

Note that MozAfterPaint has just changed so that now it actually fires (synchronously) just after painting. That probably doesn't affect this bug though.
Fixed by bug 608030.
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Yeah, thanks.  I was thinking I needed to file an additional followup bug, but I realize bug 557579 is already filed.
Verified with Mozilla/5.0 (X11; Linux i686; rv:2.0b12pre) Gecko/20110204 Firefox/4.0b12pre
Status: RESOLVED → VERIFIED
Whiteboard: [will be fixed by bug 608030][softblocker][sg:low] → [will be fixed by bug 608030][softblocker][sg:low][fx4-fixed-bugday]
You need to log in before you can comment on or make changes to this bug.