Allow non-WebUI navigations in single-process mode

WebUINavigationThrottle blocks WebUI (chrome://...) pages from loading
non-WebUI pages in subframes.

When a renderer navigates to a WebUI page, a "WebUI bindings" bit is set
in that renderer's ChildProcessSecurityPolicyImpl::SecurityState, and it
remains for the lifetime of the renderer process.
WebUINavigationThrottles are created for renderers with this bit set.

In multi-process mode, navigating away from the WebUI page creates a
fresh renderer with a fresh SecurityState, so subsequent non-WebUI pages
are again able to load non-WebUI subframes.

In single-process mode, the WebUI bit remains. After visiting a WebUI
page, iframes on all other pages will be broken until Chrome is

This breaks Android WebView as well, since WebView uses single-process
on old Android versions and low-memory devices. It breaks CTS because
testOnSafeBrowsingHit loads chrome://safe-browsing/match?type=malware,
which sets the bit, and then testShouldOverrideUrlLoadingOnCreateWindow
tries to use an iframe.

Fix this by not creating a WebUINavigationThrottle in single-process


Change-Id: I5a61f45dc065681f0e6b97e0b205e804edbd7402
Commit-Queue: Paul Miller <>
Reviewed-by: Nasko Oskov <>
Cr-Original-Commit-Position: refs/heads/master@{#626267}(cherry picked from commit 8a5d9397e612ca062c702a0f8f017db516790b85)
Reviewed-by: Paul Miller <>
Cr-Commit-Position: refs/branch-heads/3683@{#176}
Cr-Branched-From: e51029943e0a38dd794b73caaf6373d5496ae783-refs/heads/master@{#625896}
diff --git a/content/browser/frame_host/ b/content/browser/frame_host/
index 625b1cb1..90c03d6 100644
--- a/content/browser/frame_host/
+++ b/content/browser/frame_host/
@@ -4,10 +4,12 @@
 #include "content/browser/frame_host/webui_navigation_throttle.h"
+#include "base/command_line.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 namespace content {
@@ -35,7 +37,13 @@
     NavigationHandle* navigation_handle) {
-  // Create the throttle only for subframe navigations.
+  // The WebUI security model (which keeps renderes with WebUI bindings separate
+  // from untrusted renderers) only makes sense in multi-process mode.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess))
+    return nullptr;
+  // Only throttle subframe navigations.
   if (navigation_handle->IsInMainFrame())
     return nullptr;
@@ -45,8 +53,8 @@
-  // Create a throttle only for navigations where the parent frame is either
-  // at a chrome:// URL or is in a process with WebUI bindings.
+  // Throttle if the renderer process has WebUI bindings, or if the parent frame
+  // is on a WebUI page.
   if (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
           parent->GetProcess()->GetID()) ||
       parent->GetLastCommittedURL().SchemeIs(kChromeUIScheme)) {