Chromium Code Reviews| Index: content/browser/security_exploit_browsertest.cc |
| diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc |
| index 2eb7b51885b48168df9a248d249eee2bc44195dd..8ead1c3f812b26b19280666e0cbf8d373733e479 100644 |
| --- a/content/browser/security_exploit_browsertest.cc |
| +++ b/content/browser/security_exploit_browsertest.cc |
| @@ -3,11 +3,19 @@ |
| // found in the LICENSE file. |
| #include "base/command_line.h" |
| +#include "base/containers/hash_tables.h" |
| +#include "content/browser/dom_storage/dom_storage_context_wrapper.h" |
| +#include "content/browser/dom_storage/session_storage_namespace_impl.h" |
| +#include "content/browser/renderer_host/render_view_host_factory.h" |
| #include "content/browser/renderer_host/render_view_host_impl.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| +#include "content/common/view_messages.h" |
| +#include "content/public/browser/browser_context.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_types.h" |
| +#include "content/public/browser/storage_partition.h" |
| #include "content/public/common/content_switches.h" |
| +#include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/test/content_browser_test.h" |
| @@ -52,4 +60,122 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, SetWebUIProperty) { |
| terminated.Wait(); |
| } |
| +// RenderViewHostFactory object which tracks creations of RenderViewHost objects |
| +// to ensure there are no duplicates. It is used by the following |
| +// AttemptDuplicateRVH test case. |
| +class TrackingRenderViewHostFactory : public RenderViewHostFactory { |
| + public: |
| + TrackingRenderViewHostFactory() : has_duplicates_(false) { |
| + RegisterFactory(this); |
| + } |
| + |
| + virtual ~TrackingRenderViewHostFactory() { |
| + UnregisterFactory(); |
| + } |
| + |
| + // RenderViewHostFactory implementation. |
| + virtual RenderViewHost* CreateRenderViewHost( |
| + SiteInstance* instance, |
| + RenderViewHostDelegate* delegate, |
| + RenderWidgetHostDelegate* widget_delegate, |
| + int routing_id, |
| + int main_frame_routing_id, |
| + bool swapped_out) OVERRIDE { |
| + std::pair<int, int> id = std::make_pair( |
| + instance->GetProcess()->GetID(), routing_id); |
| + |
| + DuplicatesSet::iterator it = rvh_map_.find(id); |
| + if (it != rvh_map_.end()) |
| + has_duplicates_ = true; |
| + |
| + RenderViewHostImpl* rvh = new RenderViewHostImpl( |
| + instance, delegate, widget_delegate, routing_id, main_frame_routing_id, |
| + swapped_out, false); |
| + rvh_map_.insert(id); |
| + |
| + return rvh; |
| + } |
| + |
| + bool has_duplicates() { |
| + return has_duplicates_; |
| + } |
| + |
| + private: |
| + typedef base::hash_set<std::pair<int,int> > DuplicatesSet; |
|
Charlie Reis
2013/12/02 22:25:34
nit: DuplicatesSet -> IDSet
(It doesn't actually
nasko
2013/12/02 22:51:08
Done.
|
| + DuplicatesSet rvh_map_; |
|
Charlie Reis
2013/12/02 22:25:34
nit: rvh_map_ isn't the right name anymore. rvh_i
nasko
2013/12/02 22:51:08
Done.
|
| + |
| + bool has_duplicates_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TrackingRenderViewHostFactory); |
| +}; |
| + |
| +// This is a test for crbug.com/312016. It tries to create two RenderViewHosts |
| +// with the same process and routing ids, which causes a collision. |
| +// It creates a couple of windows in process 1, which causes a few routing ids |
| +// to be allocated. Then a cross-process navigation is initiated, which causes a |
| +// new process 2 to be created and have a pending RenderViewHost for it. |
| +// Before the commit of the new pending RenderViewHost, it creates a new window |
| +// through process 2. The original bug caused the new window RenderViewHost |
| +// to be created in process 1 with a routing id which has already been |
| +// allocated. |
| +IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, AttemptDuplicateRVH) { |
| + TrackingRenderViewHostFactory rvh_factory; |
| + GURL foo("http://foo.com/files/simple_page.html"); |
| + |
| + // Start off with initial navigation, so we get the first process allocated. |
| + NavigateToURL(shell(), foo); |
| + |
| + // Open another window, so we generate some more routing ids. |
| + ShellAddedObserver shell2_observer; |
| + EXPECT_TRUE(ExecuteScript( |
| + shell()->web_contents(), "window.open(document.URL + '#2');")); |
| + Shell* shell2 = shell2_observer.GetShell(); |
| + |
| + // The new window must be in the same process, but have a new routing id. |
| + EXPECT_EQ(shell()->web_contents()->GetRenderViewHost()->GetProcess()->GetID(), |
| + shell2->web_contents()->GetRenderViewHost()->GetProcess()->GetID()); |
| + int window2_routing_id = |
| + shell2->web_contents()->GetRenderViewHost()->GetRoutingID(); |
| + EXPECT_NE(window2_routing_id, |
| + shell()->web_contents()->GetRenderViewHost()->GetRoutingID()); |
| + |
| + // Now, simulate a link click coming from the renderer. |
| + GURL extension_url("https://bar.com/files/simple_page.html"); |
| + WebContentsImpl* wc = static_cast<WebContentsImpl*>( |
| + shell()->web_contents()); |
| + wc->RequestOpenURL( |
| + shell()->web_contents()->GetRenderViewHost(), extension_url, |
| + Referrer(), CURRENT_TAB, wc->GetFrameTree()->root()->frame_id(), |
| + false, true); |
| + |
| + // Since the navigation above requires a cross-process swap, there will be a |
| + // pending RenderViewHost. Ensure it exists and is in a different process |
| + // than the initial page. |
| + RenderViewHostImpl* pending_rvh = |
| + wc->GetRenderManagerForTesting()->pending_render_view_host(); |
| + EXPECT_TRUE(pending_rvh != NULL); |
| + EXPECT_NE(shell()->web_contents()->GetRenderViewHost()->GetProcess()->GetID(), |
| + pending_rvh->GetProcess()->GetID()); |
| + |
| + // Since this test executes on the UI thread and hopping threads might cause |
| + // different timing in the test, let's simulate a CreateNewWindow call coming |
| + // from the IO thread. |
| + ViewHostMsg_CreateWindow_Params params; |
| + DOMStorageContextWrapper* dom_storage_context = |
| + static_cast<DOMStorageContextWrapper*>( |
| + BrowserContext::GetStoragePartition( |
| + wc->GetBrowserContext(), |
| + pending_rvh->GetSiteInstance())->GetDOMStorageContext()); |
| + SessionStorageNamespaceImpl* session_storage = |
| + new SessionStorageNamespaceImpl(dom_storage_context); |
| + // Cause a deliberate collision in routing ids. |
| + int routing_id = window2_routing_id; |
| + int main_frame_routing_id = routing_id + 1; |
| + |
| + pending_rvh->CreateNewWindow( |
| + routing_id, main_frame_routing_id, params, session_storage); |
| + |
| + EXPECT_FALSE(rvh_factory.has_duplicates()); |
| } |
| + |
| +} // namespace content |