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
content / browser / process_lock.h [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_PROCESS_LOCK_H_
#define CONTENT_BROWSER_PROCESS_LOCK_H_
#include <optional>
#include "content/browser/site_info.h"
#include "content/browser/url_info.h"
#include "content/browser/web_exposed_isolation_info.h"
#include "content/public/browser/storage_partition_config.h"
#include "content/public/browser/web_exposed_isolation_level.h"
#include "url/origin.h"
namespace content {
class IsolationContext;
// ProcessLock is a core part of Site Isolation, which is used to determine
// which documents are allowed to load in a process and which site data the
// process is allowed to access, based on the SiteInfo principal.
//
// If a process has a ProcessLock in the "invalid" state, then no SiteInstances
// have been associated with the process and access should not be granted to
// anything.
//
// Once a process is associated with its first SiteInstance, it transitions to
// the "locked_to_site" or "allow_any_site" state depending on whether the
// SiteInstance requires the process to be locked to a specific site or not.
// If the SiteInstance does not require the process to be locked to a site, the
// process will transition to the "allow_any_site" state and will allow any
// site to commit in the process. Such a process can later be upgraded to the
// "locked_to_site" state if something later determines that the process should
// only allow access to a single site, but only if it hasn't otherwise been used
// to render content. Once the process is in the "locked_to_site" state, it will
// not be able to access site data from other sites.
//
// ProcessLock is currently defined in terms of a single SiteInfo with a process
// lock URL, but it could be possible to define it in terms of multiple
// SiteInfos that are compatible with each other.
class CONTENT_EXPORT ProcessLock {
public:
// Create a lock that that represents a process that is associated with at
// least one SiteInstance, but is not locked to a specific site. Any request
// that wants to commit in this process must have a StoragePartitionConfig
// and web-exposed isolation information (COOP/COEP, for example) that
// match the values used to create this lock.
static ProcessLock CreateAllowAnySite(
const StoragePartitionConfig& storage_partition_config,
const WebExposedIsolationInfo& web_exposed_isolation_info);
// Create a lock for a specific UrlInfo. This method can be called from both
// the UI and IO threads. Locks created with the same parameters must always
// be considered equal independent of what thread they are called on. Special
// care must be taken since SiteInfos created on different threads don't
// always have the same contents for all their fields (e.g. site_url field is
// thread dependent).
static ProcessLock Create(const IsolationContext& isolation_context,
const UrlInfo& url_info);
// Returns a ProcessLock representing what the given |site_info| requires.
// Note that this may be different from the actual ProcessLock of the
// resulting process, in cases where a locked process is not required (e.g.,
// SiteInfos for http://unisolated.invalid).
static ProcessLock FromSiteInfo(const SiteInfo& site_info);
ProcessLock();
ProcessLock(const ProcessLock& rhs);
ProcessLock& operator=(const ProcessLock& rhs);
~ProcessLock();
// Returns true if no information has been set on the lock.
bool is_invalid() const { return !site_info_.has_value(); }
// Returns true if the process is locked, but it is not restricted to a
// specific site. Any site is allowed to commit in the process as long as
// the request's COOP/COEP information matches the info provided when
// the lock was created.
bool allows_any_site() const {
return site_info_.has_value() && site_info_->process_lock_url().is_empty();
}
// Returns true if the lock is restricted to a specific site and requires
// the request's COOP/COEP information to match the values provided when
// the lock was created.
bool is_locked_to_site() const {
return site_info_.has_value() && !site_info_->process_lock_url().is_empty();
}
// Returns the url that corresponds to the SiteInfo the lock is used with. It
// will always be the same as the site URL, except in cases where effective
// urls are in use. Always empty if the SiteInfo uses the default site url.
// TODO(wjmaclean): Delete this accessor once we get to the point where we can
// safely just compare ProcessLocks directly.
const GURL lock_url() const {
return site_info_.has_value() ? site_info_->process_lock_url() : GURL();
}
// Returns the site URL of the SiteInfo with which the lock was constructed.
// Prefer comparing ProcessLocks directly or using lock_url(), unless you
// care about effective URLs.
const GURL site_url() const {
return site_info_.has_value() ? site_info_->site_url() : GURL();
}
// Returns the AgentClusterKey shared by agents allowed in this ProcessLock.
std::optional<AgentClusterKey> agent_cluster_key() const {
return site_info_.has_value() ? site_info_->agent_cluster_key()
: std::nullopt;
}
// Returns whether this ProcessLock is specific to an origin rather than
// including subdomains, such as due to opt-in origin isolation. This resolves
// an ambiguity of whether a process with a lock_url() like
// "https://foo.example" is allowed to include "https://sub.foo.example" or
// not.
bool is_origin_keyed_process() const {
return site_info_.has_value() &&
site_info_->requires_origin_keyed_process();
}
// True if this ProcessLock is for a sandboxed iframe without
// allow-same-origin.
// TODO(wjmaclean): This function's return type could mutate to an enum in
// future if required for sandboxed iframes that are restricted with different
// sandbox flags.
bool is_sandboxed() const {
return site_info_.has_value() && site_info_->is_sandboxed();
}
// If this ProcessLock is for a sandboxed iframe without allow-same-origin,
// and per-document grouping has been enabled for kIsolateSandboxedIframes,
// then each SiteInfo will have a unique sandbox id encoded as part of the
// lock. If per-document grouping is not enabled, this returns
// UrlInfo::kInvalidUniqueSandboxId.
int unique_sandbox_id() const {
return (site_info_.has_value() ? site_info_->unique_sandbox_id()
: UrlInfo::kInvalidUniqueSandboxId);
}
// Returns whether this ProcessLock is specific to PDF contents.
bool is_pdf() const { return site_info_.has_value() && site_info_->is_pdf(); }
// Returns whether this ProcessLock can only be used for error pages.
bool is_error_page() const {
return site_info_.has_value() && site_info_->is_error_page();
}
// Returns whether this ProcessLock is used for a <webview> guest process.
// This may be false for other types of GuestView.
bool is_guest() const {
return site_info_.has_value() && site_info_->is_guest();
}
// Returns whether this ProcessLock is used for a process that exclusively
// hosts content inside a <fencedframe>.
bool is_fenced() const {
return site_info_.has_value() && site_info_->is_fenced();
}
// Returns the StoragePartitionConfig that corresponds to the SiteInfo the
// lock is used with.
StoragePartitionConfig GetStoragePartitionConfig() const;
// Returns the cross-origin isolation mode of the BrowsingInstance that all
// agents allowed in this ProcessLock belong to. See
// https://html.spec.whatwg.org/multipage/document-sequences.html#cross-origin-isolation-mode
// This is tracked on ProcessLock because a RenderProcessHost can host only
// cross-origin isolated agents or only non-cross-origin isolated agents, not
// both.
WebExposedIsolationInfo GetWebExposedIsolationInfo() const;
// Returns the cross-origin isolated capability of all agents allowed in this
// ProcessLock, without taking into account the 'cross-origin-isolated'
// permissions policy. This ignores permissions policy because it's currently
// possible for agents with the same ProcessLock to have different
// 'cross-origin-isolated' permission policies. This can return a lower
// isolation level than `GetWebExposedIsolationInfo()` if this ProcessLock
// hosts agents that are cross-origin to a top-level document with the
// 'isolated application' isolation level. See
// https://html.spec.whatwg.org/multipage/webappapis.html#dom-crossoriginisolated
WebExposedIsolationLevel GetWebExposedIsolationLevel() const;
// Returns whether lock_url() is at least at the granularity of a site (i.e.,
// a scheme plus eTLD+1, like https://google.com). Also returns true if the
// lock is to a more specific origin (e.g., https://accounts.google.com), but
// not if the lock is empty or applies to an entire scheme (e.g., file://).
bool IsASiteOrOrigin() const;
bool matches_scheme(const std::string& scheme) const {
return scheme == lock_url().scheme();
}
// Returns true if lock_url() has an opaque origin.
bool HasOpaqueOrigin() const;
// Returns true if |origin| matches the lock's origin.
bool MatchesOrigin(const url::Origin& origin) const;
// Returns true if the COOP/COEP origin isolation information in this lock
// is set and matches the information in |site_info|.
// Returns true if the web-exposed isolation level in this lock is set and
// matches (or exceeds) the level set in |site_info|.|.
bool IsCompatibleWithWebExposedIsolation(const SiteInfo& site_info) const;
bool operator==(const ProcessLock& rhs) const;
bool operator!=(const ProcessLock& rhs) const;
// Defined to allow this object to act as a key for std::map.
bool operator<(const ProcessLock& rhs) const;
std::string ToString() const;
private:
explicit ProcessLock(const SiteInfo& site_info);
// TODO(creis): Consider tracking multiple compatible SiteInfos in ProcessLock
// (e.g., multiple sites when Site Isolation is disabled). This can better
// restrict what the process has access to in cases that we currently use an
// allows-any-site ProcessLock.
std::optional<SiteInfo> site_info_;
};
CONTENT_EXPORT std::ostream& operator<<(std::ostream& out,
const ProcessLock& process_lock);
} // namespace content
#endif // CONTENT_BROWSER_PROCESS_LOCK_H_