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
313
content / browser / mojo_binder_policy_map_impl.cc [blame]
// 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 "base/not_fatal_until.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(), base::NotFatalUntil::M130);
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(), base::NotFatalUntil::M130);
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