summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-15 11:13:11 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-15 11:39:43 +0000
commitb7a9c9bf5b6bc08ae8746b7679317a9027868681 (patch)
tree73dd8ca522e152927d230faff2ecd2836823e710
parent1f43353c961a58cee76faf11f1be22c182f7dffd (diff)
[Backport] Clamp performance.now() to 100us.v5.9.4
This patch reduces the resolution of performance.now() from 5us to 100us and adds pseudorandom jitter on top. TBR=skyostil@chromium.org (cherry picked from commit a77687fd89adc1bc2ce91921456e0b9b59388120) Authors: Ross McIlroy <rmcilroy@chromium.org>, Sami Kyostila <skyostil@chromium.org> Bug: 798964 Reviewed-on: https://chromium-review.googlesource.com/849993 Commit-Queue: Sami Kyöstilä <skyostil@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Jochen Eisinger <jochen@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#527008} Reviewed-on: https://chromium-review.googlesource.com/853505 Reviewed-by: Sami Kyöstilä <skyostil@chromium.org> Cr-Commit-Position: refs/branch-heads/3282@{#439} Cr-Branched-From: 5fdc0fab22ce7efd32532ee989b223fa12f8171e-refs/heads/master@{#520840} Change-Id: Ia7e1171e1505ddc73cb5356fcc0aac2466f49e08 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp2
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp1
-rw-r--r--chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp13
-rw-r--r--chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h2
-rw-r--r--chromium/third_party/WebKit/Source/platform/BUILD.gn3
-rw-r--r--chromium/third_party/WebKit/Source/platform/DEPS1
-rw-r--r--chromium/third_party/WebKit/Source/platform/TimeClamper.cpp54
-rw-r--r--chromium/third_party/WebKit/Source/platform/TimeClamper.h42
-rw-r--r--chromium/third_party/WebKit/Source/platform/TimeClamperTest.cpp98
9 files changed, 207 insertions, 9 deletions
diff --git a/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp b/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp
index f35300d57e5..66e0f2afeb1 100644
--- a/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp
@@ -15,7 +15,7 @@ IdleDeadline::IdleDeadline(double deadlineSeconds, CallbackType callbackType)
double IdleDeadline::timeRemaining() const {
double timeRemaining = m_deadlineSeconds - monotonicallyIncreasingTime();
if (timeRemaining < 0)
- timeRemaining = 0;
+ return 0;
return 1000.0 * PerformanceBase::clampTimeResolution(timeRemaining);
}
diff --git a/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp b/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
index dc267a3db88..f7192b82366 100644
--- a/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
@@ -34,7 +34,6 @@ class IdleRequestCallbackWrapper
static void idleTaskFired(
PassRefPtr<IdleRequestCallbackWrapper> callbackWrapper,
double deadlineSeconds) {
- // TODO(rmcilroy): Implement clamping of deadline in some form.
if (ScriptedIdleTaskController* controller = callbackWrapper->controller())
controller->callbackFired(callbackWrapper->id(), deadlineSeconds,
IdleDeadline::CallbackType::CalledWhenIdle);
diff --git a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
index 88094fa06e3..f23f6695234 100644
--- a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
+++ b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
@@ -39,6 +39,7 @@
#include "core/timing/PerformanceResourceTiming.h"
#include "core/timing/PerformanceUserTiming.h"
#include "platform/network/ResourceTimingInfo.h"
+#include "platform/TimeClamper.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "wtf/CurrentTime.h"
#include <algorithm>
@@ -436,9 +437,9 @@ void PerformanceBase::deliverObservationsTimerFired(TimerBase*) {
}
// static
-double PerformanceBase::clampTimeResolution(double timeSeconds) {
- const double resolutionSeconds = 0.000005;
- return floor(timeSeconds / resolutionSeconds) * resolutionSeconds;
+double PerformanceBase::clampTimeResolution(double time_seconds) {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(TimeClamper, clamper, new TimeClamper());
+ return clamper.ClampTimeResolution(time_seconds);
}
DOMHighResTimeStamp PerformanceBase::monotonicTimeToDOMHighResTimeStamp(
@@ -447,9 +448,9 @@ DOMHighResTimeStamp PerformanceBase::monotonicTimeToDOMHighResTimeStamp(
if (m_timeOrigin == 0.0)
return 0.0;
- double timeInSeconds = monotonicTime - m_timeOrigin;
- return convertSecondsToDOMHighResTimeStamp(
- clampTimeResolution(timeInSeconds));
+ double clamped_time_in_seconds =
+ clampTimeResolution(monotonicTime) - clampTimeResolution(m_timeOrigin);
+ return convertSecondsToDOMHighResTimeStamp(clamped_time_in_seconds);
}
double PerformanceBase::monotonicTimeToDOMHighResTimeStampInMillis(
diff --git a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h
index 52a1c9f2dad..05271ad793b 100644
--- a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h
+++ b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h
@@ -65,7 +65,7 @@ class CORE_EXPORT PerformanceBase : public EventTargetWithInlineData {
virtual void updateLongTaskInstrumentation() {}
- // Reduce the resolution to 5µs to prevent timing attacks. See:
+ // Reduce the resolution to prevent timing attacks. See:
// http://www.w3.org/TR/hr-time-2/#privacy-security
static double clampTimeResolution(double timeSeconds);
diff --git a/chromium/third_party/WebKit/Source/platform/BUILD.gn b/chromium/third_party/WebKit/Source/platform/BUILD.gn
index 2c35eed91ea..7f8c5fca5a2 100644
--- a/chromium/third_party/WebKit/Source/platform/BUILD.gn
+++ b/chromium/third_party/WebKit/Source/platform/BUILD.gn
@@ -315,6 +315,8 @@ component("platform") {
"Theme.cpp",
"Theme.h",
"ThemeTypes.h",
+ "TimeClamper.cpp",
+ "TimeClamper.h",
"Timer.cpp",
"Timer.h",
"UUID.cpp",
@@ -1644,6 +1646,7 @@ test("blink_platform_unittests") {
"PODRedBlackTreeTest.cpp",
"ScopedOrientationChangeIndicatorTest.cpp",
"SharedBufferTest.cpp",
+ "TimeClamperTest.cpp",
"TimerTest.cpp",
"UUIDTest.cpp",
"UserGestureIndicatorTest.cpp",
diff --git a/chromium/third_party/WebKit/Source/platform/DEPS b/chromium/third_party/WebKit/Source/platform/DEPS
index 2003c6e2f92..a91929d6dfe 100644
--- a/chromium/third_party/WebKit/Source/platform/DEPS
+++ b/chromium/third_party/WebKit/Source/platform/DEPS
@@ -4,6 +4,7 @@ include_rules = [
"+base/bind.h",
"+base/callback.h",
"+base/callback_forward.h",
+ "+base/bit_cast.h",
"+base/files",
"+base/guid.h",
"+base/json",
diff --git a/chromium/third_party/WebKit/Source/platform/TimeClamper.cpp b/chromium/third_party/WebKit/Source/platform/TimeClamper.cpp
new file mode 100644
index 00000000000..3eb6815018c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/platform/TimeClamper.cpp
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/TimeClamper.h"
+
+#include "base/bit_cast.h"
+#include "wtf/Assertions.h"
+#include "wtf/CryptographicallyRandomNumber.h"
+
+#include <cmath>
+
+namespace blink {
+
+TimeClamper::TimeClamper() {
+ cryptographicallyRandomValues(&secret_, sizeof(secret_));
+}
+
+double TimeClamper::ClampTimeResolution(double time_seconds) const {
+ DCHECK_GE(time_seconds, 0);
+ double clamped_time =
+ floor(time_seconds / kResolutionSeconds) * kResolutionSeconds;
+ double tick_threshold = ThresholdFor(clamped_time);
+
+ if (time_seconds >= tick_threshold)
+ return clamped_time + kResolutionSeconds;
+ return clamped_time;
+}
+
+inline double TimeClamper::ThresholdFor(double clamped_time) const {
+ uint64_t time_hash = MurmurHash3(bit_cast<int64_t>(clamped_time) ^ secret_);
+ return clamped_time + kResolutionSeconds * ToDouble(time_hash);
+}
+
+// static
+inline double TimeClamper::ToDouble(uint64_t value) {
+ // Exponent for double values for [1.0 .. 2.0]
+ static const uint64_t kExponentBits = uint64_t{0x3FF0000000000000};
+ static const uint64_t kMantissaMask = uint64_t{0x000FFFFFFFFFFFFF};
+ uint64_t random = (value & kMantissaMask) | kExponentBits;
+ return bit_cast<double>(random) - 1;
+}
+
+// static
+inline uint64_t TimeClamper::MurmurHash3(uint64_t value) {
+ value ^= value >> 33;
+ value *= uint64_t{0xFF51AFD7ED558CCD};
+ value ^= value >> 33;
+ value *= uint64_t{0xC4CEB9FE1A85EC53};
+ value ^= value >> 33;
+ return value;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/WebKit/Source/platform/TimeClamper.h b/chromium/third_party/WebKit/Source/platform/TimeClamper.h
new file mode 100644
index 00000000000..7550ef1ff23
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/platform/TimeClamper.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TimeClamper_h
+#define TimeClamper_h
+
+#include "base/macros.h"
+#include "platform/PlatformExport.h"
+
+#include <stdint.h>
+
+namespace blink {
+
+class PLATFORM_EXPORT TimeClamper {
+ public:
+ static constexpr double kResolutionSeconds = 0.0001;
+
+ TimeClamper();
+
+ // Deterministically clamp the time value |time_seconds| to a 100us interval
+ // to prevent timing attacks. See
+ // http://www.w3.org/TR/hr-time-2/#privacy-security.
+ //
+ // For each clamped time interval, we compute a pseudorandom transition
+ // threshold. The returned time will either be the start of that interval or
+ // the next one depending on which side of the threshold |time_seconds| is.
+ double ClampTimeResolution(double time_seconds) const;
+
+ private:
+ inline double ThresholdFor(double clamped_time) const;
+ static inline double ToDouble(uint64_t value);
+ static inline uint64_t MurmurHash3(uint64_t value);
+
+ uint64_t secret_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimeClamper);
+};
+
+} // namespace blink
+
+#endif // TimeClamper_h
diff --git a/chromium/third_party/WebKit/Source/platform/TimeClamperTest.cpp b/chromium/third_party/WebKit/Source/platform/TimeClamperTest.cpp
new file mode 100644
index 00000000000..04e4622c152
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/platform/TimeClamperTest.cpp
@@ -0,0 +1,98 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/TimeClamper.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <cmath>
+
+namespace blink {
+namespace {
+const double kInterval = TimeClamper::kResolutionSeconds;
+}
+
+TEST(TimeClamperTest, TimeStampsAreNonNegative) {
+ TimeClamper clamper;
+ EXPECT_GE(clamper.ClampTimeResolution(0), 0.f);
+ EXPECT_GE(clamper.ClampTimeResolution(TimeClamper::kResolutionSeconds), 0.f);
+}
+
+TEST(TimeClamperTest, TimeStampsIncreaseByFixedAmount) {
+ const double kEpsilon = 1e-10;
+ TimeClamper clamper;
+ double prev = clamper.ClampTimeResolution(0);
+ for (double time_seconds = 0; time_seconds < kInterval * 100;
+ time_seconds += kInterval * 0.1) {
+ double clamped_time = clamper.ClampTimeResolution(time_seconds);
+ double delta = clamped_time - prev;
+ if (delta > kEpsilon) {
+ ASSERT_TRUE(std::fabs(delta - kInterval) < kEpsilon);
+ prev = clamped_time;
+ }
+ }
+}
+
+TEST(TimeClamperTest, ClampingIsConsistent) {
+ TimeClamper clamper;
+ for (double time_seconds = 0; time_seconds < kInterval * 100;
+ time_seconds += kInterval * 0.1) {
+ double t1 = clamper.ClampTimeResolution(time_seconds);
+ double t2 = clamper.ClampTimeResolution(time_seconds);
+ EXPECT_EQ(t1, t2);
+ }
+}
+
+TEST(TimeClamperTest, ClampingIsPerInstance) {
+ const double kEpsilon = 1e-10;
+ TimeClamper clamper1;
+ TimeClamper clamper2;
+ double time_seconds = 0;
+ while (true) {
+ if (std::fabs(clamper1.ClampTimeResolution(time_seconds) -
+ clamper2.ClampTimeResolution(time_seconds)) > kEpsilon) {
+ break;
+ }
+ time_seconds += kInterval;
+ }
+}
+
+TEST(TimeClamperTest, ClampingIsUniform) {
+ const int kBuckets = 8;
+ const int kSampleCount = 10000;
+ const double kEpsilon = 1e-10;
+ const double kTimeStep = kInterval / kBuckets;
+ double time_seconds = 299792.458;
+ int histogram[kBuckets] = {0};
+ TimeClamper clamper;
+
+ // This test ensures the jitter thresholds are approximately uniformly
+ // distributed inside the clamping intervals. It samples individual intervals
+ // to detect where the threshold is and counts the number of steps taken.
+ for (int i = 0; i < kSampleCount; i++) {
+ double start = clamper.ClampTimeResolution(time_seconds);
+ for (int step = 0; step < kBuckets; step++) {
+ time_seconds += kTimeStep;
+ if (std::abs(clamper.ClampTimeResolution(time_seconds) - start) >
+ kEpsilon) {
+ histogram[step]++;
+ // Skip to the next interval to make sure each measurement is
+ // independent.
+ time_seconds = floor(time_seconds / kInterval) * kInterval + kInterval;
+ break;
+ }
+ }
+ }
+
+ double expected_count = kSampleCount / kBuckets;
+ double chi_squared = 0;
+ for (int i = 0; i < kBuckets; ++i) {
+ double difference = histogram[i] - expected_count;
+ chi_squared += difference * difference / expected_count;
+ }
+ // P-value for a 0.001 significance level with 7 degrees of freedom.
+ EXPECT_LT(chi_squared, 24.322);
+}
+
+} // namespace blink