
ChildProcessSecurityPolicy::CanAccessDataForOrigin is the main API for performing site isolation enforcements, deciding whether a renderer process is allowed to access data for a particular origin. The implementation of this check (in CanAccessMaybeOpaqueOrigin) is currently shared for three different kinds of checks and has gotten very complicated over the years, trying to compute an expected process lock from the provided URL and compare it to the actual process lock, while accounting for things like whether the URL's origin should use origin vs site isolation. This CL is a first step towards simplifying this implementation by providing an alternate mechanism for implementing CanAccessDataForOrigin (CADFO). Namely, we can track all origins ever committed for a particular process, and then only allow access to data for origins that have been committed, because they have already been validated at commit time. This subsumes the current process lock checks, since CADFO only ever used the origin comparison and ignored the other ProcessLock/SiteInfo bits, artificially making them match in the expected and actual locks (see https://source.chromium.org/chromium/chromium/src/+/main:content/browser/child_process_security_policy_impl.cc;l=2050-2065;drc=f522344e45882da4c7f7cb1b3a0a7bd747d654bb). This new check is only useful for kHostsOrigin and kCanAccessDataForCommittedOrigin checks (i.e., whether an origin was previously committed in a process, and whether the process can access data belonging to an already committed origin). It cannot be used for kCanCommitNewOrigin checks that decide whether a new origin should be allowed to commit in a particular process. These will still use the process lock comparisons for now. For implementation, SecurityState now tracks a set of committed origins. Committed origins for navigations are added in RFHI::UpdatePermissionsForNavigation() at ready-to-commit time and in Navigator::DidNavigate() at DidCommit time. The former is sufficient in vast majority of cases, but the latter is still needed in cases like adding a sandboxed about:blank iframe, where a new opaque origin is introduced into the parent's process (OOPSIFs aren't used in this case), but this doesn't go through the full navigation flow and doesn't hit UpdatePermissionsForNavigation(). Committed origins are also added when creating ServiceWorkers. For now, other workers are assumed to stay in the origin of their creator document; there is a corner case where this isn't true (workers created via a data: URL), but this will be fixed in a followup. The set of committed origins can only grow; for simplicity, there is currently no provision to revoke a committed origin. The hope is that this set won't grow overly large; but this may need to be revisited. Metrics to track the size of this set will be added in a followup CL. This does cause a slight behavior change where a process that no longer has any documents or workers could be denied access with the older checks, but would still be allowed access for the older origins with the new checks. This is covered in DynamicIsolatedOriginTest.NewBrowsingInstanceInOldProcess, where an origin becomes dynamically isolated, and a process previously lost access to that origin as soon as the last BrowsingInstance where the origin was not isolated is removed from the process, but now that access is maintained. For now, we don't consider this to be a meaningful decrease in security, as it's hard for the attacker to take advantage of, but this could be revisited in the future, e.g., by marking newly isolated origins as needing revocation when their last instance goes away from a process. The new checks are also slightly stricter than the old checks because they will compare the full origins, rather than the ProcessLocks computed from them. So, for example, if https://foo.com/ was committed and isolated at a site granularity, requests for data from https://sub.foo.com would now be blocked. Also, port mismatches in origins are no longer ignored. So, if https://foo.com:1234 has committed, requests for https://foo.com:5678 would now be denied, whereas they would be allowed by jail/citadel checks previously (since the ProcessLock computation ignores ports). The enforcements of the new checks (where they replace jail and citadel checks) are behind a feature which is off by default. Nonetheless, all affected existing tests have been fixed to pass with the checks on. ChildProcessSecurityPolicy tests have been parameterized to run both with and without the new checks. When the new checks disagree with the jail/citadel checks, we generate a DumpWithoutCrashing report to collect more information. (Some of these cases, like port mismatches, will be expected, as explained above.) Bug: 40148776 Change-Id: Id31c4130ef1f8b9936b27bddb4658641fca7ffde Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5410347 Commit-Queue: Alex Moshchuk <alexmos@chromium.org> Reviewed-by: Charlie Reis <creis@chromium.org> Cr-Commit-Position: refs/heads/main@{#1378730}
1067 lines
52 KiB
C++
1067 lines
52 KiB
C++
// Copyright 2012 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_CHILD_PROCESS_SECURITY_POLICY_IMPL_H_
|
|
#define CONTENT_BROWSER_CHILD_PROCESS_SECURITY_POLICY_IMPL_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
#include "base/containers/flat_map.h"
|
|
#include "base/containers/flat_set.h"
|
|
#include "base/gtest_prod_util.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/memory/singleton.h"
|
|
#include "base/synchronization/lock.h"
|
|
#include "base/thread_annotations.h"
|
|
#include "base/time/time.h"
|
|
#include "content/browser/can_commit_status.h"
|
|
#include "content/browser/isolated_origin_util.h"
|
|
#include "content/browser/isolation_context.h"
|
|
#include "content/browser/origin_agent_cluster_isolation_state.h"
|
|
#include "content/common/content_export.h"
|
|
#include "content/public/browser/child_process_security_policy.h"
|
|
#include "content/public/common/bindings_policy.h"
|
|
#include "storage/common/file_system/file_system_types.h"
|
|
#include "url/origin.h"
|
|
|
|
class GURL;
|
|
|
|
namespace base {
|
|
class FilePath;
|
|
} // namespace base
|
|
|
|
namespace network {
|
|
class ResourceRequestBody;
|
|
} // namespace network
|
|
|
|
namespace storage {
|
|
class FileSystemContext;
|
|
class FileSystemURL;
|
|
} // namespace storage
|
|
|
|
namespace content {
|
|
|
|
class BrowserContext;
|
|
class IsolationContext;
|
|
class ProcessLock;
|
|
class ResourceContext;
|
|
struct UrlInfo;
|
|
|
|
class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
|
|
: public ChildProcessSecurityPolicy {
|
|
public:
|
|
// Handle used to access the security state for a specific process.
|
|
//
|
|
// Objects that require the security state to be preserved beyond the
|
|
// lifetime of the RenderProcessHostImpl should hold an instance of this
|
|
// object and use it to answer security policy questions. (e.g. Mojo services
|
|
// created by RPHI that can receive calls after RPHI destruction). This
|
|
// object should only be called on the UI and IO threads.
|
|
//
|
|
// Note: Some security methods, like CanAccessDataForOrigin(), require
|
|
// information from the BrowserContext to make its decisions. These methods
|
|
// will fall back to failsafe values if called after BrowserContext
|
|
// destruction. Callers should be prepared to gracefully handle this or
|
|
// ensure that they don't make any calls after BrowserContext destruction.
|
|
class CONTENT_EXPORT Handle {
|
|
public:
|
|
Handle();
|
|
Handle(Handle&&);
|
|
Handle(const Handle&) = delete;
|
|
~Handle();
|
|
|
|
Handle& operator=(const Handle&) = delete;
|
|
Handle& operator=(Handle&&);
|
|
|
|
// Create a new instance of Handle, holding another reference to the same
|
|
// process ID as the current one.
|
|
Handle Duplicate();
|
|
|
|
// Returns true if this object has a valid process ID.
|
|
// Returns false if this object was created with the default constructor,
|
|
// the contents of this object was transferred to another Handle via
|
|
// std::move(), or ChildProcessSecurityPolicyImpl::CreateHandle()
|
|
// created this object after the process has already been destructed.
|
|
bool is_valid() const;
|
|
|
|
// Before servicing a child process's request to upload a file to the web,
|
|
// the browser should call this method to determine whether the process has
|
|
// the capability to upload the requested file.
|
|
bool CanReadFile(const base::FilePath& file);
|
|
|
|
// Explicit read permissions check for FileSystemURL specified files.
|
|
bool CanReadFileSystemFile(const storage::FileSystemURL& url);
|
|
|
|
// Returns true if the process is permitted to read and modify the data for
|
|
// the given `origin`. For more details, see
|
|
// ChildProcessSecurityPolicy::CanAccessDataForOrigin().
|
|
bool CanAccessDataForOrigin(const url::Origin& origin);
|
|
|
|
// Returns the original `child_id` used to create the handle.
|
|
int child_id() { return child_id_; }
|
|
|
|
private:
|
|
friend class ChildProcessSecurityPolicyImpl;
|
|
// |child_id| - The ID of the process that this Handle is being created
|
|
// for, or ChildProcessHost::kInvalidUniqueID if an invalid handle is being
|
|
// created.
|
|
// |duplicating_handle| - True if the handle is being created by a
|
|
// Duplicate() call. Otherwise false. This is used to trigger special
|
|
// behavior for handle duplication that is not allowed for Handles created
|
|
// by other means.
|
|
Handle(int child_id, bool duplicating_handle);
|
|
|
|
// The ID of the child process that this handle is associated with or
|
|
// ChildProcessHost::kInvalidUniqueID if the handle is no longer valid.
|
|
int child_id_;
|
|
};
|
|
|
|
ChildProcessSecurityPolicyImpl(const ChildProcessSecurityPolicyImpl&) =
|
|
delete;
|
|
ChildProcessSecurityPolicyImpl& operator=(
|
|
const ChildProcessSecurityPolicyImpl&) = delete;
|
|
|
|
// Object can only be created through GetInstance() so the constructor is
|
|
// private.
|
|
~ChildProcessSecurityPolicyImpl() override;
|
|
|
|
static ChildProcessSecurityPolicyImpl* GetInstance();
|
|
|
|
// ChildProcessSecurityPolicy implementation.
|
|
void RegisterWebSafeScheme(const std::string& scheme) override;
|
|
void RegisterWebSafeIsolatedScheme(
|
|
const std::string& scheme,
|
|
bool always_allow_in_origin_headers) override;
|
|
bool IsWebSafeScheme(const std::string& scheme) override;
|
|
void GrantReadFile(int child_id, const base::FilePath& file) override;
|
|
void GrantCreateReadWriteFile(int child_id,
|
|
const base::FilePath& file) override;
|
|
void GrantCopyInto(int child_id, const base::FilePath& dir) override;
|
|
void GrantDeleteFrom(int child_id, const base::FilePath& dir) override;
|
|
void GrantReadFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
void GrantWriteFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
void GrantCreateFileForFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
void GrantCreateReadWriteFileSystem(
|
|
int child_id,
|
|
const std::string& filesystem_id) override;
|
|
void GrantCopyIntoFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
void GrantDeleteFromFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
void GrantCommitOrigin(int child_id, const url::Origin& origin) override;
|
|
void GrantRequestOrigin(int child_id, const url::Origin& origin) override;
|
|
void GrantRequestScheme(int child_id, const std::string& scheme) override;
|
|
bool CanRequestURL(int child_id, const GURL& url) override;
|
|
bool CanReadFile(int child_id, const base::FilePath& file) override;
|
|
bool CanCreateReadWriteFile(int child_id,
|
|
const base::FilePath& file) override;
|
|
bool CanReadFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
bool CanReadWriteFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
bool CanCopyIntoFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
bool CanDeleteFromFileSystem(int child_id,
|
|
const std::string& filesystem_id) override;
|
|
bool HasWebUIBindings(int child_id) override;
|
|
void GrantSendMidiMessage(int child_id) override;
|
|
void GrantSendMidiSysExMessage(int child_id) override;
|
|
bool CanAccessDataForOrigin(int child_id, const url::Origin& origin) override;
|
|
bool HostsOrigin(int child_id, const url::Origin& origin) override;
|
|
void AddFutureIsolatedOrigins(
|
|
std::string_view origins_list,
|
|
IsolatedOriginSource source,
|
|
BrowserContext* browser_context = nullptr) override;
|
|
void AddFutureIsolatedOrigins(
|
|
const std::vector<url::Origin>& origins,
|
|
IsolatedOriginSource source,
|
|
BrowserContext* browser_context = nullptr) override;
|
|
bool IsGloballyIsolatedOriginForTesting(const url::Origin& origin) override;
|
|
std::vector<url::Origin> GetIsolatedOrigins(
|
|
std::optional<IsolatedOriginSource> source = std::nullopt,
|
|
BrowserContext* browser_context = nullptr) override;
|
|
bool IsIsolatedSiteFromSource(const url::Origin& origin,
|
|
IsolatedOriginSource source) override;
|
|
void ClearIsolatedOriginsForTesting() override;
|
|
|
|
// Centralized internal implementation of site isolation enforcements,
|
|
// including CanAccessDataForOrigin and HostsOrigin. It supports the following
|
|
// types of access checks, in order of increasing strictness:
|
|
enum class AccessType {
|
|
// Whether the process can commit a navigation to an origin, allowing a
|
|
// document with that origin to be hosted in this process. This is
|
|
// specifically about whether a particular new origin may be introduced
|
|
// into a given process.
|
|
kCanCommitNewOrigin,
|
|
// Whether the process has previously committed a document or instantiated a
|
|
// worker with the particular origin. This can be used to verify whether a
|
|
// particular origin can be used as an initiator or source origin, e.g. in
|
|
// postMessage or other IPCs sent from this process. Unlike
|
|
// kCanCommitNewOrigin, this check assumes that the origin must already
|
|
// exist in the process. Because a document/worker destruction may race with
|
|
// processing legitimate IPCs on behalf of `origin`, this check also allows
|
|
// the case where an origin has been hosted by the process in the past, but
|
|
// not necessarily now.
|
|
kHostsOrigin,
|
|
// Whether the process can access data belonging to an origin already
|
|
// committed in the process, such as passwords, localStorage, or cookies.
|
|
// Similarly to kHostsOrigin, this check assumes that the origin must
|
|
// already
|
|
// exist in the process, but it is more strict for certain kinds of
|
|
// processes that aren't supposed to access any data. For example, sandboxed
|
|
// frame processes (which contain only opaque origins) or PDF processes
|
|
// cannot access data for any origin.
|
|
kCanAccessDataForCommittedOrigin,
|
|
};
|
|
bool CanAccessOrigin(int child_id,
|
|
const url::Origin& origin,
|
|
AccessType access_type);
|
|
|
|
// Determines if the combination of origin, url and web_exposed_isolation_info
|
|
// bundled in `url_info` are safe to commit to the process associated with
|
|
// `child_id`.
|
|
//
|
|
// Returns CAN_COMMIT_ORIGIN_AND_URL if it is safe to commit `url_info` origin
|
|
// and `url_info`'s url combination to the process associated with `child_id`.
|
|
// Returns CANNOT_COMMIT_URL if `url_info` url is not safe to commit.
|
|
// Returns CANNOT_COMMIT_ORIGIN if `url_info` origin is not safe to commit.
|
|
CanCommitStatus CanCommitOriginAndUrl(
|
|
int child_id,
|
|
const IsolationContext& isolation_context,
|
|
const UrlInfo& url_info);
|
|
|
|
// Whether the process is allowed to commit a document from the given URL.
|
|
// This is more restrictive than CanRequestURL, since CanRequestURL allows
|
|
// requests that might lead to cross-process navigations or external protocol
|
|
// handlers. Used primarily as a helper for CanCommitOriginAndUrl and thus not
|
|
// exposed publicly.
|
|
bool CanCommitURL(int child_id, const GURL& url);
|
|
|
|
// This function will check whether |origin| requires process isolation
|
|
// within |isolation_context|, and if so, it will return true and put the
|
|
// most specific matching isolated origin into |result|.
|
|
//
|
|
// Such origins may be registered with the --isolate-origins command-line
|
|
// flag, via features::IsolateOrigins, via an IsolateOrigins enterprise
|
|
// policy, or by a content/ embedder using
|
|
// ContentBrowserClient::GetOriginsRequiringDedicatedProcess().
|
|
//
|
|
// If |origin| does not require process isolation, this function will return
|
|
// false, and |result| will be a unique origin. This means that neither
|
|
// |origin|, nor any origins for which |origin| is a subdomain, have been
|
|
// registered as isolated origins.
|
|
//
|
|
// For example, if both https://isolated.com/ and
|
|
// https://bar.foo.isolated.com/ are registered as isolated origins, then the
|
|
// values returned in |result| are:
|
|
// https://isolated.com/ --> https://isolated.com/
|
|
// https://foo.isolated.com/ --> https://isolated.com/
|
|
// https://bar.foo.isolated.com/ --> https://bar.foo.isolated.com/
|
|
// https://baz.bar.foo.isolated.com/ --> https://bar.foo.isolated.com/
|
|
// https://unisolated.com/ --> (unique origin)
|
|
//
|
|
// |isolation_context| is used to determine which origins are isolated in
|
|
// this context. For example, isolated origins that are dynamically added
|
|
// will only affect future BrowsingInstances.
|
|
bool GetMatchingProcessIsolatedOrigin(
|
|
const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
bool requests_origin_keyed_process,
|
|
url::Origin* result);
|
|
|
|
// Removes any origin isolation opt-in entries associated with the
|
|
// |browsing_instance_id| of the BrowsingInstance.
|
|
void RemoveOptInIsolatedOriginsForBrowsingInstance(
|
|
const BrowsingInstanceId& browsing_instance_id);
|
|
|
|
// Registers |origin| isolation state in the BrowsingInstance associated
|
|
// with |isolation_context|.
|
|
//
|
|
// |is_origin_agent_cluster| is used to indicate |origin| will receive (at
|
|
// least) logical isolation via OriginAgentCluster in the renderer. If it is
|
|
// false, then |requires_origin_keyed_process| must also be false.
|
|
//
|
|
// If |requires_origin_keyed_process| is true, then |origin| will be
|
|
// registered as an origin-keyed process; that is, subdomains of |origin|
|
|
// won't be automatically grouped with |origin|. In particular, this can be
|
|
// used for cases using the Origin-Agent-Cluster header.
|
|
//
|
|
// If |requires_origin_keyed_process| is false, then subdomains of |origin|
|
|
// will be grouped together with |origin| in the same process. |origin| is
|
|
// required to be a site (scheme and eTLD+1) in this case.
|
|
//
|
|
// If this function is called with differing values of
|
|
// |requires_origin_keyed_process| for
|
|
// the same IsolationContext and origin, then origin-keyed process isolation
|
|
// takes precedence for |origin|, though site-keyed process isolation will
|
|
// still be used for subdomains of |origin|.
|
|
//
|
|
// If |origin| has already been registered as isolated for the same
|
|
// BrowsingInstance amd the same value of |requires_origin_keyed_process|,
|
|
// then nothing will be changed by this call.
|
|
void AddOriginIsolationStateForBrowsingInstance(
|
|
const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
bool is_origin_agent_cluster,
|
|
bool requires_origin_keyed_process);
|
|
|
|
// Adds `origin` to the IsolatedOrigins list for only the BrowsingInstance of
|
|
// `isolation_context`, without isolating all subdomains. For use when the
|
|
// isolation is triggered by COOP headers.
|
|
void AddCoopIsolatedOriginForBrowsingInstance(
|
|
const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
IsolatedOriginSource source);
|
|
|
|
// This function will check whether |origin| has opted-in to logical or
|
|
// process isolation (via the Origin-Agent-Cluster header), with respect to
|
|
// the current state of the |isolation_context|. It is different from
|
|
// IsIsolatedOrigin() in that it only deals with Origin-Agent-Cluster
|
|
// isolation status, whereas IsIsolatedOrigin() considers all possible
|
|
// mechanisms for requesting isolation. It will check for two things:
|
|
// 1) whether |origin| already is assigned to a SiteInstance in the
|
|
// |isolation_context| by being tracked in
|
|
// |origin_isolation_by_browsing_instance_|, in which case we follow the
|
|
// same policy, or
|
|
// 2) if it's not currently tracked as described above, whether |origin| is
|
|
// currently requesting isolation via |requested_isolation_state|.
|
|
OriginAgentClusterIsolationState DetermineOriginAgentClusterIsolation(
|
|
const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
const OriginAgentClusterIsolationState& requested_isolation_state);
|
|
|
|
// This function adds |origin| to the master list of origins that have
|
|
// ever requested opt-in isolation in the given |browser_context|, either via
|
|
// an OriginPolicy or opt-in header. Returns true if |origin| is not already
|
|
// in the list.
|
|
bool UpdateOriginIsolationOptInListIfNecessary(
|
|
BrowserContext* browser_context,
|
|
const url::Origin& origin);
|
|
|
|
// A version of GetMatchingProcessIsolatedOrigin that takes in both the
|
|
// |origin| and the |site_url| that |origin| corresponds to. |site_url| is
|
|
// the key by which |origin| will be looked up in |isolated_origins_| within
|
|
// |isolation_context|; this function allows it to be passed in when it is
|
|
// already known to avoid recomputing it internally.
|
|
bool GetMatchingProcessIsolatedOrigin(
|
|
const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
bool requests_origin_keyed_process,
|
|
const GURL& site_url,
|
|
url::Origin* result);
|
|
|
|
// Returns if |child_id| can read all of the |files|.
|
|
bool CanReadAllFiles(int child_id, const std::vector<base::FilePath>& files);
|
|
|
|
// Validate that |child_id| in |file_system_context| is allowed to access
|
|
// data in the POST body specified by |body|. Can be called on any thread.
|
|
bool CanReadRequestBody(
|
|
int child_id,
|
|
const storage::FileSystemContext* file_system_context,
|
|
const scoped_refptr<network::ResourceRequestBody>& body);
|
|
|
|
// Validate that `process` is allowed to access data in the POST body
|
|
// specified by |body|. Has to be called on the UI thread.
|
|
bool CanReadRequestBody(
|
|
RenderProcessHost* process,
|
|
const scoped_refptr<network::ResourceRequestBody>& body);
|
|
|
|
// Pseudo schemes are treated differently than other schemes because they
|
|
// cannot be requested like normal URLs. There is no mechanism for revoking
|
|
// pseudo schemes.
|
|
void RegisterPseudoScheme(const std::string& scheme);
|
|
|
|
// Returns true iff |scheme| has been registered as pseudo scheme.
|
|
bool IsPseudoScheme(const std::string& scheme);
|
|
|
|
// Upon creation, child processes should register themselves by calling this
|
|
// this method exactly once. This call must be made on the UI thread.
|
|
void Add(int child_id, BrowserContext* browser_context);
|
|
|
|
// Helper method for unit tests that calls Add() and
|
|
// LockProcess() with an "allow_any_site" lock. This ensures that the process
|
|
// policy is always in a state where it is valid to call
|
|
// CanAccessDataForOrigin().
|
|
void AddForTesting(int child_id, BrowserContext* browser_context);
|
|
|
|
// Upon destruction, child processes should unregister themselves by calling
|
|
// this method exactly once. This call must be made on the UI thread.
|
|
//
|
|
// Note: Pre-Remove() permissions remain in effect on the IO thread until
|
|
// the task posted to the IO thread by this call runs and removes the entry
|
|
// from |pending_remove_state_|.
|
|
// This UI -> IO task sequence ensures that any pending tasks, on the IO
|
|
// thread, for this |child_id| are allowed to run before access is completely
|
|
// revoked.
|
|
void Remove(int child_id);
|
|
|
|
// Whenever the browser processes commands the child process to commit a URL,
|
|
// it should call this method to grant the child process the capability to
|
|
// commit anything from the URL's origin, along with permission to request all
|
|
// URLs of the same scheme.
|
|
void GrantCommitURL(int child_id, const GURL& url);
|
|
|
|
// Whenever the browser process drops a file icon on a tab, it should call
|
|
// this method to grant the child process the capability to request this one
|
|
// file:// URL (or content:// URL in android), but not all urls of the file://
|
|
// scheme.
|
|
void GrantRequestOfSpecificFile(int child_id, const base::FilePath& file);
|
|
|
|
// Revokes all permissions granted to the given file.
|
|
void RevokeAllPermissionsForFile(int child_id, const base::FilePath& file);
|
|
|
|
// Grant the child process the ability to use Web UI Bindings.
|
|
void GrantWebUIBindings(int child_id, BindingsPolicySet bindings);
|
|
|
|
// Grant the child process the ability to read raw cookies.
|
|
void GrantReadRawCookies(int child_id);
|
|
|
|
// Revoke read raw cookies permission.
|
|
void RevokeReadRawCookies(int child_id);
|
|
|
|
// Some APIs for Android WebView and <webview> tags allow bypassing some
|
|
// security checks, such as which URLs are allowed to commit. This method
|
|
// grants that ability to any document with an origin used with these APIs,
|
|
// because the exemption is needed for about:blank frames that inherit the
|
|
// same origin.
|
|
//
|
|
// For safety, this is limited to opaque origins used with LoadDataWithBaseURL
|
|
// in unlocked processes, as well as file origins used with
|
|
// allow_universal_access_from_file_urls.
|
|
//
|
|
// Note that LoadDataWithBaseURL can be used with non-opaque origins as well,
|
|
// but in that case the bypass is only allowed for the document and not the
|
|
// entire origin, to prevent other code in the origin from bypassing checks.
|
|
void GrantOriginCheckExemptionForWebView(int child_id,
|
|
const url::Origin& origin);
|
|
|
|
// Returns whether the given opaque or file origin was granted an exemption
|
|
// due to Android WebView and <webview> APIs, allowing its documents to bypass
|
|
// certain URL and origin checks.
|
|
bool HasOriginCheckExemptionForWebView(int child_id,
|
|
const url::Origin& origin);
|
|
|
|
// Explicit permissions checks for FileSystemURL specified files.
|
|
bool CanReadFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& filesystem_url);
|
|
bool CanWriteFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& filesystem_url);
|
|
bool CanCreateFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& filesystem_url);
|
|
bool CanCreateReadWriteFileSystemFile(
|
|
int child_id,
|
|
const storage::FileSystemURL& filesystem_url);
|
|
bool CanCopyIntoFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& filesystem_url);
|
|
bool CanDeleteFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& filesystem_url);
|
|
bool CanMoveFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& src_url,
|
|
const storage::FileSystemURL& dest_url);
|
|
bool CanCopyFileSystemFile(int child_id,
|
|
const storage::FileSystemURL& src_url,
|
|
const storage::FileSystemURL& dest_url);
|
|
|
|
// Returns true if the specified child_id has been granted ReadRawCookies.
|
|
bool CanReadRawCookies(int child_id);
|
|
|
|
// Notifies security state of |child_id| about the IsolationContext it will
|
|
// host. The main side effect is proper setting of the lowest
|
|
// BrowsingInstanceId associated with the security state.
|
|
void IncludeIsolationContext(int child_id,
|
|
const IsolationContext& isolation_context);
|
|
|
|
// Sets the process identified by |child_id| as only permitted to access data
|
|
// for the origin specified by |site_info|'s process_lock_url(). Most callers
|
|
// should use RenderProcessHostImpl::SetProcessLock instead of calling this
|
|
// directly. |isolation_context| provides the context, such as
|
|
// BrowsingInstance, from which this process locked was created. This
|
|
// information is used when making isolation decisions for this process, such
|
|
// as determining which isolated origins pertain to it. |is_process_used|
|
|
// indicates whether any content has been loaded in the process already.
|
|
void LockProcess(const IsolationContext& isolation_context,
|
|
int child_id,
|
|
bool is_process_used,
|
|
const ProcessLock& process_lock);
|
|
|
|
// Testing helper method that generates a lock_url from |url| and then
|
|
// calls LockProcess() with that lock URL.
|
|
void LockProcessForTesting(const IsolationContext& isolation_context,
|
|
int child_id,
|
|
const GURL& url);
|
|
|
|
// Retrieves the current ProcessLock of process |child_id|. Returns an empty
|
|
// lock if the process does not exist or if it is not locked.
|
|
ProcessLock GetProcessLock(int child_id);
|
|
|
|
// Register FileSystem type and permission policy which should be used
|
|
// for the type. The |policy| must be a bitwise-or'd value of
|
|
// storage::FilePermissionPolicy.
|
|
void RegisterFileSystemPermissionPolicy(storage::FileSystemType type,
|
|
int policy);
|
|
|
|
// Returns true if sending MIDI messages is allowed.
|
|
bool CanSendMidiMessage(int child_id);
|
|
|
|
// Returns true if sending system exclusive (SysEx) MIDI messages is allowed.
|
|
bool CanSendMidiSysExMessage(int child_id);
|
|
|
|
// Remove all isolated origins associated with |browser_context| and clear any
|
|
// pointers that may reference |browser_context|. This is
|
|
// typically used when |browser_context| is being destroyed and assumes that
|
|
// no processes are running or will run for that profile; this makes the
|
|
// isolated origin removal safe. Note that |browser_context| cannot be null;
|
|
// i.e., isolated origins that apply globally to all profiles cannot
|
|
// currently be removed, since that is not safe to do at runtime.
|
|
void RemoveStateForBrowserContext(const BrowserContext& browser_context);
|
|
|
|
// Check whether |origin| requires origin-wide process isolation within
|
|
// |isolation_context|.
|
|
//
|
|
// Subdomains of an isolated origin are considered part of that isolated
|
|
// origin. Thus, if https://isolated.foo.com/ had been added as an isolated
|
|
// origin, this will return true for https://isolated.foo.com/,
|
|
// https://bar.isolated.foo.com/, or https://baz.bar.isolated.foo.com/; and
|
|
// it will return false for https://foo.com/ or https://unisolated.foo.com/.
|
|
//
|
|
// |isolation_context| is used to determine which origins are isolated in
|
|
// this context. For example, isolated origins that are dynamically added
|
|
// will only affect future BrowsingInstances. |origin_requests_isolation| may
|
|
// be true during navigation requests, and allows us to correctly determine
|
|
// isolation status for an origin that may not have had its isolation status
|
|
// recorded in the BrowsingInstance yet.
|
|
bool IsIsolatedOrigin(const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
bool origin_requests_isolation);
|
|
|
|
// Removes a previously added isolated origin, currently only used in tests.
|
|
//
|
|
// TODO(alexmos): Exposing this more generally will require extra care, such
|
|
// as ensuring that there are no active SiteInstances in that origin.
|
|
void RemoveIsolatedOriginForTesting(const url::Origin& origin);
|
|
|
|
// Returns false for redirects that must be blocked no matter which renderer
|
|
// process initiated the request (if any).
|
|
// Note: Checking CanRedirectToURL is not enough. CanRequestURL(child_id, url)
|
|
// represents a stricter subset. It must also be used for
|
|
// renderer-initiated navigations.
|
|
bool CanRedirectToURL(const GURL& url);
|
|
|
|
// Sets "killed_process_origin_lock" crash key with lock info for the
|
|
// process associated with |child_id|.
|
|
void LogKilledProcessOriginLock(int child_id);
|
|
|
|
// Creates a Handle object for a specific child process ID.
|
|
//
|
|
// This handle can be used to extend the lifetime of policy state beyond
|
|
// the Remove() call for |child_id|. This should be used by objects that can
|
|
// outlive the RenderProcessHostImpl object associated with |child_id| and
|
|
// need to be able to make policy decisions after RPHI destruction. (e.g.
|
|
// Mojo services created by RPHI)
|
|
//
|
|
// Returns a valid Handle for any |child_id| that is present in
|
|
// |security_state_|. Otherwise it returns a Handle that returns false for
|
|
// all policy checks.
|
|
Handle CreateHandle(int child_id);
|
|
|
|
// Returns true if we have seen an explicit Origin-Agent-Cluster header
|
|
// (either opt-in or opt-out) for this |origin| in the given |browser_context|
|
|
// before in any BrowsingInstance.
|
|
bool HasOriginEverRequestedOriginAgentClusterValue(
|
|
BrowserContext* browser_context,
|
|
const url::Origin& origin);
|
|
|
|
// Adds |origin| to the opt-in-out list as having the default isolation state
|
|
// for the BrowsingInstance specified by |isolation_context|, if we need to
|
|
// track it and it's not already in the list.
|
|
// |is_global_walk_or_frame_removal| should be set to true during the global
|
|
// walk that is triggered when |origin| first requests opt-in isolation, so
|
|
// that the function can skip safety checks that will be unnecessary during
|
|
// the global walk. It is also set to true if this function is called when
|
|
// removing a FrameNavigationEntry, since that entry won't be available to any
|
|
// subsequent global walks.
|
|
void AddDefaultIsolatedOriginIfNeeded(
|
|
const IsolationContext& isolation_context,
|
|
const url::Origin& origin,
|
|
bool is_global_walk_or_frame_removal);
|
|
|
|
// Add `origin` to the list of committed origins for the process identified by
|
|
// `child_id`. An attempt to add the same origin more than once is safely
|
|
// ignored. Note that there is currently no way to revoke an origin once it
|
|
// has been committed, even if all associated documents and workers go away.
|
|
// This might need to be revisited in the future if the list of committed
|
|
// origins grows too large.
|
|
void AddCommittedOrigin(int child_id, const url::Origin& origin);
|
|
|
|
// Allows tests to modify the delay in cleaning up BrowsingInstanceIds. If the
|
|
// delay is set to zero, cleanup happens immediately.
|
|
void SetBrowsingInstanceCleanupDelayForTesting(int64_t delay_in_seconds) {
|
|
browsing_instance_cleanup_delay_ = base::Seconds(delay_in_seconds);
|
|
}
|
|
|
|
// Allows tests to query the number of BrowsingInstanceIds associated with a
|
|
// child process.
|
|
size_t BrowsingInstanceIdCountForTesting(int child_id);
|
|
|
|
void ClearRegisteredSchemeForTesting(const std::string& scheme);
|
|
|
|
// Checks if the provided `url` matches any committed origin in the process
|
|
// `child_id`. Currently only exposed for testing, since normally this check
|
|
// happens within CanAccessMaybeOpaqueOrigin().
|
|
bool MatchesCommittedOriginForTesting(int child_id,
|
|
const GURL& url,
|
|
bool url_is_for_precursor_origin);
|
|
|
|
// Exposes LookupOriginIsolationState() for tests.
|
|
OriginAgentClusterIsolationState* LookupOriginIsolationStateForTesting(
|
|
const BrowsingInstanceId& browsing_instance_id,
|
|
const url::Origin& origin);
|
|
|
|
private:
|
|
friend class ChildProcessSecurityPolicyInProcessBrowserTest;
|
|
friend class ChildProcessSecurityPolicyTest;
|
|
friend class ChildProcessSecurityPolicyImpl::Handle;
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyInProcessBrowserTest,
|
|
NoLeak);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, FilePermissions);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
AddFutureIsolatedOrigins);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
DynamicIsolatedOrigins);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
IsolatedOriginsForSpecificBrowserContexts);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
IsolatedOriginsForSpecificBrowsingInstances);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
IsolatedOriginsForCurrentAndFutureBrowsingInstances);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
IsolatedOriginsRemovedWhenBrowserContextDestroyed);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
IsolateAllSuborigins);
|
|
FRIEND_TEST_ALL_PREFIXES(
|
|
ChildProcessSecurityPolicyTest_NoOriginKeyedProcessesByDefault,
|
|
WildcardAndNonWildcardOrigins);
|
|
FRIEND_TEST_ALL_PREFIXES(
|
|
ChildProcessSecurityPolicyTest_NoOriginKeyedProcessesByDefault,
|
|
WildcardAndNonWildcardEmbedded);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
ParseIsolatedOrigins);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, WildcardDefaultPort);
|
|
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest,
|
|
MatchesCommittedOrigin);
|
|
|
|
class SecurityState;
|
|
|
|
typedef std::set<std::string> SchemeSet;
|
|
typedef std::map<int, std::unique_ptr<SecurityState>> SecurityStateMap;
|
|
typedef std::map<storage::FileSystemType, int> FileSystemPermissionPolicyMap;
|
|
|
|
// This class holds an isolated origin along with information such as which
|
|
// BrowsingInstances and profile it applies to. See |isolated_origins_|
|
|
// below for more details.
|
|
class CONTENT_EXPORT IsolatedOriginEntry {
|
|
public:
|
|
IsolatedOriginEntry(const url::Origin& origin,
|
|
bool applies_to_future_browsing_instances,
|
|
BrowsingInstanceId browsing_instance_id,
|
|
BrowserContext* browser_context,
|
|
ResourceContext* resource_context,
|
|
bool isolate_all_subdomains,
|
|
IsolatedOriginSource source);
|
|
// Copyable and movable.
|
|
IsolatedOriginEntry(const IsolatedOriginEntry& other);
|
|
IsolatedOriginEntry& operator=(const IsolatedOriginEntry& other);
|
|
IsolatedOriginEntry(IsolatedOriginEntry&& other);
|
|
IsolatedOriginEntry& operator=(IsolatedOriginEntry&& other);
|
|
~IsolatedOriginEntry();
|
|
|
|
// Allow this class to be used as a key in STL.
|
|
bool operator<(const IsolatedOriginEntry& other) const {
|
|
return std::tie(origin_, applies_to_future_browsing_instances_,
|
|
browsing_instance_id_, browser_context_,
|
|
resource_context_, isolate_all_subdomains_, source_) <
|
|
std::tie(other.origin_,
|
|
other.applies_to_future_browsing_instances_,
|
|
other.browsing_instance_id_, other.browser_context_,
|
|
other.resource_context_, other.isolate_all_subdomains_,
|
|
source_);
|
|
}
|
|
|
|
bool operator==(const IsolatedOriginEntry& other) const {
|
|
return origin_ == other.origin_ &&
|
|
applies_to_future_browsing_instances_ ==
|
|
other.applies_to_future_browsing_instances_ &&
|
|
browsing_instance_id_ == other.browsing_instance_id_ &&
|
|
browser_context_ == other.browser_context_ &&
|
|
resource_context_ == other.resource_context_ &&
|
|
isolate_all_subdomains_ == other.isolate_all_subdomains_ &&
|
|
source_ == other.source_;
|
|
}
|
|
|
|
// True if this isolated origin applies globally to all profiles.
|
|
bool AppliesToAllBrowserContexts() const;
|
|
|
|
// True if (1) this entry is associated with the same profile as
|
|
// |browser_or_resource_context|, or (2) this entry applies to all
|
|
// profiles. May be used on UI or IO threads.
|
|
bool MatchesProfile(
|
|
const BrowserOrResourceContext& browser_or_resource_context) const;
|
|
|
|
// True if this entry applies to the BrowsingInstance specified by
|
|
// `browsing_instance_id`. See `applies_to_future_browsing_instances_` and
|
|
// `browsing_instance_id_` for more details.
|
|
bool MatchesBrowsingInstance(BrowsingInstanceId browsing_instance_id) const;
|
|
|
|
const url::Origin& origin() const { return origin_; }
|
|
|
|
// See the declaration of `applies_to_future_browsing_instances_` for
|
|
// details.
|
|
bool applies_to_future_browsing_instances() const {
|
|
return applies_to_future_browsing_instances_;
|
|
}
|
|
|
|
// See the declaration of `browsing_instance_id_` for details.
|
|
BrowsingInstanceId browsing_instance_id() const {
|
|
return browsing_instance_id_;
|
|
}
|
|
|
|
const BrowserContext* browser_context() const { return browser_context_; }
|
|
|
|
bool isolate_all_subdomains() const { return isolate_all_subdomains_; }
|
|
|
|
IsolatedOriginSource source() const { return source_; }
|
|
|
|
private:
|
|
url::Origin origin_;
|
|
|
|
// If this is false, the origin is isolated only in the BrowsingInstance
|
|
// specified by `browsing_instance_id_`. If this is true, the origin is
|
|
// isolated in all BrowsingInstances that have an ID equal to or
|
|
// greater than `browsing_instance_id_`.
|
|
bool applies_to_future_browsing_instances_;
|
|
|
|
// Specifies which BrowsingInstance(s) this IsolatedOriginEntry applies to.
|
|
// When `applies_to_future_browsing_instances_` is false, this refers to a
|
|
// specific BrowsingInstance. Otherwise, it specifies the minimum
|
|
// BrowsingInstance ID, and the origin is isolated in all
|
|
// BrowsingInstances with IDs greater than or equal to this value.
|
|
BrowsingInstanceId browsing_instance_id_;
|
|
|
|
// Optional information about the profile where the isolated origin
|
|
// applies. |browser_context_| may be used on the UI thread, and
|
|
// |resource_context_| may be used on the IO thread. If these are null,
|
|
// then the isolated origin applies globally to all profiles.
|
|
raw_ptr<BrowserContext> browser_context_;
|
|
raw_ptr<ResourceContext> resource_context_;
|
|
|
|
// True if origins at this or lower level should be treated as distinct
|
|
// isolated origins, effectively isolating all domains below a given domain,
|
|
// e.g. if the origin is https://foo.com and isolate_all_subdomains_ is
|
|
// true, then https://bar.foo.com, https://qux.bar.foo.com and all
|
|
// subdomains of the form https://<<any pattern here>>.foo.com are
|
|
// considered isolated origins.
|
|
bool isolate_all_subdomains_;
|
|
|
|
// This tracks the source of each isolated origin entry, e.g., to
|
|
// distinguish those that should be displayed to the user from those that
|
|
// should not. See https://crbug.com/920911.
|
|
IsolatedOriginSource source_;
|
|
};
|
|
|
|
// A struct to hold the OAC opted-in origins and their isolation state. It
|
|
// associates a specific |origin| with its OriginAgentClusterIsolationState,
|
|
// and is tracked in |origin_isolation_by_browsing_instance_|.
|
|
struct OriginAgentClusterOptInEntry {
|
|
OriginAgentClusterOptInEntry(
|
|
const OriginAgentClusterIsolationState& oac_isolation_state_in,
|
|
const url::Origin& origin_in);
|
|
OriginAgentClusterOptInEntry(const OriginAgentClusterOptInEntry&);
|
|
~OriginAgentClusterOptInEntry();
|
|
|
|
OriginAgentClusterIsolationState oac_isolation_state;
|
|
url::Origin origin;
|
|
};
|
|
|
|
// Obtain an instance of ChildProcessSecurityPolicyImpl via GetInstance().
|
|
ChildProcessSecurityPolicyImpl();
|
|
friend struct base::DefaultSingletonTraits<ChildProcessSecurityPolicyImpl>;
|
|
|
|
// Determines if certain permissions were granted for a file to given child
|
|
// process. |permissions| is an internally defined bit-set.
|
|
bool ChildProcessHasPermissionsForFile(int child_id,
|
|
const base::FilePath& file,
|
|
int permissions)
|
|
EXCLUSIVE_LOCKS_REQUIRED(lock_);
|
|
|
|
// Grant a particular permission set for a file. |permissions| is an
|
|
// internally defined bit-set.
|
|
void GrantPermissionsForFile(int child_id,
|
|
const base::FilePath& file,
|
|
int permissions);
|
|
|
|
// Grants access permission to the given isolated file system
|
|
// identified by |filesystem_id|. See comments for
|
|
// ChildProcessSecurityPolicy::GrantReadFileSystem() for more details.
|
|
void GrantPermissionsForFileSystem(int child_id,
|
|
const std::string& filesystem_id,
|
|
int permission);
|
|
|
|
// Determines if certain permissions were granted for a file. |permissions|
|
|
// is an internally defined bit-set.
|
|
bool HasPermissionsForFile(int child_id,
|
|
const base::FilePath& file,
|
|
int permissions);
|
|
|
|
// Determines if certain permissions were granted for a file in FileSystem
|
|
// API. |permissions| is an internally defined bit-set.
|
|
bool HasPermissionsForFileSystemFile(
|
|
int child_id,
|
|
const storage::FileSystemURL& filesystem_url,
|
|
int permissions);
|
|
|
|
// Determines if certain permissions were granted for a file system.
|
|
// |permissions| is an internally defined bit-set.
|
|
bool HasPermissionsForFileSystem(int child_id,
|
|
const std::string& filesystem_id,
|
|
int permission);
|
|
|
|
// Gets the SecurityState object associated with |child_id|.
|
|
// Note: Returned object is only valid for the duration the caller holds
|
|
// |lock_|.
|
|
SecurityState* GetSecurityState(int child_id) EXCLUSIVE_LOCKS_REQUIRED(lock_);
|
|
|
|
// Convert a list of comma separated isolated origins in |pattern_list|,
|
|
// specified either as wildcard origins, non-wildcard origins or a mix of the
|
|
// two into IsolatedOriginPatterns, suitable for addition via
|
|
// AddFutureIsolatedOrigins().
|
|
static std::vector<IsolatedOriginPattern> ParseIsolatedOrigins(
|
|
std::string_view pattern_list);
|
|
|
|
void AddFutureIsolatedOrigins(
|
|
const std::vector<IsolatedOriginPattern>& patterns,
|
|
IsolatedOriginSource source,
|
|
BrowserContext* browser_context = nullptr);
|
|
|
|
// Internal helper used for adding a particular isolated origin. See
|
|
// IsolatedOriginEntry for descriptions of various parameters.
|
|
void AddIsolatedOriginInternal(BrowserContext* browser_context,
|
|
const url::Origin& origin,
|
|
bool applies_to_future_browsing_instances,
|
|
BrowsingInstanceId browsing_instance_id,
|
|
bool isolate_all_subdomains,
|
|
IsolatedOriginSource source)
|
|
EXCLUSIVE_LOCKS_REQUIRED(isolated_origins_lock_);
|
|
|
|
bool AddProcessReference(int child_id, bool duplicating_handle);
|
|
bool AddProcessReferenceLocked(int child_id, bool duplicating_handle)
|
|
EXCLUSIVE_LOCKS_REQUIRED(lock_);
|
|
void RemoveProcessReference(int child_id);
|
|
void RemoveProcessReferenceLocked(int child_id)
|
|
EXCLUSIVE_LOCKS_REQUIRED(lock_);
|
|
|
|
// Internal helper for RemoveOptInIsolatedOriginsForBrowsingInstance().
|
|
void RemoveOptInIsolatedOriginsForBrowsingInstanceInternal(
|
|
const BrowsingInstanceId browsing_instance_id);
|
|
|
|
// Creates the value to place in the "killed_process_origin_lock" crash key
|
|
// based on the contents of |security_state|.
|
|
static std::string GetKilledProcessOriginLock(
|
|
const SecurityState* security_state);
|
|
|
|
// Helper for CanAccessMaybeOpaqueOrigin, to perform two security checks:
|
|
// - Jail check: a process locked to a particular site shouldn't access data
|
|
// belonging to other sites.
|
|
// - Citadel check: a process not locked to any site shouldn't access data
|
|
// belonging to sites that require a dedicated process.
|
|
//
|
|
// These checks are performed by comparing the actual ProcessLock of the
|
|
// process represented by `child_id` and `security_state` to an expected
|
|
// ProcessLock computed from `url`, which takes into account factors such as
|
|
// whether `url` should be site-isolated or origin-isolated (or not isolated,
|
|
// e.g. on Android). Determining site-vs-origin isolation is non-trivial: the
|
|
// answer may differ depending on BrowsingInstance (e.g., OriginAgentCluster
|
|
// might require origin isolation only for certain BrowsingInstances), so all
|
|
// BrowsingInstances hosting in the process must be consulted.
|
|
//
|
|
// This function returns true only if both Jail and Citadel checks pass. On
|
|
// failure, it also populates `out_failure_reason` with debugging information
|
|
// about the cause of the failure, as well as `out_expected_process_lock` with
|
|
// what the process lock was expected to be (e.g., to be used in crash keys).
|
|
//
|
|
// This function must be called while already holding `lock_`.
|
|
bool PerformJailAndCitadelChecks(int child_id,
|
|
SecurityState* security_state,
|
|
const GURL& url,
|
|
bool url_is_precursor_of_opaque_origin,
|
|
AccessType access_type,
|
|
ProcessLock& out_expected_process_lock,
|
|
std::string& out_failure_reason)
|
|
EXCLUSIVE_LOCKS_REQUIRED(lock_);
|
|
|
|
// Helper for public CanAccessOrigin overloads.
|
|
bool CanAccessMaybeOpaqueOrigin(int child_id,
|
|
const GURL& url,
|
|
bool url_is_precursor_of_opaque_origin,
|
|
AccessType access_type);
|
|
|
|
// Helper used by CanAccessOrigin to impose additional restrictions on a
|
|
// sandboxed process locked to `process_lock`.
|
|
bool IsAccessAllowedForSandboxedProcess(const ProcessLock& process_lock,
|
|
const GURL& url,
|
|
bool url_is_for_opaque_origin,
|
|
AccessType access_type);
|
|
|
|
// Helper used by CanAccessOrigin to impose additional restrictions on a
|
|
// process that only hosts PDF documents.
|
|
bool IsAccessAllowedForPdfProcess(AccessType access_type);
|
|
|
|
// Utility function to simplify lookups for OriginAgentClusterOptInEntry
|
|
// values by origin.
|
|
OriginAgentClusterIsolationState* LookupOriginIsolationState(
|
|
const BrowsingInstanceId& browsing_instance_id,
|
|
const url::Origin& origin)
|
|
EXCLUSIVE_LOCKS_REQUIRED(origins_isolation_opt_in_lock_);
|
|
|
|
// You must acquire this lock before reading or writing any members of this
|
|
// class, except for isolated_origins_, schemes_okay_to_*, and
|
|
// pseudo_schemes_, which use their own locks. You must not block while
|
|
// holding this lock.
|
|
base::Lock lock_;
|
|
|
|
// These schemes are allow-listed for all child processes in various contexts.
|
|
// These sets are protected by |schemes_lock_| rather than |lock_|.
|
|
base::Lock schemes_lock_;
|
|
SchemeSet schemes_okay_to_commit_in_any_process_ GUARDED_BY(schemes_lock_);
|
|
SchemeSet schemes_okay_to_request_in_any_process_ GUARDED_BY(schemes_lock_);
|
|
SchemeSet schemes_okay_to_appear_as_origin_headers_ GUARDED_BY(schemes_lock_);
|
|
|
|
// These schemes do not actually represent retrievable URLs. For example,
|
|
// the the URLs in the "about" scheme are aliases to other URLs. This set is
|
|
// protected by |schemes_lock_|.
|
|
SchemeSet pseudo_schemes_ GUARDED_BY(schemes_lock_);
|
|
|
|
// This map holds a SecurityState for each child process. The key for the
|
|
// map is the ID of the ChildProcessHost. The SecurityState objects are
|
|
// owned by this object and are protected by |lock_|. References to them must
|
|
// not escape this class.
|
|
SecurityStateMap security_state_ GUARDED_BY(lock_);
|
|
|
|
// This map holds the SecurityState for a child process after Remove()
|
|
// is called on the UI thread. An entry stays in this map until a task has
|
|
// run on the IO thread. This is necessary to provide consistent security
|
|
// decisions and avoid races between the UI & IO threads during child process
|
|
// shutdown. This separate map is used to preserve SecurityState info AND
|
|
// preventing mutation of that state after Remove() is called.
|
|
SecurityStateMap pending_remove_state_ GUARDED_BY(lock_);
|
|
|
|
FileSystemPermissionPolicyMap file_system_policy_map_ GUARDED_BY(lock_);
|
|
|
|
// Contains a mapping between child process ID and the number of outstanding
|
|
// references that want to keep the SecurityState for each process alive.
|
|
// This object and Handles created by this object increment/decrement
|
|
// the counts in this map and only destroy a SecurityState object for a
|
|
// process when its count goes to zero.
|
|
std::map<int, int> process_reference_counts_ GUARDED_BY(lock_);
|
|
|
|
// You must acquire this lock before reading or writing isolated_origins_.
|
|
// You must not block while holding this lock.
|
|
//
|
|
// It is allowed to hold both |lock_| and |isolated_origins_lock_|, but in
|
|
// this case, |lock_| should always be acquired first to prevent deadlock.
|
|
base::Lock isolated_origins_lock_ ACQUIRED_AFTER(lock_);
|
|
|
|
// Tracks origins for which the entire origin should be treated as a site
|
|
// when making process model decisions, rather than the origin's scheme and
|
|
// eTLD+1. Each of these origins requires a dedicated process. This set is
|
|
// protected by |isolated_origins_lock_|.
|
|
//
|
|
// The origins are stored in a map indexed by a site URL computed for each
|
|
// origin. For example, adding https://foo.com, https://bar.foo.com, and
|
|
// https://www.bar.com would result in the following structure:
|
|
// https://foo.com -> { https://foo.com, https://bar.foo.com }
|
|
// https://bar.com -> { https://www.bar.com }
|
|
// This organization speeds up lookups of isolated origins. The site can be
|
|
// found in O(log n) time, and the corresponding list of origins to search
|
|
// using the expensive DoesOriginMatchIsolatedOrigin() comparison is
|
|
// typically small.
|
|
//
|
|
// Each origin entry stores information about:
|
|
// 1. Which BrowsingInstances it applies to. This is a combination of a
|
|
// BrowsingInstance ID |browsing_instance_id_| and a bool flag
|
|
// |applies_to_future_browsing_instances_| stored in in each origin's
|
|
// IsolatedOriginEntry. When |applies_to_future_browsing_instances_| is
|
|
// true, the origin will be isolated in all BrowsingInstances with
|
|
// IDs equal to or greater than |browsing_instance_id_|. When
|
|
// |applies_to_future_browsing_instances_| is false, the origin will be
|
|
// isolated only in a single BrowsingInstance with ID
|
|
// |browsing_instance_id_|.
|
|
// 2. Optionally, which BrowserContext (profile) it applies to. When the
|
|
// |browser_context| field in the IsolatedOriginEntry is non-null, a
|
|
// particular isolated origin entry only applies to that BrowserContext.
|
|
// A ResourceContext, BrowserContext's representation on the IO thread,
|
|
// is also stored in the entry to facilitate checks on the IO thread.
|
|
// Note that the same origin may be isolated in different profiles,
|
|
// possibly with different BrowsingInstance ID cut-offs. For example:
|
|
// https://foo.com -> { [https://test.foo.com profile1 4],
|
|
// [https://test.foo.com profile2 7] }
|
|
// represents https://test.foo.com being isolated in profile1
|
|
// with BrowsingInstance ID 4, and also in profile2 with
|
|
// BrowsingInstance ID 7.
|
|
base::flat_map<GURL, std::vector<IsolatedOriginEntry>> isolated_origins_
|
|
GUARDED_BY(isolated_origins_lock_);
|
|
|
|
// TODO(wjmaclean): Move these lists into a per-BrowserContext container, to
|
|
// prevent any record of sites visible in one profile from being visible to
|
|
// another profile.
|
|
base::Lock origins_isolation_opt_in_lock_;
|
|
// The set of all origins that have ever requested opt-in isolation or
|
|
// requested to opt-out, organized by BrowserContext. This is tracked so we
|
|
// know which origins need to be tracked when using default isolation in any
|
|
// given BrowsingInstance. Origins requesting isolation opt-in or out, if
|
|
// successful, are marked as isolated or not via
|
|
// DetermineOriginAgentClusterIsolation's checking
|
|
// |requested_isolation_state|. Each BrowserContext's state is tracked
|
|
// separately so that timing attacks do not reveal whether an origin has been
|
|
// visited in another (e.g., incognito) BrowserContext. In general, the state
|
|
// of other BrowsingInstances is not observable outside such timing side
|
|
// channels.
|
|
base::flat_map<BrowserContext*, base::flat_set<url::Origin>>
|
|
origin_isolation_opt_ins_and_outs_
|
|
GUARDED_BY(origins_isolation_opt_in_lock_);
|
|
|
|
// A map to track origins that have been isolated within a given
|
|
// BrowsingInstance, or that have been loaded in a BrowsingInstance
|
|
// without isolation, but that have requested isolation in at least one other
|
|
// BrowsingInstance. Origins loaded without isolation are tracked to make sure
|
|
// we don't try to isolate the origin in the associated BrowsingInstance at a
|
|
// later time, in order to keep the isolation consistent over the lifetime of
|
|
// the BrowsingInstance.
|
|
base::flat_map<BrowsingInstanceId, std::vector<OriginAgentClusterOptInEntry>>
|
|
origin_isolation_by_browsing_instance_
|
|
GUARDED_BY(origins_isolation_opt_in_lock_);
|
|
|
|
// When we are notified a BrowsingInstance has destructed, delay cleanup by
|
|
// this amount to allow outstanding IO thread requests to complete. May be set
|
|
// to different values in tests. Note: the value is chosen to be slightly
|
|
// longer than the KeepAliveHandleFactory delay of 30 seconds, with the aim of
|
|
// covering the maximum time needed by any IncrementKeepAliveRefCount callers.
|
|
// TODO(wjmaclean): we know the IncrementKeepAliveRefCount API needs
|
|
// improvement, and with it the BrowsingInstance cleanup here can also be
|
|
// improved.
|
|
base::TimeDelta browsing_instance_cleanup_delay_;
|
|
};
|
|
|
|
} // namespace content
|
|
|
|
#endif // CONTENT_BROWSER_CHILD_PROCESS_SECURITY_POLICY_IMPL_H_
|