From 8ee57bdeb09bf67ca29018ee007aaa9402eff6b7 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Tue, 21 Apr 2015 14:13:19 -0700 Subject: [PATCH] Bug 1517: Reduce precision of time for Javascript. This clamps Javascript's time precision to 100ms for most things, without altering event delivery or responsiveness. Includes clamping keyboard events (such as keypress, keyup, keydown, etc) to 100ms resolution, to mitigate keystroke fingerprinting. --- dom/base/File.cpp | 3 ++- dom/base/MultipartBlobImpl.cpp | 4 +++- dom/base/nsDOMNavigationTiming.h | 2 +- dom/events/Event.cpp | 6 ++++-- dom/html/HTMLMediaElement.cpp | 8 +++++++- dom/html/HTMLMediaElement.h | 3 +++ dom/media/DOMMediaStream.cpp | 3 ++- dom/media/webaudio/AudioContext.cpp | 4 +++- dom/performance/Performance.cpp | 7 ++++--- js/src/jsdate.cpp | 4 +++- layout/style/nsAnimationManager.h | 4 +++- mozglue/misc/TimeStamp.h | 6 ++++-- 12 files changed, 39 insertions(+), 15 deletions(-) diff --git a/dom/base/File.cpp b/dom/base/File.cpp index 46b37b976afb3..f45ba07c6bf94 100644 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -724,7 +724,8 @@ BlobImplBase::GetLastModified(ErrorResult& aRv) { NS_ASSERTION(mIsFile, "Should only be called on files"); if (IsDateUnknown()) { - mLastModificationDate = PR_Now(); + // Round to nearest 100 ms. + mLastModificationDate = floor(PR_Now() / 100000) * 100000; } return mLastModificationDate / PR_USEC_PER_MSEC; diff --git a/dom/base/MultipartBlobImpl.cpp b/dom/base/MultipartBlobImpl.cpp index ba26d07f93233..e3a3c437a5cc6 100644 --- a/dom/base/MultipartBlobImpl.cpp +++ b/dom/base/MultipartBlobImpl.cpp @@ -271,7 +271,9 @@ MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv) // x.getTime() < f.dateModified.getTime() // could fail. mLastModificationDate = - lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now(); + lastModifiedSet ? lastModified * PR_USEC_PER_MSEC + // Round to nearest 100 ms + : floor(JS_Now() / 100000) * 100000; } } diff --git a/dom/base/nsDOMNavigationTiming.h b/dom/base/nsDOMNavigationTiming.h index 9babece96319b..730769a205b8d 100644 --- a/dom/base/nsDOMNavigationTiming.h +++ b/dom/base/nsDOMNavigationTiming.h @@ -111,7 +111,7 @@ public: inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) { mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp; - return duration.ToMilliseconds(); + return floor(duration.ToMilliseconds()); // Clamp to milliseconds at least } private: diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index a85a0d66b2a12..9ca6aa0fb379b 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -1082,11 +1082,13 @@ Event::DefaultPrevented(JSContext* aCx) const return mEvent->DefaultPreventedByContent() || IsChrome(aCx); } +// XXX: We could change this resolution in other subclasses.. +// Keypress in particular... double Event::TimeStamp() const { if (!sReturnHighResTimeStamp) { - return static_cast(mEvent->mTime); + return static_cast(mEvent->mTime / 100)*100; } if (mEvent->mTimeStamp.IsNull()) { @@ -1108,7 +1110,7 @@ Event::TimeStamp() const return 0.0; } - return perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp); + return floor(perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp) / 100.0) * 100.0; } // For dedicated workers, we should make times relative to the navigation diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index b64761270f697..4ac9bdc883523 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -1854,7 +1854,7 @@ NS_IMETHODIMP HTMLMediaElement::GetSeeking(bool* aSeeking) } double -HTMLMediaElement::CurrentTime() const +HTMLMediaElement::CurrentTimeImpl() const { if (MediaStream* stream = GetSrcMediaStream()) { if (mSrcStreamPausedCurrentTime >= 0) { @@ -1870,6 +1870,12 @@ HTMLMediaElement::CurrentTime() const return mDefaultPlaybackStartPosition; } +double +HTMLMediaElement::CurrentTime() const +{ + return floor(10 * CurrentTimeImpl()) / 10; +} + NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double* aCurrentTime) { *aCurrentTime = CurrentTime(); diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index d40e9df463026..11a2e22df3b15 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -1739,6 +1739,9 @@ private: // be seeked even before the media is loaded. double mDefaultPlaybackStartPosition; + // The unrounded current time + double CurrentTimeImpl() const; + // True if the audio track is not silent. bool mIsAudioTrackAudible; diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 6794ee32f2abf..ad12d5213cbdd 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -544,8 +544,9 @@ DOMMediaStream::CurrentTime() if (!mPlaybackStream) { return 0.0; } - return mPlaybackStream-> + double currentTime = mPlaybackStream-> StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime); + return floor(10 * currentTime) / 10; } void diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index f61226a482e2f..2ff64b0faff96 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -744,7 +744,9 @@ double AudioContext::CurrentTime() const { MediaStream* stream = Destination()->Stream(); - return stream->StreamTimeToSeconds(stream->GetCurrentTime()); + double currentTime = stream->StreamTimeToSeconds(stream->GetCurrentTime()); + // Round to the latest 100 ms. + return floor(10 * currentTime) / 10; } void diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp index 17273c55dfae9..0cff90b53f535 100644 --- a/dom/performance/Performance.cpp +++ b/dom/performance/Performance.cpp @@ -228,9 +228,10 @@ Performance::ClearResourceTimings() DOMHighResTimeStamp Performance::RoundTime(double aTime) const { - // Round down to the nearest 20us, because if the timer is too accurate people - // can do nasty timing attacks with it. - const double maxResolutionMs = 0.020; + // Round down to the nearest 100 ms, because if the timer is too accurate people + // can do nasty timing attacks with it. See similar code in the worker + // Performance implementation. + const double maxResolutionMs = 100; return floor(aTime / maxResolutionMs) * maxResolutionMs; } diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index d73fb93d2e947..4900d27bce5f6 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -1232,7 +1232,9 @@ date_parse(JSContext* cx, unsigned argc, Value* vp) static ClippedTime NowAsMillis() { - return TimeClip(static_cast(PRMJ_Now()) / PRMJ_USEC_PER_MSEC); + // Truncate all date objects to 100ms precision + double now = static_cast(PRMJ_Now() / PRMJ_USEC_PER_MSEC); + return TimeClip(floor(now/100.0)*100.0); } bool diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index abe3aeeb88194..f36ac0ea7299b 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -47,7 +47,9 @@ struct AnimationEventInfo { { // XXX Looks like nobody initialize WidgetEvent::time mEvent.mAnimationName = aAnimationName; - mEvent.mElapsedTime = aElapsedTime.ToSeconds(); + // Only expose milliseconds of accuracy, since ms is the smallest time unit + // for animations anyway. + mEvent.mElapsedTime = floor(aElapsedTime.ToMilliseconds())/1000.0; mEvent.mPseudoElement = AnimationCollection::PseudoTypeAsString(aPseudoType); } diff --git a/mozglue/misc/TimeStamp.h b/mozglue/misc/TimeStamp.h index a1a0eb36078e7..779790e003c9e 100644 --- a/mozglue/misc/TimeStamp.h +++ b/mozglue/misc/TimeStamp.h @@ -13,6 +13,7 @@ #include "mozilla/FloatingPoint.h" #include "mozilla/TypeTraits.h" #include "mozilla/Types.h" +#include namespace IPC { template struct ParamTraits; @@ -108,8 +109,9 @@ public: } return BaseTimeDurationPlatformUtils::ToSecondsSigDigits(mValue); } - double ToMilliseconds() const { return ToSeconds() * 1000.0; } - double ToMicroseconds() const { return ToMilliseconds() * 1000.0; } + // Truncate all timers to microsecond accuracy + double ToMilliseconds() const { return ToMicroseconds() / 1000.0; } + double ToMicroseconds() const { return floor(ToSeconds() * 1000000.0); } // Using a double here is safe enough; with 53 bits we can represent // durations up to over 280,000 years exactly. If the units of -- GitLab