blob: 0acae529bf4f63604d892f45d5de3d35cd45457d [file] [log] [blame]
// Copyright 2015 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/public/browser/site_isolation_policy.h"
#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/field_trial_params.h"
#include "base/no_destructor.h"
#include "base/strings/string_split.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/site_isolation_mode.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/switches.h"
#include "url/origin.h"
namespace content {
namespace {
bool g_disable_flag_caching_for_tests = false;
bool IsDisableSiteIsolationFlagPresent() {
static const bool site_isolation_disabled =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSiteIsolation);
if (g_disable_flag_caching_for_tests) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSiteIsolation);
}
return site_isolation_disabled;
}
#if BUILDFLAG(IS_ANDROID)
bool IsDisableSiteIsolationForPolicyFlagPresent() {
static const bool site_isolation_disabled_by_policy =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSiteIsolationForPolicy);
if (g_disable_flag_caching_for_tests) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSiteIsolationForPolicy);
}
return site_isolation_disabled_by_policy;
}
#endif
bool IsSiteIsolationDisabled(SiteIsolationMode site_isolation_mode) {
if (IsDisableSiteIsolationFlagPresent()) {
return true;
}
#if BUILDFLAG(IS_ANDROID)
// Desktop platforms no longer support disabling Site Isolation by policy.
if (IsDisableSiteIsolationForPolicyFlagPresent()) {
return true;
}
#endif
// Check with the embedder. In particular, chrome/ uses this to disable site
// isolation when below a memory threshold.
return GetContentClient() &&
GetContentClient()->browser()->ShouldDisableSiteIsolation(
site_isolation_mode);
}
} // namespace
// static
bool SiteIsolationPolicy::UseDedicatedProcessesForAllSites() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess)) {
return true;
}
if (IsSiteIsolationDisabled(SiteIsolationMode::kStrictSiteIsolation))
return false;
// The switches above needs to be checked first, because if the
// ContentBrowserClient consults a base::Feature, then it will activate the
// field trial and assigns the client either to a control or an experiment
// group - such assignment should be final.
return GetContentClient() &&
GetContentClient()->browser()->ShouldEnableStrictSiteIsolation();
}
// static
bool SiteIsolationPolicy::AreIsolatedSandboxedIframesEnabled() {
// This feature is controlled by kIsolateSandboxedIframes, and depends on
// partial Site Isolation being enabled. It also requires new base URL
// behavior, so it implicitly causes
// blink::features::IsNewBaseUrlInheritanceBehaviorEnabled() to return true,
// and can't be enabled if the new base URL behavior has been disabled by
// enterprise policy.
return base::FeatureList::IsEnabled(
blink::features::kIsolateSandboxedIframes) &&
!IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation) &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
blink::switches::kDisableNewBaseUrlInheritanceBehavior);
}
// static
bool SiteIsolationPolicy::AreIsolatedOriginsEnabled() {
// NOTE: Because it is possible for --isolate-origins to be isolating origins
// at a finer-than-site granularity, we do not suppress --isolate-origins when
// --site-per-process is also enabled.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIsolateOrigins)) {
return true;
}
if (IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation))
return false;
// The feature needs to be checked last, because checking the feature
// activates the field trial and assigns the client either to a control or an
// experiment group - such assignment should be final.
return base::FeatureList::IsEnabled(features::kIsolateOrigins);
}
// static
bool SiteIsolationPolicy::IsStrictOriginIsolationEnabled() {
// If the feature is explicitly enabled by the user (e.g., from
// chrome://flags), honor this regardless of checks to disable site isolation
// below. This means this takes precedence over memory thresholds or
// switches to disable site isolation.
if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
features::kStrictOriginIsolation.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE)) {
return true;
}
// TODO(wjmaclean): Figure out what should happen when this feature is
// combined with --isolate-origins.
//
// TODO(alexmos): For now, use the same memory threshold for strict origin
// isolation and strict site isolation. In the future, strict origin
// isolation may need its own memory threshold.
if (IsSiteIsolationDisabled(SiteIsolationMode::kStrictSiteIsolation))
return false;
// The feature needs to be checked last, because checking the feature
// activates the field trial and assigns the client either to a control or an
// experiment group - such assignment should be final.
return base::FeatureList::IsEnabled(features::kStrictOriginIsolation);
}
// static
bool SiteIsolationPolicy::IsErrorPageIsolationEnabled(bool in_main_frame) {
return GetContentClient()->browser()->ShouldIsolateErrorPage(in_main_frame);
}
// static
bool SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled() {
return !IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation);
}
// static
bool SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled() {
if (IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation))
return false;
// Currently, preloaded isolated origins are redundant when full site
// isolation is enabled. This may be true on Android if full site isolation
// is enabled manually or via field trials.
if (UseDedicatedProcessesForAllSites())
return false;
return true;
}
// static
bool SiteIsolationPolicy::IsProcessIsolationForOriginAgentClusterEnabled() {
// If strict site isolation is in use (either by default on desktop or via a
// user opt-in on Android), unconditionally enable opt-in origin isolation.
if (UseDedicatedProcessesForAllSites())
return true;
// Otherwise, if site isolation is disabled (e.g., on Android due to being
// under a memory threshold), turn off opt-in origin isolation.
if (IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation))
return false;
return IsOriginAgentClusterEnabled();
}
// static
bool SiteIsolationPolicy::IsOriginAgentClusterEnabled() {
return base::FeatureList::IsEnabled(features::kOriginIsolationHeader);
}
// static
bool SiteIsolationPolicy::AreOriginAgentClustersEnabledByDefault(
BrowserContext* browser_context) {
// OriginAgentClusters are enabled by default if OriginAgentCluster and
// kOriginAgentClusterDefaultEnabled are enabled, and if there is no
// enterprise policy forbidding it.
// This also returns true if kOriginKeyedProcessesByDefault is enabled,
// because it depends on having OriginAgentClusters by default. This can be
// handled here because this function is the only place that
// kOriginAgentClusterDefaultEnabled is directly checked.
return IsOriginAgentClusterEnabled() &&
(base::FeatureList::IsEnabled(
blink::features::kOriginAgentClusterDefaultEnabled) ||
base::FeatureList::IsEnabled(
features::kOriginKeyedProcessesByDefault)) &&
!GetContentClient()->browser()->ShouldDisableOriginAgentClusterDefault(
browser_context);
}
// static
bool SiteIsolationPolicy::IsSiteIsolationForCOOPEnabled() {
// If the user has explicitly enabled site isolation for COOP sites from the
// command line, honor this regardless of policies that may disable site
// isolation.
if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
features::kSiteIsolationForCrossOriginOpenerPolicy.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE)) {
return true;
}
// Don't apply COOP isolation if site isolation has been disabled (e.g., due
// to memory thresholds).
if (!SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled())
return false;
// COOP isolation is only needed on platforms where strict site isolation is
// not used.
if (UseDedicatedProcessesForAllSites())
return false;
// The feature needs to be checked last, because checking the feature
// activates the field trial and assigns the client either to a control or an
// experiment group - such assignment should be final.
return base::FeatureList::IsEnabled(
features::kSiteIsolationForCrossOriginOpenerPolicy);
}
// static
bool SiteIsolationPolicy::ShouldPersistIsolatedCOOPSites() {
if (!IsSiteIsolationForCOOPEnabled())
return false;
return features::kSiteIsolationForCrossOriginOpenerPolicyShouldPersistParam
.Get();
}
// static
std::string SiteIsolationPolicy::GetIsolatedOriginsFromCommandLine() {
std::string cmdline_arg =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kIsolateOrigins);
return cmdline_arg;
}
std::string SiteIsolationPolicy::GetIsolatedOriginsFromFieldTrial() {
std::string origins;
// Check if site isolation modes are turned off (e.g., due to an opt-out
// flag).
if (IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation))
return origins;
// The feature needs to be checked after the opt-out, because checking the
// feature activates the field trial and assigns the client either to a
// control or an experiment group - such assignment should be final.
if (base::FeatureList::IsEnabled(features::kIsolateOrigins)) {
origins = base::GetFieldTrialParamValueByFeature(
features::kIsolateOrigins,
features::kIsolateOriginsFieldTrialParamName);
}
return origins;
}
void SiteIsolationPolicy::ApplyGlobalIsolatedOrigins() {
ChildProcessSecurityPolicy* policy =
ChildProcessSecurityPolicy::GetInstance();
std::string from_cmdline = GetIsolatedOriginsFromCommandLine();
policy->AddFutureIsolatedOrigins(
from_cmdline,
ChildProcessSecurityPolicy::IsolatedOriginSource::COMMAND_LINE);
std::string from_trial = GetIsolatedOriginsFromFieldTrial();
policy->AddFutureIsolatedOrigins(
from_trial,
ChildProcessSecurityPolicy::IsolatedOriginSource::FIELD_TRIAL);
std::vector<url::Origin> from_embedder =
GetContentClient()->browser()->GetOriginsRequiringDedicatedProcess();
policy->AddFutureIsolatedOrigins(
from_embedder,
ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN);
}
// static
bool SiteIsolationPolicy::ShouldUrlUseApplicationIsolationLevel(
BrowserContext* browser_context,
const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return GetContentClient()->browser()->ShouldUrlUseApplicationIsolationLevel(
browser_context, url);
}
// static
void SiteIsolationPolicy::DisableFlagCachingForTesting() {
g_disable_flag_caching_for_tests = true;
}
// static
bool SiteIsolationPolicy::IsProcessIsolationForFencedFramesEnabled() {
// If the user has explicitly enabled process isolation for fenced frames from
// the command line, honor this regardless of policies that may disable site
// isolation.
if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
features::kIsolateFencedFrames.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE)) {
return true;
}
return UseDedicatedProcessesForAllSites() &&
base::FeatureList::IsEnabled(features::kIsolateFencedFrames);
}
} // namespace content