Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2021 The Chromium Authors |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CONTENT_BROWSER_PROCESS_LOCK_H_ |
| 6 | #define CONTENT_BROWSER_PROCESS_LOCK_H_ |
| 7 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 8 | #include <optional> |
| 9 | |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 10 | #include "content/browser/site_info.h" |
| 11 | #include "content/browser/url_info.h" |
| 12 | #include "content/browser/web_exposed_isolation_info.h" |
| 13 | #include "content/public/browser/storage_partition_config.h" |
Robbie McElrath | eae661e | 2023-08-10 19:05:28 | [diff] [blame] | 14 | #include "content/public/browser/web_exposed_isolation_level.h" |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 15 | #include "url/origin.h" |
| 16 | |
| 17 | namespace content { |
| 18 | |
| 19 | class IsolationContext; |
| 20 | |
| 21 | // ProcessLock is a core part of Site Isolation, which is used to determine |
| 22 | // which documents are allowed to load in a process and which site data the |
Charlie Reis | 47457a6 | 2022-05-18 21:57:37 | [diff] [blame] | 23 | // process is allowed to access, based on the SiteInfo principal. |
| 24 | // |
| 25 | // If a process has a ProcessLock in the "invalid" state, then no SiteInstances |
| 26 | // have been associated with the process and access should not be granted to |
| 27 | // anything. |
| 28 | // |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 29 | // Once a process is associated with its first SiteInstance, it transitions to |
| 30 | // the "locked_to_site" or "allow_any_site" state depending on whether the |
| 31 | // SiteInstance requires the process to be locked to a specific site or not. |
| 32 | // If the SiteInstance does not require the process to be locked to a site, the |
| 33 | // process will transition to the "allow_any_site" state and will allow any |
| 34 | // site to commit in the process. Such a process can later be upgraded to the |
| 35 | // "locked_to_site" state if something later determines that the process should |
Charlie Reis | 47457a6 | 2022-05-18 21:57:37 | [diff] [blame] | 36 | // only allow access to a single site, but only if it hasn't otherwise been used |
| 37 | // to render content. Once the process is in the "locked_to_site" state, it will |
| 38 | // not be able to access site data from other sites. |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 39 | // |
| 40 | // ProcessLock is currently defined in terms of a single SiteInfo with a process |
| 41 | // lock URL, but it could be possible to define it in terms of multiple |
Charlie Reis | 47457a6 | 2022-05-18 21:57:37 | [diff] [blame] | 42 | // SiteInfos that are compatible with each other. |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 43 | class CONTENT_EXPORT ProcessLock { |
| 44 | public: |
| 45 | // Create a lock that that represents a process that is associated with at |
| 46 | // least one SiteInstance, but is not locked to a specific site. Any request |
| 47 | // that wants to commit in this process must have a StoragePartitionConfig |
Camille Lamy | 52a5120 | 2025-07-29 14:16:12 | [diff] [blame] | 48 | // and cross-origin isolation and web-exposed isolation information |
| 49 | // (COOP/COEP, for example) that match the values used to create this lock. |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 50 | static ProcessLock CreateAllowAnySite( |
| 51 | const StoragePartitionConfig& storage_partition_config, |
Camille Lamy | 52a5120 | 2025-07-29 14:16:12 | [diff] [blame] | 52 | const WebExposedIsolationInfo& web_exposed_isolation_info, |
| 53 | const std::optional<AgentClusterKey::CrossOriginIsolationKey>& |
| 54 | cross_origin_isolation_key); |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 55 | |
| 56 | // Create a lock for a specific UrlInfo. This method can be called from both |
| 57 | // the UI and IO threads. Locks created with the same parameters must always |
| 58 | // be considered equal independent of what thread they are called on. Special |
| 59 | // care must be taken since SiteInfos created on different threads don't |
| 60 | // always have the same contents for all their fields (e.g. site_url field is |
| 61 | // thread dependent). |
| 62 | static ProcessLock Create(const IsolationContext& isolation_context, |
| 63 | const UrlInfo& url_info); |
| 64 | |
Sharon Yang | 2c077a7 | 2021-11-30 02:27:58 | [diff] [blame] | 65 | // Returns a ProcessLock representing what the given |site_info| requires. |
| 66 | // Note that this may be different from the actual ProcessLock of the |
| 67 | // resulting process, in cases where a locked process is not required (e.g., |
Alex Moshchuk | 4b137ea | 2023-03-30 17:49:36 | [diff] [blame] | 68 | // SiteInfos for http://unisolated.invalid). |
Sharon Yang | 2c077a7 | 2021-11-30 02:27:58 | [diff] [blame] | 69 | static ProcessLock FromSiteInfo(const SiteInfo& site_info); |
| 70 | |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 71 | ProcessLock(); |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 72 | ProcessLock(const ProcessLock& rhs); |
| 73 | ProcessLock& operator=(const ProcessLock& rhs); |
| 74 | |
| 75 | ~ProcessLock(); |
| 76 | |
| 77 | // Returns true if no information has been set on the lock. |
| 78 | bool is_invalid() const { return !site_info_.has_value(); } |
| 79 | |
| 80 | // Returns true if the process is locked, but it is not restricted to a |
| 81 | // specific site. Any site is allowed to commit in the process as long as |
| 82 | // the request's COOP/COEP information matches the info provided when |
| 83 | // the lock was created. |
Camille Lamy | bc43eff | 2025-08-22 09:32:14 | [diff] [blame] | 84 | bool AllowsAnySite() const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 85 | |
| 86 | // Returns true if the lock is restricted to a specific site and requires |
| 87 | // the request's COOP/COEP information to match the values provided when |
| 88 | // the lock was created. |
Camille Lamy | bc43eff | 2025-08-22 09:32:14 | [diff] [blame] | 89 | bool IsLockedToSite() const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 90 | |
| 91 | // Returns the url that corresponds to the SiteInfo the lock is used with. It |
| 92 | // will always be the same as the site URL, except in cases where effective |
| 93 | // urls are in use. Always empty if the SiteInfo uses the default site url. |
Camille Lamy | bc43eff | 2025-08-22 09:32:14 | [diff] [blame] | 94 | // Note: this is derived from the AgentClusterKey. It's possible for two |
| 95 | // ProcessLocks to have the same process lock URL but different |
| 96 | // AgentClusterKeys when one of the AgentClusterKey is site keyed and the |
| 97 | // other is origin keyed, or when the two process locks have different |
| 98 | // cross-origin isolation status. This means that two ProcessLocks with the |
| 99 | // same process lock URL might not be considered equal. Therefore, compare |
| 100 | // ProcessLocks directly as much as possible. |
| 101 | GURL GetProcessLockURL() const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 102 | |
Alex Moshchuk | 5000006 | 2023-01-03 23:08:59 | [diff] [blame] | 103 | // Returns the site URL of the SiteInfo with which the lock was constructed. |
Camille Lamy | bc43eff | 2025-08-22 09:32:14 | [diff] [blame] | 104 | // Prefer comparing ProcessLocks directly or using agent_cluster_key(), unless |
| 105 | // you care about effective URLs. |
Alex Moshchuk | 5000006 | 2023-01-03 23:08:59 | [diff] [blame] | 106 | const GURL site_url() const { |
| 107 | return site_info_.has_value() ? site_info_->site_url() : GURL(); |
| 108 | } |
| 109 | |
Camille Lamy | d1f015d | 2024-07-06 14:14:10 | [diff] [blame] | 110 | // Returns the AgentClusterKey shared by agents allowed in this ProcessLock. |
Camille Lamy | 52a5120 | 2025-07-29 14:16:12 | [diff] [blame] | 111 | const AgentClusterKey agent_cluster_key() const { |
Camille Lamy | d1f015d | 2024-07-06 14:14:10 | [diff] [blame] | 112 | return site_info_.has_value() ? site_info_->agent_cluster_key() |
Camille Lamy | 52a5120 | 2025-07-29 14:16:12 | [diff] [blame] | 113 | : AgentClusterKey(); |
Camille Lamy | d1f015d | 2024-07-06 14:14:10 | [diff] [blame] | 114 | } |
| 115 | |
W. James MacLean | 37dd4aade | 2022-07-28 15:40:51 | [diff] [blame] | 116 | // True if this ProcessLock is for a sandboxed iframe without |
| 117 | // allow-same-origin. |
W. James MacLean | c79153d | 2022-02-10 19:17:34 | [diff] [blame] | 118 | // TODO(wjmaclean): This function's return type could mutate to an enum in |
| 119 | // future if required for sandboxed iframes that are restricted with different |
| 120 | // sandbox flags. |
| 121 | bool is_sandboxed() const { |
| 122 | return site_info_.has_value() && site_info_->is_sandboxed(); |
| 123 | } |
| 124 | |
W. James MacLean | 37dd4aade | 2022-07-28 15:40:51 | [diff] [blame] | 125 | // If this ProcessLock is for a sandboxed iframe without allow-same-origin, |
| 126 | // and per-document grouping has been enabled for kIsolateSandboxedIframes, |
| 127 | // then each SiteInfo will have a unique sandbox id encoded as part of the |
| 128 | // lock. If per-document grouping is not enabled, this returns |
| 129 | // UrlInfo::kInvalidUniqueSandboxId. |
| 130 | int unique_sandbox_id() const { |
| 131 | return (site_info_.has_value() ? site_info_->unique_sandbox_id() |
| 132 | : UrlInfo::kInvalidUniqueSandboxId); |
| 133 | } |
| 134 | |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 135 | // Returns whether this ProcessLock is specific to PDF contents. |
| 136 | bool is_pdf() const { return site_info_.has_value() && site_info_->is_pdf(); } |
| 137 | |
Charlie Reis | 3331283 | 2022-05-23 17:26:57 | [diff] [blame] | 138 | // Returns whether this ProcessLock can only be used for error pages. |
Sharon Yang | a694255 | 2021-11-16 21:15:09 | [diff] [blame] | 139 | bool is_error_page() const { |
| 140 | return site_info_.has_value() && site_info_->is_error_page(); |
| 141 | } |
| 142 | |
Charlie Reis | 3331283 | 2022-05-23 17:26:57 | [diff] [blame] | 143 | // Returns whether this ProcessLock is used for a <webview> guest process. |
| 144 | // This may be false for other types of GuestView. |
Alex Moshchuk | df15d8e | 2022-02-01 04:43:49 | [diff] [blame] | 145 | bool is_guest() const { |
| 146 | return site_info_.has_value() && site_info_->is_guest(); |
| 147 | } |
| 148 | |
Adithya Srinivasan | f6377b1 | 2022-08-31 21:58:44 | [diff] [blame] | 149 | // Returns whether this ProcessLock is used for a process that exclusively |
| 150 | // hosts content inside a <fencedframe>. |
| 151 | bool is_fenced() const { |
| 152 | return site_info_.has_value() && site_info_->is_fenced(); |
| 153 | } |
| 154 | |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 155 | // Returns the StoragePartitionConfig that corresponds to the SiteInfo the |
| 156 | // lock is used with. |
Sharon Yang | a694255 | 2021-11-16 21:15:09 | [diff] [blame] | 157 | StoragePartitionConfig GetStoragePartitionConfig() const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 158 | |
Robbie McElrath | eae661e | 2023-08-10 19:05:28 | [diff] [blame] | 159 | // Returns the cross-origin isolation mode of the BrowsingInstance that all |
| 160 | // agents allowed in this ProcessLock belong to. See |
| 161 | // https://html.spec.whatwg.org/multipage/document-sequences.html#cross-origin-isolation-mode |
Charlie Reis | 3331283 | 2022-05-23 17:26:57 | [diff] [blame] | 162 | // This is tracked on ProcessLock because a RenderProcessHost can host only |
| 163 | // cross-origin isolated agents or only non-cross-origin isolated agents, not |
| 164 | // both. |
Sharon Yang | a694255 | 2021-11-16 21:15:09 | [diff] [blame] | 165 | WebExposedIsolationInfo GetWebExposedIsolationInfo() const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 166 | |
Robbie McElrath | eae661e | 2023-08-10 19:05:28 | [diff] [blame] | 167 | // Returns the cross-origin isolated capability of all agents allowed in this |
| 168 | // ProcessLock, without taking into account the 'cross-origin-isolated' |
| 169 | // permissions policy. This ignores permissions policy because it's currently |
| 170 | // possible for agents with the same ProcessLock to have different |
| 171 | // 'cross-origin-isolated' permission policies. This can return a lower |
| 172 | // isolation level than `GetWebExposedIsolationInfo()` if this ProcessLock |
| 173 | // hosts agents that are cross-origin to a top-level document with the |
| 174 | // 'isolated application' isolation level. See |
| 175 | // https://html.spec.whatwg.org/multipage/webappapis.html#dom-crossoriginisolated |
| 176 | WebExposedIsolationLevel GetWebExposedIsolationLevel() const; |
| 177 | |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 178 | // Returns whether lock_url() is at least at the granularity of a site (i.e., |
| 179 | // a scheme plus eTLD+1, like https://google.com). Also returns true if the |
| 180 | // lock is to a more specific origin (e.g., https://accounts.google.com), but |
| 181 | // not if the lock is empty or applies to an entire scheme (e.g., file://). |
| 182 | bool IsASiteOrOrigin() const; |
| 183 | |
Camille Lamy | bc43eff | 2025-08-22 09:32:14 | [diff] [blame] | 184 | bool MatchesScheme(const std::string& scheme) const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 185 | |
| 186 | // Returns true if lock_url() has an opaque origin. |
| 187 | bool HasOpaqueOrigin() const; |
| 188 | |
| 189 | // Returns true if |origin| matches the lock's origin. |
| 190 | bool MatchesOrigin(const url::Origin& origin) const; |
| 191 | |
| 192 | // Returns true if the COOP/COEP origin isolation information in this lock |
| 193 | // is set and matches the information in |site_info|. |
| 194 | // Returns true if the web-exposed isolation level in this lock is set and |
| 195 | // matches (or exceeds) the level set in |site_info|.|. |
| 196 | bool IsCompatibleWithWebExposedIsolation(const SiteInfo& site_info) const; |
| 197 | |
| 198 | bool operator==(const ProcessLock& rhs) const; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 199 | // Defined to allow this object to act as a key for std::map. |
| 200 | bool operator<(const ProcessLock& rhs) const; |
| 201 | |
| 202 | std::string ToString() const; |
| 203 | |
| 204 | private: |
Sharon Yang | 2c077a7 | 2021-11-30 02:27:58 | [diff] [blame] | 205 | explicit ProcessLock(const SiteInfo& site_info); |
| 206 | |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 207 | // TODO(creis): Consider tracking multiple compatible SiteInfos in ProcessLock |
Charlie Reis | 3331283 | 2022-05-23 17:26:57 | [diff] [blame] | 208 | // (e.g., multiple sites when Site Isolation is disabled). This can better |
| 209 | // restrict what the process has access to in cases that we currently use an |
| 210 | // allows-any-site ProcessLock. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 211 | std::optional<SiteInfo> site_info_; |
Sharon Yang | a005ca1 | 2021-11-16 20:09:42 | [diff] [blame] | 212 | }; |
| 213 | |
| 214 | CONTENT_EXPORT std::ostream& operator<<(std::ostream& out, |
| 215 | const ProcessLock& process_lock); |
| 216 | |
| 217 | } // namespace content |
| 218 | |
| 219 | #endif // CONTENT_BROWSER_PROCESS_LOCK_H_ |