summaryrefslogtreecommitdiff
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 10:24:59 +0000
commit17e4aafb6fe894047b46abeb3c3b8290de4094cf (patch)
tree2ed9ffd73e57954896a20e7c6fd3565b469d0992
parent44b6c003b1e3ab8ef4ce9d516fd24d7a8eefb2ff (diff)
downloadqtwebengine-chromium-17e4aafb6fe894047b46abeb3c3b8290de4094cf.tar.gz
[Backport] Clamp performance.now() to 100us.
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.cpp4
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/IdleDeadlineTest.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
10 files changed, 209 insertions, 11 deletions
diff --git a/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp b/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp
index df981b7b097..415dce1b67e 100644
--- a/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/IdleDeadline.cpp
@@ -17,12 +17,12 @@ IdleDeadline::IdleDeadline(double deadline_seconds, CallbackType callback_type)
double IdleDeadline::timeRemaining() const {
double time_remaining = deadline_seconds_ - MonotonicallyIncreasingTime();
if (time_remaining < 0) {
- time_remaining = 0;
+ return 0;
} else if (Platform::Current()
->CurrentThread()
->Scheduler()
->ShouldYieldForHighPriorityWork()) {
- time_remaining = 0;
+ return 0;
}
return 1000.0 * PerformanceBase::ClampTimeResolution(time_remaining);
diff --git a/chromium/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp b/chromium/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp
index a9cd8887e01..c215904b594 100644
--- a/chromium/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp
@@ -86,7 +86,7 @@ TEST_F(IdleDeadlineTest, deadlineInFuture) {
IdleDeadline* deadline =
IdleDeadline::Create(1.25, IdleDeadline::CallbackType::kCalledWhenIdle);
// Note: the deadline is computed with reduced resolution.
- EXPECT_FLOAT_EQ(249.995, deadline->timeRemaining());
+ EXPECT_FLOAT_EQ(250.0, deadline->timeRemaining());
}
TEST_F(IdleDeadlineTest, deadlineInPast) {
diff --git a/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp b/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
index 1b7c3b1032c..3d8c03f5b72 100644
--- a/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
@@ -35,7 +35,6 @@ class IdleRequestCallbackWrapper
static void IdleTaskFired(
PassRefPtr<IdleRequestCallbackWrapper> callback_wrapper,
double deadline_seconds) {
- // TODO(rmcilroy): Implement clamping of deadline in some form.
if (ScriptedIdleTaskController* controller =
callback_wrapper->Controller()) {
// If we are going to yield immediately, reschedule the callback for
diff --git a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
index 90c794e0061..5f14cffb213 100644
--- a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
+++ b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
@@ -44,6 +44,7 @@
#include "core/timing/PerformanceResourceTiming.h"
#include "core/timing/PerformanceUserTiming.h"
#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/TimeClamper.h"
#include "platform/loader/fetch/ResourceResponse.h"
#include "platform/loader/fetch/ResourceTimingInfo.h"
#include "platform/weborigin/SecurityOrigin.h"
@@ -508,8 +509,8 @@ void PerformanceBase::DeliverObservationsTimerFired(TimerBase*) {
// static
double PerformanceBase::ClampTimeResolution(double time_seconds) {
- const double kResolutionSeconds = 0.000005;
- return floor(time_seconds / kResolutionSeconds) * kResolutionSeconds;
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(TimeClamper, clamper, ());
+ return clamper.ClampTimeResolution(time_seconds);
}
// static
@@ -521,11 +522,11 @@ DOMHighResTimeStamp PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
if (!monotonic_time || !time_origin)
return 0.0;
- double time_in_seconds = monotonic_time - time_origin;
- if (time_in_seconds < 0 && !allow_negative_value)
+ double clamped_time_in_seconds =
+ ClampTimeResolution(monotonic_time) - ClampTimeResolution(time_origin);
+ if (clamped_time_in_seconds < 0 && !allow_negative_value)
return 0.0;
- return ConvertSecondsToDOMHighResTimeStamp(
- ClampTimeResolution(time_in_seconds));
+ return ConvertSecondsToDOMHighResTimeStamp(clamped_time_in_seconds);
}
DOMHighResTimeStamp PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
diff --git a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h
index f94a11ad882..625a45c49c1 100644
--- a/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h
+++ b/chromium/third_party/WebKit/Source/core/timing/PerformanceBase.h
@@ -70,7 +70,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 time_seconds);
diff --git a/chromium/third_party/WebKit/Source/platform/BUILD.gn b/chromium/third_party/WebKit/Source/platform/BUILD.gn
index 85adfaf2098..5ba4275c714 100644
--- a/chromium/third_party/WebKit/Source/platform/BUILD.gn
+++ b/chromium/third_party/WebKit/Source/platform/BUILD.gn
@@ -320,6 +320,8 @@ component("platform") {
"Theme.cpp",
"Theme.h",
"ThemeTypes.h",
+ "TimeClamper.cpp",
+ "TimeClamper.h",
"Timer.cpp",
"Timer.h",
"UUID.cpp",
@@ -1824,6 +1826,7 @@ test("blink_platform_unittests") {
"PODRedBlackTreeTest.cpp",
"ScopedOrientationChangeIndicatorTest.cpp",
"SharedBufferTest.cpp",
+ "TimeClamperTest.cpp",
"TimerTest.cpp",
"UUIDTest.cpp",
"WebIconSizesParserTest.cpp",
diff --git a/chromium/third_party/WebKit/Source/platform/DEPS b/chromium/third_party/WebKit/Source/platform/DEPS
index b31a2ecbcd6..b026f2f9ff9 100644
--- a/chromium/third_party/WebKit/Source/platform/DEPS
+++ b/chromium/third_party/WebKit/Source/platform/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+base/bind_helpers.h",
"+base/callback.h",
"+base/callback_forward.h",
+ "+base/bit_cast.h",
"+base/feature_list.h",
"+base/files",
"+base/guid.h",
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..18244e769f3
--- /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 "platform/wtf/Assertions.h"
+#include "platform/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