Have Safe Browsing consider a portal host dangerous if the portal contents are dangerous

Currently, we're showing a Safe Browsing interstitial just within the
portal. Safe Browsing treats embedders of dangerous iframes as dangerous
themselves. The same should presumably be the case for portals.

Now when a portal loads dangerous content, we load a post commit error
page in the top level contents to show the Safe Browsing interstitial.

Bug: 1077016
Change-Id: I8f6f47df91c41747c663a7def21512d6e73d7469
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2231858
Commit-Queue: Kevin McNee <[email protected]>
Reviewed-by: Varun Khaneja <[email protected]>
Reviewed-by: Carlos IL <[email protected]>
Reviewed-by: Charlie Reis <[email protected]>
Reviewed-by: Daniel Rubery <[email protected]>
Reviewed-by: Lucas Gadani <[email protected]>
Cr-Commit-Position: refs/heads/master@{#781410}
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index 30b227be..0dc69665 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -53,9 +53,8 @@
 }
 
 Portal::~Portal() {
-  WebContentsImpl* outer_contents_impl = static_cast<WebContentsImpl*>(
-      WebContents::FromRenderFrameHost(owner_render_frame_host_));
-  devtools_instrumentation::PortalDetached(outer_contents_impl->GetMainFrame());
+  devtools_instrumentation::PortalDetached(
+      GetPortalHostContents()->GetMainFrame());
   Observe(nullptr);
 }
 
@@ -118,8 +117,7 @@
 }
 
 RenderFrameProxyHost* Portal::CreateProxyAndAttachPortal() {
-  WebContentsImpl* outer_contents_impl = static_cast<WebContentsImpl*>(
-      WebContents::FromRenderFrameHost(owner_render_frame_host_));
+  WebContentsImpl* outer_contents_impl = GetPortalHostContents();
 
   // Check if portal has already been attached.
   if (portal_contents_ && portal_contents_->GetOuterWebContents()) {
@@ -309,8 +307,7 @@
 void Portal::Activate(blink::TransferableMessage data,
                       base::TimeTicks activation_time,
                       ActivateCallback callback) {
-  WebContentsImpl* outer_contents = static_cast<WebContentsImpl*>(
-      WebContents::FromRenderFrameHost(owner_render_frame_host_));
+  WebContentsImpl* outer_contents = GetPortalHostContents();
 
   if (outer_contents->portal()) {
     mojo::ReportBadMessage("Portal::Activate called on nested portal");
@@ -525,8 +522,7 @@
 }
 
 void Portal::PortalWebContentsCreated(WebContents* portal_web_contents) {
-  WebContentsImpl* outer_contents = static_cast<WebContentsImpl*>(
-      WebContents::FromRenderFrameHost(owner_render_frame_host_));
+  WebContentsImpl* outer_contents = GetPortalHostContents();
   DCHECK(outer_contents->GetDelegate());
   outer_contents->GetDelegate()->PortalWebContentsCreated(portal_web_contents);
 }
@@ -537,13 +533,12 @@
 }
 
 WebContents* Portal::GetResponsibleWebContents(WebContents* web_contents) {
-  return WebContents::FromRenderFrameHost(owner_render_frame_host_);
+  return GetPortalHostContents();
 }
 
 void Portal::NavigationStateChanged(WebContents* source,
                                     InvalidateTypes changed_flags) {
-  WebContents* outer_contents =
-      WebContents::FromRenderFrameHost(owner_render_frame_host_);
+  WebContents* outer_contents = GetPortalHostContents();
   // Can be null in tests.
   if (!outer_contents->GetDelegate())
     return;
@@ -569,6 +564,11 @@
   return portal_contents_.get();
 }
 
+WebContentsImpl* Portal::GetPortalHostContents() {
+  return static_cast<WebContentsImpl*>(
+      WebContents::FromRenderFrameHost(owner_render_frame_host_));
+}
+
 Portal::WebContentsHolder::WebContentsHolder(Portal* portal)
     : portal_(portal) {}
 
diff --git a/content/browser/portal/portal.h b/content/browser/portal/portal.h
index b8ae679..ed6a3701 100644
--- a/content/browser/portal/portal.h
+++ b/content/browser/portal/portal.h
@@ -117,6 +117,8 @@
 
   // Returns the Portal's WebContents.
   WebContentsImpl* GetPortalContents();
+  // Returns the WebContents that hosts this portal.
+  WebContentsImpl* GetPortalHostContents();
 
   RenderFrameHostImpl* owner_render_frame_host() {
     return owner_render_frame_host_;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 36a6d0a1..33072ec 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -73,6 +73,7 @@
 #include "content/browser/media/media_web_contents_observer.h"
 #include "content/browser/media/session/media_session_impl.h"
 #include "content/browser/plugin_content_origin_allowlist.h"
+#include "content/browser/portal/portal.h"
 #include "content/browser/renderer_host/frame_token_message_queue.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
@@ -5272,6 +5273,10 @@
   return portal();
 }
 
+WebContentsImpl* WebContentsImpl::GetPortalHostWebContents() {
+  return portal() ? portal()->GetPortalHostContents() : nullptr;
+}
+
 void WebContentsImpl::NotifyBeforeFormRepostWarningShow() {
   for (auto& observer : observers_)
     observer.BeforeFormRepostWarningShow();
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index e9a2a0e..5209401 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -400,6 +400,7 @@
                               bool is_full_page) override;
   bool IsInnerWebContentsForGuest() override;
   bool IsPortal() override;
+  WebContentsImpl* GetPortalHostWebContents() override;
   RenderFrameHostImpl* GetOuterWebContentsFrame() override;
   WebContentsImpl* GetOuterWebContents() override;
   WebContentsImpl* GetOutermostWebContents() override;