1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/mojo_binder_policy_map_impl.h"
#include <string_view>
#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "content/common/dom_automation_controller.mojom.h"
#include "content/common/frame.mojom.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/mojo_binder_policy_map.h"
#include "content/public/common/content_client.h"
#include "device/gamepad/public/mojom/gamepad.mojom.h"
#include "media/mojo/mojom/media_player.mojom.h"
#include "media/mojo/mojom/webrtc_video_perf.mojom.h"
#include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
#include "third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom.h"
#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h"
#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
#include "third_party/blink/public/mojom/file/file_utilities.mojom.h"
#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom.h"
#include "third_party/blink/public/mojom/frame/frame.mojom.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
#include "third_party/blink/public/mojom/loader/fetch_later.mojom.h"
#if BUILDFLAG(IS_MAC)
#include "third_party/blink/public/mojom/input/text_input_host.mojom.h"
#endif
#include "third_party/blink/public/mojom/loader/code_cache.mojom.h"
#include "third_party/blink/public/mojom/manifest/manifest_observer.mojom.h"
#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom.h"
#include "third_party/blink/public/mojom/notifications/notification_service.mojom.h"
#include "third_party/blink/public/mojom/page/display_cutout.mojom.h"
namespace content {
#if BUILDFLAG(IS_MAC)
// Put crbug.com/115920 fix under flag, so we can measure its CWV impact.
BASE_FEATURE(kTextInputHostMojoCapabilityControlWorkaround,
"TextInputHostMojoCapabilityControlWorkaround",
base::FEATURE_ENABLED_BY_DEFAULT);
#endif
namespace {
enum class PolicyClass {
kSameOriginPrerendering,
kPreview,
};
// Register feature specific policies for interfaces registered in
// `internal::PopulateBinderMap` and `internal::PopulateBinderMapWithContext`.
void RegisterNonAssociatedPolicies(MojoBinderPolicyMap& map,
PolicyClass policy) {
// For Prerendering, kCancel is usually used for those interfaces that cannot
// be granted because they can cause undesirable side-effects (e.g., playing
// audio, showing notification) and are non-deferrable.
// Please update `PrerenderCancelledInterface` and
// `GetCancelledInterfaceType()` in
// content/browser/preloading/prerender/prerender_metrics.h once you add a new
// kCancel interface.
map.SetNonAssociatedPolicy<device::mojom::GamepadHapticsManager>(
MojoBinderNonAssociatedPolicy::kCancel);
map.SetNonAssociatedPolicy<device::mojom::GamepadMonitor>(
MojoBinderNonAssociatedPolicy::kCancel);
if (policy == PolicyClass::kSameOriginPrerendering) {
// ClipboardHost has sync messages, so it cannot be kDefer. However, the
// renderer is not expected to request the interface; prerendering documents
// do not have system focus nor user activation, which is required before
// sending the request.
map.SetNonAssociatedPolicy<blink::mojom::ClipboardHost>(
MojoBinderNonAssociatedPolicy::kUnexpected);
}
// FileUtilitiesHost is only used by APIs that require user activations, being
// impossible for a prerendered document. For the reason, this is marked as
// kUnexpected.
map.SetNonAssociatedPolicy<blink::mojom::FileUtilitiesHost>(
MojoBinderNonAssociatedPolicy::kUnexpected);
map.SetNonAssociatedPolicy<blink::mojom::CacheStorage>(
MojoBinderNonAssociatedPolicy::kGrant);
map.SetNonAssociatedPolicy<blink::mojom::IDBFactory>(
MojoBinderNonAssociatedPolicy::kGrant);
// Grant this interface because some sync web APIs rely on it; deferring it
// leads to deadlock. However, granting this interface does not mean that
// prerenders are allowed to create output streams.
// RenderFrameAudioOutputStreamFactory understands which pages are
// prerendering and does not fulfill their requests for audio streams.
map.SetNonAssociatedPolicy<blink::mojom::RendererAudioOutputStreamFactory>(
MojoBinderNonAssociatedPolicy::kGrant);
map.SetNonAssociatedPolicy<network::mojom::RestrictedCookieManager>(
MojoBinderNonAssociatedPolicy::kGrant);
// Set policy to Grant for CodeCacheHost. Without this loads won't progress
// since we wait for a response from code cache when loading resources.
map.SetNonAssociatedPolicy<blink::mojom::CodeCacheHost>(
MojoBinderNonAssociatedPolicy::kGrant);
// Grant this for Media Capabilities APIs. This should be safe as the APIs
// just query encoding / decoding information.
map.SetNonAssociatedPolicy<media::mojom::WebrtcVideoPerfHistory>(
content::MojoBinderNonAssociatedPolicy::kGrant);
#if BUILDFLAG(IS_MAC)
// Set policy to Grant for TextInputHost.
// This is used to return macOS IME sync call results to the browser process,
// and will hang entire Chrome if paused.
// This is a prospective fix added for crbug.com/1480850
if (base::FeatureList::IsEnabled(
kTextInputHostMojoCapabilityControlWorkaround)) {
map.SetNonAssociatedPolicy<blink::mojom::TextInputHost>(
MojoBinderNonAssociatedPolicy::kGrant);
}
#endif
}
// Register same-origin prerendering policies for channel-associated interfaces
// registered in `RenderFrameHostImpl::SetUpMojoIfNeeded()`.
void RegisterChannelAssociatedPoliciesForSameOriginPrerendering(
MojoBinderPolicyMap& map) {
// Basic skeleton. All of them are critical to load a page so their policies
// have to be kGrant.
// TODO(crbug.com/40201285): Message-level control should be performed.
map.SetAssociatedPolicy<mojom::FrameHost>(MojoBinderAssociatedPolicy::kGrant);
map.SetAssociatedPolicy<blink::mojom::LocalFrameHost>(
MojoBinderAssociatedPolicy::kGrant);
map.SetAssociatedPolicy<blink::mojom::LocalMainFrameHost>(
MojoBinderAssociatedPolicy::kGrant);
// These interfaces do not leak sensitive information.
map.SetAssociatedPolicy<blink::mojom::BackForwardCacheControllerHost>(
MojoBinderAssociatedPolicy::kGrant);
map.SetAssociatedPolicy<blink::mojom::ManifestUrlChangeObserver>(
MojoBinderAssociatedPolicy::kGrant);
map.SetAssociatedPolicy<mojom::DomAutomationControllerHost>(
MojoBinderAssociatedPolicy::kGrant);
// BroadcastChannel is granted for prerendering, as this API is restricted to
// same-origin.
map.SetAssociatedPolicy<blink::mojom::BroadcastChannelProvider>(
MojoBinderAssociatedPolicy::kGrant);
// Granting this interface does not mean prerendering pages are allowed to
// play media. Feature-specific capability control is implemented to delay
// playing media. See `RenderFrameImpl::DeferMediaLoad` for more information.
map.SetAssociatedPolicy<media::mojom::MediaPlayerHost>(
MojoBinderAssociatedPolicy::kGrant);
// DisplayCutout supports the CSS viewport-fit property. It tracks
// the current viewport-fit on a per-document basis, but only calls
// the WebContents::NotifyViewportFitChanged and informs WebContents's
// observers when the document is fullscreened. Prerendered documents cannot
// enter fullscreen because they do not have transient activation, nor are
// they active documents (see RenderFrameHostImpl::EnterFullscreen), so it is
// safe to allow a prerendered document to use it.
map.SetAssociatedPolicy<blink::mojom::DisplayCutoutHost>(
MojoBinderAssociatedPolicy::kGrant);
// Prerendering pages are allowed to create urls for blobs.
map.SetAssociatedPolicy<blink::mojom::BlobURLStore>(
MojoBinderAssociatedPolicy::kGrant);
// Pages with FetchLater API calls should be allowed to prerender.
// TODO(crbug.com/40276121): Update according to feedback from
// https://github.com/WICG/pending-beacon/issues/82
map.SetAssociatedPolicy<blink::mojom::FetchLaterLoaderFactory>(
MojoBinderAssociatedPolicy::kGrant);
}
// Register mojo binder policies for same-origin prerendering for content/
// interfaces.
void RegisterContentBinderPoliciesForSameOriginPrerendering(
MojoBinderPolicyMap& map) {
RegisterNonAssociatedPolicies(map, PolicyClass::kSameOriginPrerendering);
RegisterChannelAssociatedPoliciesForSameOriginPrerendering(map);
}
// Register mojo binder policies for preview mode for content/ interfaces.
void RegisterContentBinderPoliciesForPreview(MojoBinderPolicyMap& map) {
RegisterNonAssociatedPolicies(map, PolicyClass::kPreview);
// Inherits the policies for same-origin prerendering.
// TODO(b:299240273): Adjust policies for preview.
RegisterChannelAssociatedPoliciesForSameOriginPrerendering(map);
}
// A singleton class that stores the `MojoBinderPolicyMap` of interfaces which
// are obtained via `BrowserInterfaceBrowser` for frames.
// content/ initializes the policy map with predefined policies, then allows
// embedders to update the map.
class BrowserInterfaceBrokerMojoBinderPolicyMapHolder {
public:
BrowserInterfaceBrokerMojoBinderPolicyMapHolder() {
RegisterContentBinderPoliciesForSameOriginPrerendering(same_origin_map_);
GetContentClient()
->browser()
->RegisterMojoBinderPoliciesForSameOriginPrerendering(same_origin_map_);
RegisterContentBinderPoliciesForPreview(preview_map_);
GetContentClient()->browser()->RegisterMojoBinderPoliciesForPreview(
preview_map_);
}
~BrowserInterfaceBrokerMojoBinderPolicyMapHolder() = default;
// Remove copy and move operations.
BrowserInterfaceBrokerMojoBinderPolicyMapHolder(
const BrowserInterfaceBrokerMojoBinderPolicyMapHolder& other) = delete;
BrowserInterfaceBrokerMojoBinderPolicyMapHolder& operator=(
const BrowserInterfaceBrokerMojoBinderPolicyMapHolder& other) = delete;
BrowserInterfaceBrokerMojoBinderPolicyMapHolder(
BrowserInterfaceBrokerMojoBinderPolicyMapHolder&&) = delete;
BrowserInterfaceBrokerMojoBinderPolicyMapHolder& operator=(
BrowserInterfaceBrokerMojoBinderPolicyMapHolder&&) = delete;
const MojoBinderPolicyMapImpl* GetSameOriginPolicyMap() const {
return &same_origin_map_;
}
const MojoBinderPolicyMapImpl* GetPreviewPolicyMap() const {
return &preview_map_;
}
private:
// TODO(crbug.com/40156088): Set default policy map for content/.
// Changes to `same_origin_map_` require security review.
MojoBinderPolicyMapImpl same_origin_map_;
MojoBinderPolicyMapImpl preview_map_;
};
} // namespace
MojoBinderPolicyMapImpl::MojoBinderPolicyMapImpl() = default;
MojoBinderPolicyMapImpl::MojoBinderPolicyMapImpl(
const base::flat_map<std::string, MojoBinderNonAssociatedPolicy>& init_map)
: non_associated_policy_map_(init_map) {}
MojoBinderPolicyMapImpl::~MojoBinderPolicyMapImpl() = default;
const MojoBinderPolicyMapImpl*
MojoBinderPolicyMapImpl::GetInstanceForSameOriginPrerendering() {
static const base::NoDestructor<
BrowserInterfaceBrokerMojoBinderPolicyMapHolder>
map;
return map->GetSameOriginPolicyMap();
}
const MojoBinderPolicyMapImpl*
MojoBinderPolicyMapImpl::GetInstanceForPreview() {
static const base::NoDestructor<
BrowserInterfaceBrokerMojoBinderPolicyMapHolder>
map;
return map->GetPreviewPolicyMap();
}
MojoBinderNonAssociatedPolicy
MojoBinderPolicyMapImpl::GetNonAssociatedMojoBinderPolicy(
const std::string& interface_name,
const MojoBinderNonAssociatedPolicy default_policy) const {
const auto& found = non_associated_policy_map_.find(interface_name);
if (found != non_associated_policy_map_.end())
return found->second;
return default_policy;
}
MojoBinderAssociatedPolicy
MojoBinderPolicyMapImpl::GetAssociatedMojoBinderPolicy(
const std::string& interface_name,
const MojoBinderAssociatedPolicy default_policy) const {
const auto& found = associated_policy_map_.find(interface_name);
if (found != associated_policy_map_.end())
return found->second;
return default_policy;
}
MojoBinderNonAssociatedPolicy
MojoBinderPolicyMapImpl::GetNonAssociatedMojoBinderPolicyOrDieForTesting(
const std::string& interface_name) const {
const auto& found = non_associated_policy_map_.find(interface_name);
CHECK(found != non_associated_policy_map_.end());
return found->second;
}
MojoBinderAssociatedPolicy
MojoBinderPolicyMapImpl::GetAssociatedMojoBinderPolicyOrDieForTesting(
const std::string& interface_name) const {
const auto& found = associated_policy_map_.find(interface_name);
CHECK(found != associated_policy_map_.end());
return found->second;
}
void MojoBinderPolicyMapImpl::SetPolicyByName(
const std::string_view& name,
MojoBinderNonAssociatedPolicy policy) {
non_associated_policy_map_.emplace(name, policy);
}
void MojoBinderPolicyMapImpl::SetPolicyByName(
const std::string_view& name,
MojoBinderAssociatedPolicy policy) {
associated_policy_map_.emplace(name, policy);
}
} // namespace content
|