// Copyright 2021 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_PROCESS_LOCK_H_ #define CONTENT_BROWSER_PROCESS_LOCK_H_ #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 "third_party/abseil-cpp/absl/types/optional.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. Once the process is in the // "locked_to_site" state, the process 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 (e.g., multiple extensions // sharing an extension process). 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 chrome-guest:// or 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 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 origin-restricted sandboxed iframe. // 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(); } // Returns whether this ProcessLock is specific to PDF contents. bool is_pdf() const { return site_info_.has_value() && site_info_->is_pdf(); } bool is_error_page() const { return site_info_.has_value() && site_info_->is_error_page(); } bool is_guest() const { return site_info_.has_value() && site_info_->is_guest(); } // Returns the StoragePartitionConfig that corresponds to the SiteInfo the // lock is used with. StoragePartitionConfig GetStoragePartitionConfig() const; // Representing agent cluster's "cross-origin isolated" concept. // https://html.spec.whatwg.org/multipage/webappapis.html#dom-crossoriginisolated // This property is renderer process global because we ensure that a // renderer process host only cross-origin isolated agents or only // non-cross-origin isolated agents, not both. WebExposedIsolationInfo GetWebExposedIsolationInfo() 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 extensions). This can better restrict what the process has // access to in cases that we don't currently use a ProcessLock. absl::optional site_info_; }; CONTENT_EXPORT std::ostream& operator<<(std::ostream& out, const ProcessLock& process_lock); } // namespace content #endif // CONTENT_BROWSER_PROCESS_LOCK_H_