Skip to content

Commit 3ffd36d

Browse files
committed
Cherry-pick fix for CVE-2015-1237
Clear RenderFrameImpl::frame_ pointer after deleting it. Also avoid dereferencing it in OnMessageReceived after deletion. BUG=461191 TEST=No more crashes in RenderFrameImpl::OnMessageReceived Review URL: https://codereview.chromium.org/1007123003 Change-Id: I0f2dcd9e9e78e4255f37ddaa8d5b75b0852d9521 Reviewed-by: Michael Brüning <[email protected]>
1 parent ec84d41 commit 3ffd36d

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

chromium/content/renderer/render_frame_impl.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,11 @@ void RenderFrameImpl::DidHideExternalPopupMenu() {
887887
#endif
888888

889889
bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
890+
// We may get here while detaching, when the WebFrame has been deleted. Do
891+
// not process any messages in this state.
892+
if (!frame_)
893+
return false;
894+
890895
// TODO(kenrb): document() should not be null, but as a transitional step
891896
// we have RenderFrameProxy 'wrapping' a RenderFrameImpl, passing messages
892897
// to this method. This happens for a top-level remote frame, where a
@@ -1932,8 +1937,11 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
19321937
if (is_subframe)
19331938
frame->parent()->removeChild(frame);
19341939

1935-
// |frame| is invalid after here.
1940+
// |frame| is invalid after here. Be sure to clear frame_ as well, since this
1941+
// object may not be deleted immediately and other methods may try to access
1942+
// it.
19361943
frame->close();
1944+
frame_ = nullptr;
19371945

19381946
if (is_subframe) {
19391947
delete this;

chromium/content/renderer/render_frame_impl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,10 @@ class CONTENT_EXPORT RenderFrameImpl
678678
RendererCdmManager* GetCdmManager();
679679
#endif
680680

681-
// Stores the WebLocalFrame we are associated with.
681+
// Stores the WebLocalFrame we are associated with. This is null from the
682+
// constructor until SetWebFrame is called, and it is null after
683+
// frameDetached is called until destruction (which is asynchronous in the
684+
// case of the main frame, but not subframes).
682685
blink::WebLocalFrame* frame_;
683686

684687
base::WeakPtr<RenderViewImpl> render_view_;

chromium/content/renderer/render_view_browsertest.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,31 @@ class RenderViewImplTest : public RenderViewTest {
287287
scoped_ptr<MockKeyboard> mock_keyboard_;
288288
};
289289

290+
// Test for https://crbug.com/461191.
291+
TEST_F(RenderViewImplTest, RenderFrameMessageAfterDetach) {
292+
// Create a new main frame RenderFrame so that we don't interfere with the
293+
// shutdown of frame() in RenderViewTest.TearDown.
294+
blink::WebURLRequest popup_request(GURL("http://foo.com"));
295+
blink::WebView* new_web_view = view()->createView(
296+
GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
297+
blink::WebNavigationPolicyNewForegroundTab, false);
298+
RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
299+
RenderFrameImpl* new_frame =
300+
static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame());
301+
302+
// Detach the main frame.
303+
new_view->Close();
304+
305+
// Before the frame is asynchronously deleted, it may receive a message.
306+
// We should not crash here, and the message should not be processed.
307+
scoped_ptr<const IPC::Message> msg(
308+
new FrameMsg_Stop(frame()->GetRoutingID()));
309+
EXPECT_FALSE(new_frame->OnMessageReceived(*msg));
310+
311+
// Clean up after the new view so we don't leak it.
312+
new_view->Release();
313+
}
314+
290315
TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
291316
const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
292317
ViewHostMsg_SaveImageFromDataURL::ID);

chromium/content/renderer/render_view_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ class CONTENT_EXPORT RenderViewImpl
562562
// code away from this class.
563563
friend class RenderFrameImpl;
564564

565+
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, RenderFrameMessageAfterDetach);
565566
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, DecideNavigationPolicyForWebUI);
566567
FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest,
567568
DidFailProvisionalLoadWithErrorForError);

0 commit comments

Comments
 (0)