Commit 88ca1797 authored by Antonio Sartori's avatar Antonio Sartori Committed by Commit Bot

Attach PolicyContainer to RenderFrameHostImpl

The PolicyContainer will serve as a container for security policies
(such as Content-Security-Policy, Referrer Policy, COOP, COEP) that
are applied to a document and have similar lifecycles.

This is the first of a series of CLs implementing the
PolicyContainer. We define a PolicyContainer class in content and
attach a PolicyContainer to each RenderFrameHostImpl.

Change-Id: Ief6d3b342c3f458aa21b53bee265732e65f3bd1e
Bug: 1130587
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2418316
Commit-Queue: Antonio Sartori <antoniosartori@chromium.org>
Reviewed-by: default avatarNasko Oskov <nasko@chromium.org>
Reviewed-by: default avatarArthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: default avatarPâris Meuleman <pmeuleman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815505}
parent 2206cb50
...@@ -1471,6 +1471,8 @@ source_set("browser") { ...@@ -1471,6 +1471,8 @@ source_set("browser") {
"renderer_host/p2p/socket_dispatcher_host.h", "renderer_host/p2p/socket_dispatcher_host.h",
"renderer_host/page_lifecycle_state_manager.cc", "renderer_host/page_lifecycle_state_manager.cc",
"renderer_host/page_lifecycle_state_manager.h", "renderer_host/page_lifecycle_state_manager.h",
"renderer_host/policy_container.cc",
"renderer_host/policy_container.h",
"renderer_host/raw_clipboard_host_impl.cc", "renderer_host/raw_clipboard_host_impl.cc",
"renderer_host/raw_clipboard_host_impl.h", "renderer_host/raw_clipboard_host_impl.h",
"renderer_host/render_frame_host_delegate.cc", "renderer_host/render_frame_host_delegate.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/policy_container.h"
namespace content {
PolicyContainer::PolicyContainer() = default;
PolicyContainer::PolicyContainer(network::mojom::ReferrerPolicy referrer_policy)
: referrer_policy_(referrer_policy) {}
void PolicyContainer::SetReferrerPolicy(
network::mojom::ReferrerPolicy referrer_policy) {
referrer_policy_ = referrer_policy;
}
std::unique_ptr<PolicyContainer> PolicyContainer::Clone() const {
std::unique_ptr<PolicyContainer> copy =
std::make_unique<PolicyContainer>(referrer_policy());
return copy;
}
} // namespace content
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_POLICY_CONTAINER_H_
#define CONTENT_BROWSER_RENDERER_HOST_POLICY_CONTAINER_H_
#include "content/common/content_export.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
namespace content {
// PolicyContainer serves as a container for several security policies. It
// should be owned by a RenderFrameHost. It keep tracks of the policies assigned
// to a document. When a document creates/opens another document with a local
// scheme (about:blank, about:srcdoc, data, blob, filesystem), the policy
// container of the opener is cloned and a copy is attached to the new document,
// so that the same security policies are applied to it.
class CONTENT_EXPORT PolicyContainer {
public:
PolicyContainer();
explicit PolicyContainer(network::mojom::ReferrerPolicy referrer_policy);
PolicyContainer(const PolicyContainer&) = delete;
PolicyContainer& operator=(const PolicyContainer&) = delete;
void SetReferrerPolicy(network::mojom::ReferrerPolicy referrer_policy);
network::mojom::ReferrerPolicy referrer_policy() const {
return referrer_policy_;
}
std::unique_ptr<PolicyContainer> Clone() const;
private:
// The referrer policy for the associated document. If not overwritten via a
// call to SetReferrerPolicy (for example after parsing the Referrer-Policy
// header or a meta tag), the default referrer policy will be applied to the
// document.
network::mojom::ReferrerPolicy referrer_policy_ =
network::mojom::ReferrerPolicy::kDefault;
};
} // namespace content
#endif
...@@ -986,6 +986,41 @@ RenderFrameHostImpl::RenderFrameHostImpl( ...@@ -986,6 +986,41 @@ RenderFrameHostImpl::RenderFrameHostImpl(
set_nav_entry_id(parent_->nav_entry_id()); set_nav_entry_id(parent_->nav_entry_id());
} }
// The initial empty document inherits its policy container from its creator.
// The creator is either its parent for iframes or its opener for new windows.
//
// Note 1: For normal document created from a navigation, the policy container
// is computed from the NavigationRequest and assigned in
// DidCommitNewDocument().
//
// Note 2: After creating a new frame, blink emits a second IPC
// (DidCommitProvisionalLoad) for committing the initial empty
// document. However, since the RenderFrameHost has already been created, we
// cannot use DidCommitProvisionalLoad to set the policy container, since we
// could run into a race condition. Hence we need to set The policy container
// immediately when creating the RenderFrameHost here.
if (!frame_tree_node_->has_committed_real_load()) {
if (parent_) {
// TODO(antoniosartori): Remove this check as soon as we are able to
// always ensure that then parent RFH has a policy container.
if (parent_->policy_container())
policy_container_ = parent_->policy_container()->Clone();
} else if (frame_tree_node_->opener()) {
// TODO(antoniosartori): Remove this check as soon as we are able to
// always ensure that then opener RFH has a policy container.
if (frame_tree_node_->opener()
->current_frame_host()
->policy_container()) {
policy_container_ = frame_tree_node_->opener()
->current_frame_host()
->policy_container()
->Clone();
}
} else {
policy_container_ = std::make_unique<PolicyContainer>();
}
}
SetUpMojoIfNeeded(); SetUpMojoIfNeeded();
unload_event_monitor_timeout_ = unload_event_monitor_timeout_ =
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "content/browser/renderer_host/back_forward_cache_metrics.h" #include "content/browser/renderer_host/back_forward_cache_metrics.h"
#include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h" #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
#include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h" #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
#include "content/browser/renderer_host/policy_container.h"
#include "content/browser/renderer_host/should_swap_browsing_instance.h" #include "content/browser/renderer_host/should_swap_browsing_instance.h"
#include "content/browser/site_instance_impl.h" #include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_impl.h" #include "content/browser/webui/web_ui_impl.h"
...@@ -1488,6 +1489,8 @@ class CONTENT_EXPORT RenderFrameHostImpl ...@@ -1488,6 +1489,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
return required_csp_.get(); return required_csp_.get();
} }
PolicyContainer* policy_container() { return policy_container_.get(); }
// This function mimics DidCommitProvisionalLoad for navigations served from // This function mimics DidCommitProvisionalLoad for navigations served from
// the back-forward cache. // the back-forward cache.
void DidCommitBackForwardCacheNavigation( void DidCommitBackForwardCacheNavigation(
...@@ -3236,6 +3239,14 @@ class CONTENT_EXPORT RenderFrameHostImpl ...@@ -3236,6 +3239,14 @@ class CONTENT_EXPORT RenderFrameHostImpl
// stored when the frame commits the navigation. // stored when the frame commits the navigation.
network::mojom::ContentSecurityPolicyPtr required_csp_; network::mojom::ContentSecurityPolicyPtr required_csp_;
// The policy container for the current document, containing security policies
// that apply to it. It should never be null if the RenderFrameHost is
// displaying a document. Its lifetime should coincide with the lifetime of
// the document displayed in the RenderFrameHost. It is overwritten at
// navigation commit time in DidCommitNewDocument with the policy container of
// the new document.
std::unique_ptr<PolicyContainer> policy_container_;
// NOTE: This must be the last member. // NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_{this}; base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_{this};
......
...@@ -99,4 +99,40 @@ TEST_F(RenderFrameHostImplTest, CreateFullscreenWidget) { ...@@ -99,4 +99,40 @@ TEST_F(RenderFrameHostImplTest, CreateFullscreenWidget) {
mojo::PendingAssociatedRemote<blink::mojom::Widget>(), base::DoNothing()); mojo::PendingAssociatedRemote<blink::mojom::Widget>(), base::DoNothing());
} }
TEST_F(RenderFrameHostImplTest, PolicyContainerLifecycle) {
TestRenderFrameHost* main_rfh = contents()->GetMainFrame();
ASSERT_NE(main_rfh->policy_container(), nullptr);
EXPECT_EQ(main_rfh->policy_container()->referrer_policy(),
network::mojom::ReferrerPolicy::kDefault);
main_rfh->policy_container()->SetReferrerPolicy(
network::mojom::ReferrerPolicy::kAlways);
EXPECT_EQ(main_rfh->policy_container()->referrer_policy(),
network::mojom::ReferrerPolicy::kAlways);
// Create a child frame and check that it inherits the policy container from
// the parent frame.
auto* child_frame = static_cast<TestRenderFrameHost*>(
content::RenderFrameHostTester::For(main_test_rfh())
->AppendChild("child"));
ASSERT_NE(child_frame->policy_container(), nullptr);
EXPECT_EQ(child_frame->policy_container()->referrer_policy(),
network::mojom::ReferrerPolicy::kAlways);
// Create a new WebContents with opener and test that the new main frame
// inherits the policy container from the opener.
child_frame->policy_container()->SetReferrerPolicy(
network::mojom::ReferrerPolicy::kNever);
WebContents::CreateParams params(browser_context());
std::unique_ptr<WebContentsImpl> new_contents(
WebContentsImpl::CreateWithOpener(params, child_frame));
RenderFrameHostImpl* new_frame =
new_contents->GetFrameTree()->root()->current_frame_host();
ASSERT_NE(new_frame->policy_container(), nullptr);
EXPECT_EQ(new_frame->policy_container()->referrer_policy(),
network::mojom::ReferrerPolicy::kNever);
}
} // namespace content } // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment