Index: third_party/WebKit/Source/core/frame/History.cpp |
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp |
index 30ebcc037c8ef77fc46f2cb63e954175ea56360a..140f70118b9ad147c30681d12fabd8723953ee09 100644 |
--- a/third_party/WebKit/Source/core/frame/History.cpp |
+++ b/third_party/WebKit/Source/core/frame/History.cpp |
@@ -116,6 +116,28 @@ HistoryScrollRestorationType History::ScrollRestorationInternal() const { |
: kScrollRestorationAuto; |
} |
+// TODO(crbug.com/394296): This is not the long-term fix to IPC flooding that we |
+// need. However, it does somewhat mitigate the immediate concern of |pushState| |
+// and |replaceState| DoS (assuming the renderer has not been compromised). |
+bool History::ShouldThrottleStateObjectChanges() { |
+ const int kStateUpdateLimit = 50; |
+ |
+ if (state_flood_guard.count > kStateUpdateLimit) { |
+ static constexpr auto kStateUpdateLimitResetInterval = |
+ TimeDelta::FromSeconds(10); |
+ const auto now = TimeTicks::Now(); |
+ if (now - state_flood_guard.last_updated > kStateUpdateLimitResetInterval) { |
+ state_flood_guard.count = 0; |
+ state_flood_guard.last_updated = now; |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ state_flood_guard.count++; |
+ return false; |
+} |
+ |
bool History::stateChanged() const { |
return last_state_object_requested_ != StateInternal(); |
} |
@@ -230,6 +252,9 @@ void History::StateObjectAdded(PassRefPtr<SerializedScriptValue> data, |
return; |
} |
+ if (ShouldThrottleStateObjectChanges()) |
+ return; |
+ |
GetFrame()->Loader().UpdateForSameDocumentNavigation( |
full_url, kSameDocumentNavigationHistoryApi, std::move(data), |
restoration_type, type, GetFrame()->GetDocument()); |