summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Klocek <michal.klocek@qt.io>2016-11-30 08:52:25 -0800
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-04-20 07:39:28 +0000
commit1db3712d835eda2032d1f04216d928587ecdb36b (patch)
tree76b1fade669886f07a5cdd00913c308d87e558ac
parent1feaad93afad5a93882859e950eaf948e3a83ff2 (diff)
[Backport] CVE-2017-5019
Fix UaF in RenderFrameImpl::OnBeforeUnload. BUG=666714 Review-Url: https://codereview.chromium.org/2514323003 Cr-Commit-Position: refs/heads/master@{#434226} (cherry picked from commit 0dd441a0007aa46917779e782ee9094f111a02b3) TBR=creis@chromium.org,thestig@chromium.org NOTRY=true NOPRESUBMIT=true Change-Id: I9a80342c23552be89ba952b5c0d841f4538099bb Review-Url: https://codereview.chromium.org/2541073002 Cr-Commit-Position: refs/branch-heads/2924@{#187} Cr-Branched-From: 3a87aecc31cd1ffe751dd72c04e5a96a1fc8108a-refs/heads/master@{#433059} Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--chromium/content/renderer/render_frame_impl.cc9
-rw-r--r--chromium/content/renderer/render_view_browsertest.cc58
2 files changed, 64 insertions, 3 deletions
diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc
index dfa128cb154..56e1adc3bf1 100644
--- a/chromium/content/renderer/render_frame_impl.cc
+++ b/chromium/content/renderer/render_frame_impl.cc
@@ -1470,12 +1470,15 @@ void RenderFrameImpl::OnBeforeUnload() {
// it.
CHECK(!frame_->parent());
+ // Save the routing_id, as the RenderFrameImpl can be deleted in
+ // dispatchBeforeUnloadEvent. See https://crbug.com/666714 for details.
+ int routing_id = routing_id_;
+
base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
bool proceed = frame_->dispatchBeforeUnloadEvent();
base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
- Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_, proceed,
- before_unload_start_time,
- before_unload_end_time));
+ RenderThread::Get()->Send(new FrameHostMsg_BeforeUnload_ACK(
+ routing_id, proceed, before_unload_start_time, before_unload_end_time));
}
void RenderFrameImpl::OnSwapOut(
diff --git a/chromium/content/renderer/render_view_browsertest.cc b/chromium/content/renderer/render_view_browsertest.cc
index 050d05fa8c8..5337dae887b 100644
--- a/chromium/content/renderer/render_view_browsertest.cc
+++ b/chromium/content/renderer/render_view_browsertest.cc
@@ -2578,6 +2578,64 @@ TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnNavigation) {
view()->historyForwardListCount() + 1);
}
+// IPC Listener that runs a callback when a console.log() is executed from
+// javascript.
+class ConsoleCallbackFilter : public IPC::Listener {
+ public:
+ explicit ConsoleCallbackFilter(
+ base::Callback<void(const base::string16&)> callback)
+ : callback_(callback) {}
+
+ bool OnMessageReceived(const IPC::Message& msg) override {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ConsoleCallbackFilter, msg)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidAddMessageToConsole,
+ OnDidAddMessageToConsole)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+ }
+
+ void OnDidAddMessageToConsole(int32_t,
+ const base::string16& message,
+ int32_t,
+ const base::string16&) {
+ callback_.Run(message);
+ }
+
+ private:
+ base::Callback<void(const base::string16&)> callback_;
+};
+
+// Tests that there's no UaF after dispatchBeforeUnloadEvent.
+// See https://crbug.com/666714.
+TEST_F(RenderViewImplTest, DispatchBeforeUnloadCanDetachFrame) {
+ LoadHTML(
+ "<script>window.onbeforeunload = function() { "
+ "window.console.log('OnBeforeUnload called'); }</script>");
+
+ // Creates a callback that swaps the frame when the 'OnBeforeUnload called'
+ // log is printed from the beforeunload handler.
+ std::unique_ptr<ConsoleCallbackFilter> callback_filter(
+ new ConsoleCallbackFilter(base::Bind(
+ [](RenderFrameImpl* frame, const base::string16& msg) {
+ // Makes sure this happens during the beforeunload handler.
+ EXPECT_EQ(base::UTF8ToUTF16("OnBeforeUnload called"), msg);
+
+ // Swaps the main frame.
+ frame->OnMessageReceived(FrameMsg_SwapOut(
+ frame->GetRoutingID(), 1, false, FrameReplicationState()));
+ },
+ base::Unretained(frame()))));
+ render_thread_->sink().AddFilter(callback_filter.get());
+
+ // Simulates a BeforeUnload IPC received from the browser.
+ frame()->OnMessageReceived(
+ FrameMsg_BeforeUnload(frame()->GetRoutingID(), false));
+
+ render_thread_->sink().RemoveFilter(callback_filter.get());
+}
+
TEST_F(RenderViewImplBlinkSettingsTest, Default) {
DoSetUp();
EXPECT_FALSE(settings()->viewportEnabled());