diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/site_isolation | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/site_isolation')
-rw-r--r-- | chromium/components/site_isolation/BUILD.gn | 26 | ||||
-rw-r--r-- | chromium/components/site_isolation/DEPS | 7 | ||||
-rw-r--r-- | chromium/components/site_isolation/features.cc | 44 | ||||
-rw-r--r-- | chromium/components/site_isolation/features.h | 20 | ||||
-rw-r--r-- | chromium/components/site_isolation/pref_names.cc | 17 | ||||
-rw-r--r-- | chromium/components/site_isolation/pref_names.h | 16 | ||||
-rw-r--r-- | chromium/components/site_isolation/site_isolation_policy.cc | 133 | ||||
-rw-r--r-- | chromium/components/site_isolation/site_isolation_policy.h | 54 | ||||
-rw-r--r-- | chromium/components/site_isolation/site_isolation_policy_unittest.cc | 938 |
9 files changed, 1254 insertions, 1 deletions
diff --git a/chromium/components/site_isolation/BUILD.gn b/chromium/components/site_isolation/BUILD.gn index e079b2436c7..6e877b2c355 100644 --- a/chromium/components/site_isolation/BUILD.gn +++ b/chromium/components/site_isolation/BUILD.gn @@ -27,8 +27,14 @@ buildflag_header("buildflags") { source_set("site_isolation") { sources = [ + "features.cc", + "features.h", + "pref_names.cc", + "pref_names.h", "preloaded_isolated_origins.cc", "preloaded_isolated_origins.h", + "site_isolation_policy.cc", + "site_isolation_policy.h", ] if (use_internal_isolated_origins) { @@ -41,7 +47,27 @@ source_set("site_isolation") { deps = [ ":buildflags", "//base", + "//components/prefs", + "//components/user_prefs", "//content/public/browser", "//url", ] } + +source_set("unit_tests") { + testonly = true + sources = [ "site_isolation_policy_unittest.cc" ] + deps = [ + ":site_isolation", + "//base", + "//base/test:test_support", + "//build:branding_buildflags", + "//components/prefs", + "//components/prefs:test_support", + "//components/user_prefs", + "//components/variations", + "//content/public/browser", + "//content/test:test_support", + "//testing/gtest", + ] +} diff --git a/chromium/components/site_isolation/DEPS b/chromium/components/site_isolation/DEPS index f7bd8874887..aee55fdfec2 100644 --- a/chromium/components/site_isolation/DEPS +++ b/chromium/components/site_isolation/DEPS @@ -1,6 +1,11 @@ include_rules = [ "+base", "+build", + "+components/prefs", + "+components/user_prefs", + "+components/variations", "+content/public/browser", + "+content/public/common", + "+content/public/test", "+url", -]
\ No newline at end of file +] diff --git a/chromium/components/site_isolation/features.cc b/chromium/components/site_isolation/features.cc new file mode 100644 index 00000000000..7d180987b95 --- /dev/null +++ b/chromium/components/site_isolation/features.cc @@ -0,0 +1,44 @@ +// Copyright 2020 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. + +#include "components/site_isolation/features.h" + +#include "build/build_config.h" + +namespace site_isolation { +namespace features { + +// Controls a mode for dynamically process-isolating sites where the user has +// entered a password. This is intended to be used primarily when full site +// isolation is turned off. To check whether this mode is enabled, use +// SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() rather than +// checking the feature directly, since that decision is influenced by other +// factors as well. +const base::Feature kSiteIsolationForPasswordSites { + "site-isolation-for-password-sites", +// Enabled by default on Android; see https://crbug.com/849815. Note that this +// should not affect Android Webview, which does not include this code. +#if defined(OS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; + +// kSitePerProcessOnlyForHighMemoryClients is checked before kSitePerProcess, +// and (if enabled) can restrict if kSitePerProcess feature is checked at all - +// no check will be made on devices with low memory (these devices will have no +// Site Isolation via kSitePerProcess trials and won't activate either the +// control or the experiment group). The threshold for what is considered a +// "low memory" device is set (in MB) via a field trial param with the name +// defined below ("site-per-process-low-memory-cutoff-mb") and compared against +// base::SysInfo::AmountOfPhysicalMemoryMB(). +const base::Feature kSitePerProcessOnlyForHighMemoryClients{ + "site-per-process-only-for-high-memory-clients", + base::FEATURE_DISABLED_BY_DEFAULT}; +const char kSitePerProcessOnlyForHighMemoryClientsParamName[] = + "site-per-process-low-memory-cutoff-mb"; + +} // namespace features +} // namespace site_isolation diff --git a/chromium/components/site_isolation/features.h b/chromium/components/site_isolation/features.h new file mode 100644 index 00000000000..4fb00df2546 --- /dev/null +++ b/chromium/components/site_isolation/features.h @@ -0,0 +1,20 @@ +// Copyright 2020 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 COMPONENTS_SITE_ISOLATION_FEATURES_H_ +#define COMPONENTS_SITE_ISOLATION_FEATURES_H_ + +#include "base/feature_list.h" + +namespace site_isolation { +namespace features { + +extern const base::Feature kSiteIsolationForPasswordSites; +extern const base::Feature kSitePerProcessOnlyForHighMemoryClients; +extern const char kSitePerProcessOnlyForHighMemoryClientsParamName[]; + +} // namespace features +} // namespace site_isolation + +#endif // COMPONENTS_SITE_ISOLATION_FEATURES_H_ diff --git a/chromium/components/site_isolation/pref_names.cc b/chromium/components/site_isolation/pref_names.cc new file mode 100644 index 00000000000..403cf018f8e --- /dev/null +++ b/chromium/components/site_isolation/pref_names.cc @@ -0,0 +1,17 @@ +// Copyright 2020 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. + +#include "components/site_isolation/pref_names.h" + +namespace site_isolation { +namespace prefs { + +// A list of origins that were heuristically determined to need process +// isolation. For example, an origin may be placed on this list in response to +// the user typing a password on it. +const char kUserTriggeredIsolatedOrigins[] = + "site_isolation.user_triggered_isolated_origins"; + +} // namespace prefs +} // namespace site_isolation diff --git a/chromium/components/site_isolation/pref_names.h b/chromium/components/site_isolation/pref_names.h new file mode 100644 index 00000000000..ffdf32f2e1e --- /dev/null +++ b/chromium/components/site_isolation/pref_names.h @@ -0,0 +1,16 @@ +// Copyright 2020 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 COMPONENTS_SITE_ISOLATION_PREF_NAMES_H_ +#define COMPONENTS_SITE_ISOLATION_PREF_NAMES_H_ + +namespace site_isolation { +namespace prefs { + +extern const char kUserTriggeredIsolatedOrigins[]; + +} // namespace prefs +} // namespace site_isolation + +#endif // COMPONENTS_SITE_ISOLATION_PREF_NAMES_H diff --git a/chromium/components/site_isolation/site_isolation_policy.cc b/chromium/components/site_isolation/site_isolation_policy.cc new file mode 100644 index 00000000000..9a91d3034b0 --- /dev/null +++ b/chromium/components/site_isolation/site_isolation_policy.cc @@ -0,0 +1,133 @@ +// Copyright 2019 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. + +#include "components/site_isolation/site_isolation_policy.h" + +#include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram_macros.h" +#include "base/system/sys_info.h" +#include "build/build_config.h" +#include "components/prefs/pref_service.h" +#include "components/site_isolation/features.h" +#include "components/site_isolation/pref_names.h" +#include "components/user_prefs/user_prefs.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/site_isolation_policy.h" + +namespace site_isolation { + +// static +bool SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() { + // If the user has explicitly enabled site isolation for password sites from + // chrome://flags or from the command line, honor this regardless of policies + // that may disable site isolation. In particular, this means that the + // chrome://flags switch for this feature takes precedence over any memory + // threshold restrictions and over a switch for disabling site isolation. + if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine( + features::kSiteIsolationForPasswordSites.name, + base::FeatureList::OVERRIDE_ENABLE_FEATURE)) { + return true; + } + + // Don't isolate anything when site isolation is turned off by the user or + // policy. This includes things like the switches::kDisableSiteIsolation + // command-line switch, the corresponding "Disable site isolation" entry in + // chrome://flags, enterprise policy controlled via + // switches::kDisableSiteIsolationForPolicy, and memory threshold checks in + // ShouldDisableSiteIsolationDueToMemoryThreshold(). + if (!content::SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled()) + 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::kSiteIsolationForPasswordSites); +} + +// static +bool SiteIsolationPolicy::IsEnterprisePolicyApplicable() { +#if defined(OS_ANDROID) + // https://crbug.com/844118: Limiting policy to devices with > 1GB RAM. + // Using 1077 rather than 1024 because 1) it helps ensure that devices with + // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one + // errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2. + bool have_enough_memory = base::SysInfo::AmountOfPhysicalMemoryMB() > 1077; + return have_enough_memory; +#else + return true; +#endif +} + +// static +bool SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold() { + // The memory threshold behavior differs for desktop and Android: + // - Android uses a 1900MB default threshold, which is the threshold used by + // password-triggered site isolation - see docs in + // https://crbug.com/849815. This can be overridden via a param defined in + // a kSitePerProcessOnlyForHighMemoryClients field trial. + // - Desktop does not enforce a default memory threshold, but for now we + // still support a threshold defined via a + // kSitePerProcessOnlyForHighMemoryClients field trial. The trial + // typically carries the threshold in a param; if it doesn't, use a default + // that's slightly higher than 1GB (see https://crbug.com/844118). + // + // TODO(alexmos): currently, this threshold applies to all site isolation + // modes. Eventually, we may need separate thresholds for different modes, + // such as full site isolation vs. password-triggered site isolation. +#if defined(OS_ANDROID) + constexpr int kDefaultMemoryThresholdMb = 1900; +#else + constexpr int kDefaultMemoryThresholdMb = 1077; +#endif + + // TODO(acolwell): Rename feature since it now affects more than just the + // site-per-process case. + if (base::FeatureList::IsEnabled( + features::kSitePerProcessOnlyForHighMemoryClients)) { + int memory_threshold_mb = base::GetFieldTrialParamByFeatureAsInt( + features::kSitePerProcessOnlyForHighMemoryClients, + features::kSitePerProcessOnlyForHighMemoryClientsParamName, + kDefaultMemoryThresholdMb); + return base::SysInfo::AmountOfPhysicalMemoryMB() <= memory_threshold_mb; + } + +#if defined(OS_ANDROID) + if (base::SysInfo::AmountOfPhysicalMemoryMB() <= kDefaultMemoryThresholdMb) { + return true; + } +#endif + + return false; +} + +// static +void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins( + content::BrowserContext* browser_context) { + // If the user turned off password-triggered isolation, don't apply any + // stored isolated origins, but also don't clear them from prefs, so that + // they can be used if password-triggered isolation is re-enabled later. + if (!IsIsolationForPasswordSitesEnabled()) + return; + + std::vector<url::Origin> origins; + for (const auto& value : + *user_prefs::UserPrefs::Get(browser_context) + ->GetList(prefs::kUserTriggeredIsolatedOrigins)) { + origins.push_back(url::Origin::Create(GURL(value.GetString()))); + } + + if (!origins.empty()) { + auto* policy = content::ChildProcessSecurityPolicy::GetInstance(); + using IsolatedOriginSource = + content::ChildProcessSecurityPolicy::IsolatedOriginSource; + policy->AddIsolatedOrigins(origins, IsolatedOriginSource::USER_TRIGGERED, + browser_context); + } + + UMA_HISTOGRAM_COUNTS_1000( + "SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", origins.size()); +} + +} // namespace site_isolation diff --git a/chromium/components/site_isolation/site_isolation_policy.h b/chromium/components/site_isolation/site_isolation_policy.h new file mode 100644 index 00000000000..ade65a884d6 --- /dev/null +++ b/chromium/components/site_isolation/site_isolation_policy.h @@ -0,0 +1,54 @@ +// Copyright 2019 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 COMPONENTS_SITE_ISOLATION_SITE_ISOLATION_POLICY_H_ +#define COMPONENTS_SITE_ISOLATION_SITE_ISOLATION_POLICY_H_ + +#include "base/macros.h" + +namespace content { +class BrowserContext; +} + +namespace site_isolation { + +// A centralized place for making policy decisions about site isolation modes +// which can be shared between content embedders. This supplements +// content::SiteIsolationPolicy with features that may be useful to embedders. +// +// These methods can be called from any thread. +class SiteIsolationPolicy { + public: + // Returns true if the site isolation mode for isolating sites where users + // enter passwords is enabled. + static bool IsIsolationForPasswordSitesEnabled(); + + // Returns true if Site Isolation related enterprise policies should take + // effect (e.g. such policies might not be applicable to low-end Android + // devices because of 1) performance impact and 2) infeasibility of + // Spectre-like attacks on such devices). + static bool IsEnterprisePolicyApplicable(); + + // Reads and applies any isolated origins stored in user prefs associated with + // |browser_context|. This is expected to be called on startup after user + // prefs have been loaded. + static void ApplyPersistedIsolatedOrigins( + content::BrowserContext* browser_context); + + // Determines whether Site Isolation should be disabled because the device + // does not have the minimum required amount of memory. + // + // TODO(alexmos): Currently, the memory threshold is shared for all site + // isolation modes, including strict site isolation and password site + // isolation. In the future, some site isolation modes may require their own + // memory threshold. + static bool ShouldDisableSiteIsolationDueToMemoryThreshold(); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SiteIsolationPolicy); +}; + +} // namespace site_isolation + +#endif // COMPONENTS_SITE_ISOLATION_SITE_ISOLATION_POLICY_H_ diff --git a/chromium/components/site_isolation/site_isolation_policy_unittest.cc b/chromium/components/site_isolation/site_isolation_policy_unittest.cc new file mode 100644 index 00000000000..47d16fddefb --- /dev/null +++ b/chromium/components/site_isolation/site_isolation_policy_unittest.cc @@ -0,0 +1,938 @@ +// Copyright 2019 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. + +#include "components/site_isolation/site_isolation_policy.h" + +#include "base/base_switches.h" +#include "base/system/sys_info.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/mock_entropy_provider.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/scoped_field_trial_list_resetter.h" +#include "build/branding_buildflags.h" +#include "build/build_config.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "components/prefs/testing_pref_service.h" +#include "components/site_isolation/features.h" +#include "components/site_isolation/pref_names.h" +#include "components/site_isolation/preloaded_isolated_origins.h" +#include "components/user_prefs/user_prefs.h" +#include "components/variations/variations_switches.h" +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/site_isolation_policy.h" +#include "content/public/common/content_client.h" +#include "content/public/common/content_features.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_browser_context.h" +#include "content/public/test/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace site_isolation { +namespace { + +// Some command-line switches override field trials - the tests need to be +// skipped in this case. +bool ShouldSkipBecauseOfConflictingCommandLineSwitches() { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSitePerProcess)) + return true; + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSiteIsolation)) + return true; + + return false; +} + +} // namespace + +// Base class for site isolation tests which handles setting a +// ContentBrowserClient with logic for enabling/disabling site isolation. +class BaseSiteIsolationTest : public testing::Test { + public: + BaseSiteIsolationTest() { + original_client_ = content::SetBrowserClientForTesting(&browser_client_); + SetEnableStrictSiteIsolation( + original_client_->ShouldEnableStrictSiteIsolation()); + } + + ~BaseSiteIsolationTest() override { + content::SetBrowserClientForTesting(original_client_); + } + + protected: + void SetEnableStrictSiteIsolation(bool enable) { + browser_client_.strict_isolation_enabled_ = enable; + } + + private: + class SiteIsolationContentBrowserClient + : public content::ContentBrowserClient { + public: + bool ShouldEnableStrictSiteIsolation() override { + return strict_isolation_enabled_; + } + + bool ShouldDisableSiteIsolation() override { + return SiteIsolationPolicy:: + ShouldDisableSiteIsolationDueToMemoryThreshold(); + } + + std::vector<url::Origin> GetOriginsRequiringDedicatedProcess() override { + return GetBrowserSpecificBuiltInIsolatedOrigins(); + } + + bool strict_isolation_enabled_ = false; + }; + + SiteIsolationContentBrowserClient browser_client_; + content::ContentBrowserClient* original_client_ = nullptr; +}; + +class SiteIsolationPolicyTest : public BaseSiteIsolationTest { + public: + SiteIsolationPolicyTest() { + prefs_.registry()->RegisterListPref(prefs::kUserTriggeredIsolatedOrigins); + user_prefs::UserPrefs::Set(&browser_context_, &prefs_); + } + + protected: + content::BrowserContext* browser_context() { return &browser_context_; } + + PrefService* prefs() { return &prefs_; } + + private: + content::BrowserTaskEnvironment task_environment_; + content::TestBrowserContext browser_context_; + TestingPrefServiceSimple prefs_; + + DISALLOW_COPY_AND_ASSIGN(SiteIsolationPolicyTest); +}; + +// Helper class that enables site isolation for password sites. +class PasswordSiteIsolationPolicyTest : public SiteIsolationPolicyTest { + public: + PasswordSiteIsolationPolicyTest() = default; + + protected: + void SetUp() override { + feature_list_.InitAndEnableFeature( + features::kSiteIsolationForPasswordSites); + SetEnableStrictSiteIsolation(false); + SiteIsolationPolicyTest::SetUp(); + } + + private: + base::test::ScopedFeatureList feature_list_; + + DISALLOW_COPY_AND_ASSIGN(PasswordSiteIsolationPolicyTest); +}; + +// Verifies that SiteIsolationPolicy::ApplyPersistedIsolatedOrigins applies +// stored isolated origins correctly when using site isolation for password +// sites. +TEST_F(PasswordSiteIsolationPolicyTest, ApplyPersistedIsolatedOrigins) { + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + // Add foo.com and bar.com to stored isolated origins. + { + ListPrefUpdate update(prefs(), prefs::kUserTriggeredIsolatedOrigins); + base::ListValue* list = update.Get(); + list->Append("http://foo.com"); + list->Append("https://bar.com"); + } + + // New SiteInstances for foo.com and bar.com shouldn't require a dedicated + // process to start with. An exception is if this test runs with a + // command-line --site-per-process flag (which might be the case on some + // bots). This will override the feature configuration in this test and make + // all sites isolated. + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSitePerProcess)) { + scoped_refptr<content::SiteInstance> foo_instance = + content::SiteInstance::CreateForURL(browser_context(), + GURL("http://foo.com/1")); + EXPECT_FALSE(foo_instance->RequiresDedicatedProcess()); + + scoped_refptr<content::SiteInstance> bar_instance = + content::SiteInstance::CreateForURL(browser_context(), + GURL("https://baz.bar.com/2")); + EXPECT_FALSE(bar_instance->RequiresDedicatedProcess()); + } + + // Apply isolated origins and ensure that they take effect for SiteInstances + // in new BrowsingInstances. + base::HistogramTester histograms; + SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(browser_context()); + histograms.ExpectUniqueSample( + "SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", 2, 1); + { + scoped_refptr<content::SiteInstance> foo_instance = + content::SiteInstance::CreateForURL(browser_context(), + GURL("http://foo.com/1")); + EXPECT_TRUE(foo_instance->RequiresDedicatedProcess()); + + scoped_refptr<content::SiteInstance> bar_instance = + content::SiteInstance::CreateForURL(browser_context(), + GURL("https://baz.bar.com/2")); + EXPECT_TRUE(bar_instance->RequiresDedicatedProcess()); + } +} + +// Helper class that disables strict site isolation as well as site isolation +// for password sites. +class NoPasswordSiteIsolationPolicyTest : public SiteIsolationPolicyTest { + public: + NoPasswordSiteIsolationPolicyTest() = default; + + protected: + void SetUp() override { + feature_list_.InitAndDisableFeature( + features::kSiteIsolationForPasswordSites); + SetEnableStrictSiteIsolation(false); + SiteIsolationPolicyTest::SetUp(); + } + + private: + base::test::ScopedFeatureList feature_list_; + + DISALLOW_COPY_AND_ASSIGN(NoPasswordSiteIsolationPolicyTest); +}; + +// Verifies that SiteIsolationPolicy::ApplyPersistedIsolatedOrigins ignores +// stored isolated origins when site isolation for password sites is off. +TEST_F(NoPasswordSiteIsolationPolicyTest, + PersistedIsolatedOriginsIgnoredWithoutPasswordIsolation) { + // Running this test with a command-line --site-per-process flag (which might + // be the case on some bots) doesn't make sense, as that will make all sites + // isolated, overriding the feature configuration in this test. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSitePerProcess)) + return; + + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + // Add foo.com to stored isolated origins. + { + ListPrefUpdate update(prefs(), prefs::kUserTriggeredIsolatedOrigins); + base::ListValue* list = update.Get(); + list->Append("http://foo.com"); + } + + // Applying saved isolated origins should have no effect, since site + // isolation for password sites is off. + SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(browser_context()); + scoped_refptr<content::SiteInstance> foo_instance = + content::SiteInstance::CreateForURL(browser_context(), + GURL("http://foo.com/")); + EXPECT_FALSE(foo_instance->RequiresDedicatedProcess()); +} + +enum class SitePerProcessMemoryThreshold { + kNone, + k128MB, + k768MB, +}; + +enum class SitePerProcessMode { + kDisabled, + kEnabled, + kIsolatedOrigin, +}; + +struct SitePerProcessMemoryThresholdBrowserTestParams { + SitePerProcessMemoryThreshold threshold; + SitePerProcessMode mode; +}; + +const url::Origin& GetTrialOrigin() { + static base::NoDestructor<url::Origin> origin{ + url::Origin::Create(GURL("http://foo.com/"))}; + return *origin; +} + +// Helper class to run tests on a simulated 512MB low-end device. +class SitePerProcessMemoryThresholdBrowserTest + : public BaseSiteIsolationTest, + public ::testing::WithParamInterface< + SitePerProcessMemoryThresholdBrowserTestParams> { + public: + SitePerProcessMemoryThresholdBrowserTest() { + switch (GetParam().threshold) { + case SitePerProcessMemoryThreshold::kNone: + break; + case SitePerProcessMemoryThreshold::k128MB: + threshold_feature_.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, + "128"}}); + break; + case SitePerProcessMemoryThreshold::k768MB: + threshold_feature_.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, + "768"}}); + break; + } + + switch (GetParam().mode) { + case SitePerProcessMode::kDisabled: + SetEnableStrictSiteIsolation(false); + break; + case SitePerProcessMode::kEnabled: + SetEnableStrictSiteIsolation(true); + break; + case SitePerProcessMode::kIsolatedOrigin: + mode_feature_.InitAndEnableFeatureWithParameters( + ::features::kIsolateOrigins, + {{::features::kIsolateOriginsFieldTrialParamName, + GetTrialOrigin().Serialize()}}); + break; + } + } + + void SetUp() override { + // This way the test always sees the same amount of physical memory + // (kLowMemoryDeviceThresholdMB = 512MB), regardless of how much memory is + // available in the testing environment. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableLowEndDeviceMode); + EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB()); + + // On Android official builds, we expect to isolate an additional set of + // built-in origins. + expected_embedder_origins_ = GetBrowserSpecificBuiltInIsolatedOrigins(); + } + + protected: + content::BrowserTaskEnvironment task_environment_; + + // These are the origins we expect to be returned by + // content::ChildProcessSecurityPolicy::GetIsolatedOrigins() even if + // ContentBrowserClient::ShouldDisableSiteIsolation() returns true. + std::vector<url::Origin> expected_embedder_origins_; + +#if defined(OS_ANDROID) + // On Android we don't expect any trial origins because the 512MB + // physical memory used for testing is below the Android specific + // hardcoded 1024MB memory limit that disables site isolation. + const std::size_t kExpectedTrialOrigins = 0; +#else + // All other platforms expect the single trial origin to be returned because + // they don't have the memory limit that disables site isolation. + const std::size_t kExpectedTrialOrigins = 1; +#endif + + private: + base::test::ScopedFeatureList threshold_feature_; + base::test::ScopedFeatureList mode_feature_; + + DISALLOW_COPY_AND_ASSIGN(SitePerProcessMemoryThresholdBrowserTest); +}; + +using SitePerProcessMemoryThresholdBrowserTestNoIsolation = + SitePerProcessMemoryThresholdBrowserTest; +TEST_P(SitePerProcessMemoryThresholdBrowserTestNoIsolation, NoIsolation) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // Isolation should be disabled given the set of parameters used to + // instantiate these tests. + EXPECT_FALSE( + content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); +} + +using SitePerProcessMemoryThresholdBrowserTestIsolation = + SitePerProcessMemoryThresholdBrowserTest; +TEST_P(SitePerProcessMemoryThresholdBrowserTestIsolation, Isolation) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // Isolation should be enabled given the set of parameters used to + // instantiate these tests. + EXPECT_TRUE(content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); +} + +INSTANTIATE_TEST_SUITE_P( + NoIsolation, + SitePerProcessMemoryThresholdBrowserTestNoIsolation, + testing::Values( +#if defined(OS_ANDROID) + // Expect no isolation on Android because 512MB physical memory + // triggered by kEnableLowEndDeviceMode in SetUp() is below the 1024MB + // Android specific memory limit which disables site isolation for all + // sites. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, SitePerProcessMode::kEnabled}, +#endif + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k768MB, + SitePerProcessMode::kEnabled}, + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kDisabled}, + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k128MB, + SitePerProcessMode::kDisabled}, + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k768MB, + SitePerProcessMode::kDisabled})); + +INSTANTIATE_TEST_SUITE_P(Isolation, + SitePerProcessMemoryThresholdBrowserTestIsolation, + testing::Values( +#if !defined(OS_ANDROID) + // See the note above regarding why this + // expectation is different on Android. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kEnabled}, +#endif + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k128MB, + SitePerProcessMode::kEnabled})); + +using SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin = + SitePerProcessMemoryThresholdBrowserTest; +TEST_P(SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin, + TrialNoIsolatedOrigin) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); + + auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); + std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins(); + EXPECT_EQ(expected_embedder_origins_.size(), isolated_origins.size()); + + // Verify that the expected embedder origins are present even though site + // isolation has been disabled and the trial origins should not be present. + EXPECT_THAT(expected_embedder_origins_, + ::testing::IsSubsetOf(isolated_origins)); + + // Verify that the trial origin is not present. + EXPECT_THAT(isolated_origins, + ::testing::Not(::testing::Contains(GetTrialOrigin()))); +} + +using SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin = + SitePerProcessMemoryThresholdBrowserTest; +TEST_P(SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin, + TrialIsolatedOrigin) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); + + auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); + std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins(); + EXPECT_EQ(1u + expected_embedder_origins_.size(), isolated_origins.size()); + EXPECT_THAT(expected_embedder_origins_, + ::testing::IsSubsetOf(isolated_origins)); + + // Verify that the trial origin is present. + EXPECT_THAT(isolated_origins, ::testing::Contains(GetTrialOrigin())); +} + +INSTANTIATE_TEST_SUITE_P( + TrialNoIsolatedOrigin, + SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin, + testing::Values( +#if defined(OS_ANDROID) + // When the memory threshold is not explicitly specified, Android uses + // a 1900MB global memory threshold. The 512MB simulated device memory + // is below 1900MB, so the test origin should not be isolated. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kIsolatedOrigin}, +#endif + // The 512MB simulated device memory is under the explicit 768MB memory + // threshold below, so the test origin should not be isolated. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k768MB, + SitePerProcessMode::kIsolatedOrigin})); + +INSTANTIATE_TEST_SUITE_P( + TrialIsolatedOrigin, + SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin, + // The 512MB simulated device memory is above the explicit 128MB memory + // threshold below, so the test origin should be isolated both on desktop + // and Android. + testing::Values(SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k128MB, + SitePerProcessMode::kIsolatedOrigin})); + +// Helper class to run tests with password-triggered site isolation initialized +// via a regular field trial and *not* via a command-line override. It +// creates a new field trial (with 100% probability of being in the group), and +// initializes the test class's ScopedFeatureList using it. Two derived +// classes below control are used to initialize the feature to either enabled +// or disabled state. +class PasswordSiteIsolationFieldTrialTest : public BaseSiteIsolationTest { + public: + explicit PasswordSiteIsolationFieldTrialTest(bool should_enable) + : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) { + const std::string kTrialName = "PasswordSiteIsolation"; + const std::string kGroupName = "FooGroup"; // unused + scoped_refptr<base::FieldTrial> trial = + base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); + + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->RegisterFieldTrialOverride( + features::kSiteIsolationForPasswordSites.name, + should_enable + ? base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE + : base::FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE, + trial.get()); + + feature_list_.InitWithFeatureList(std::move(feature_list)); + } + + void SetUp() override { + // This test creates and tests its own field trial group, so it needs to + // disable the field trial testing config, which might define an + // incompatible trial name/group. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + variations::switches::kDisableFieldTrialTestingConfig); + + // This way the test always sees the same amount of physical memory + // (kLowMemoryDeviceThresholdMB = 512MB), regardless of how much memory is + // available in the testing environment. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableLowEndDeviceMode); + EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB()); + } + + protected: + base::test::ScopedFieldTrialListResetter trial_list_resetter_; + base::test::ScopedFeatureList feature_list_; + base::FieldTrialList field_trial_list_; + + private: + DISALLOW_COPY_AND_ASSIGN(PasswordSiteIsolationFieldTrialTest); +}; + +class EnabledPasswordSiteIsolationFieldTrialTest + : public PasswordSiteIsolationFieldTrialTest { + public: + EnabledPasswordSiteIsolationFieldTrialTest() + : PasswordSiteIsolationFieldTrialTest(true /* should_enable */) {} + + private: + DISALLOW_COPY_AND_ASSIGN(EnabledPasswordSiteIsolationFieldTrialTest); +}; + +class DisabledPasswordSiteIsolationFieldTrialTest + : public PasswordSiteIsolationFieldTrialTest { + public: + DisabledPasswordSiteIsolationFieldTrialTest() + : PasswordSiteIsolationFieldTrialTest(false /* should_enable */) {} + + private: + DISALLOW_COPY_AND_ASSIGN(DisabledPasswordSiteIsolationFieldTrialTest); +}; + +TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, BelowThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // If no memory threshold is defined, password site isolation should be + // enabled on desktop. It should be disabled on Android, because Android + // defaults to a 1900MB memory threshold, which is above the 512MB physical + // memory that this test simulates. +#if defined(OS_ANDROID) + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +#else + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +#endif + + // Define a memory threshold at 768MB. Since this is above the 512MB of + // physical memory that this test simulates, password site isolation should + // now be disabled. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); + + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + // Simulate enabling password site isolation from command line. (Note that + // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine + // internally, and that triggering the feature via chrome://flags follows the + // same override path as well.) + base::test::ScopedFeatureList password_site_isolation_feature; + password_site_isolation_feature.InitAndEnableFeature( + features::kSiteIsolationForPasswordSites); + + // This should override the memory threshold and enable password site + // isolation. + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +} + +TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, AboveThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // If no memory threshold is defined, password site isolation should be + // enabled on desktop. It should be disabled on Android, because Android + // defaults to a 1900MB memory threshold, which is above the 512MB physical + // memory that this test simulates. +#if defined(OS_ANDROID) + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +#else + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +#endif + + // Define a memory threshold at 128MB. Since this is below the 512MB of + // physical memory that this test simulates, password site isolation should + // still be enabled. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); + + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + // Simulate disabling password site isolation from command line. (Note that + // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine + // internally, and that triggering the feature via chrome://flags follows the + // same override path as well.) This should take precedence over the regular + // field trial behavior. + base::test::ScopedFeatureList password_site_isolation_feature; + password_site_isolation_feature.InitAndDisableFeature( + features::kSiteIsolationForPasswordSites); + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +} + +// This test verifies that when password-triggered site isolation is disabled +// via field trials but force-enabled via command line, it takes effect even +// when below the memory threshold. See https://crbug.com/1009828. +TEST_F(DisabledPasswordSiteIsolationFieldTrialTest, + CommandLineOverride_BelowThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // Password site isolation should be disabled at this point. + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + // Simulate enabling password site isolation from command line. (Note that + // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine + // internally, and that triggering the feature via chrome://flags follows the + // same override path as well.) + base::test::ScopedFeatureList password_site_isolation_feature; + password_site_isolation_feature.InitAndEnableFeature( + features::kSiteIsolationForPasswordSites); + + // If no memory threshold is defined, password site isolation should be + // enabled. + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + // Define a memory threshold at 768MB. This is above the 512MB of physical + // memory that this test simulates, but password site isolation should still + // be enabled, because the test has simulated the user manually overriding + // this feature via command line. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); + + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +} + +// Similar to the test above, but with device memory being above memory +// threshold. +TEST_F(DisabledPasswordSiteIsolationFieldTrialTest, + CommandLineOverride_AboveThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + base::test::ScopedFeatureList password_site_isolation_feature; + password_site_isolation_feature.InitAndEnableFeature( + features::kSiteIsolationForPasswordSites); + + // If no memory threshold is defined, password site isolation should be + // enabled. + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); + + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); + + EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()); +} + +// Helper class to run tests with strict origin isolation initialized via +// a regular field trial and *not* via a command-line override. It creates a +// new field trial (with 100% probability of being in the group), and +// initializes the test class's ScopedFeatureList using it. Two derived +// classes below control are used to initialize the feature to either enabled +// or disabled state. +class StrictOriginIsolationFieldTrialTest : public BaseSiteIsolationTest { + public: + explicit StrictOriginIsolationFieldTrialTest(bool should_enable) + : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) { + const std::string kTrialName = "StrictOriginIsolation"; + const std::string kGroupName = "FooGroup"; // unused + scoped_refptr<base::FieldTrial> trial = + base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); + + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->RegisterFieldTrialOverride( + ::features::kStrictOriginIsolation.name, + should_enable + ? base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE + : base::FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE, + trial.get()); + + feature_list_.InitWithFeatureList(std::move(feature_list)); + } + + void SetUp() override { + // This test creates and tests its own field trial group, so it needs to + // disable the field trial testing config, which might define an + // incompatible trial name/group. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + variations::switches::kDisableFieldTrialTestingConfig); + + // This way the test always sees the same amount of physical memory + // (kLowMemoryDeviceThresholdMB = 512MB), regardless of how much memory is + // available in the testing environment. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableLowEndDeviceMode); + EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB()); + } + + protected: + base::test::ScopedFieldTrialListResetter trial_list_resetter_; + base::test::ScopedFeatureList feature_list_; + base::FieldTrialList field_trial_list_; + + private: + DISALLOW_COPY_AND_ASSIGN(StrictOriginIsolationFieldTrialTest); +}; + +class EnabledStrictOriginIsolationFieldTrialTest + : public StrictOriginIsolationFieldTrialTest { + public: + EnabledStrictOriginIsolationFieldTrialTest() + : StrictOriginIsolationFieldTrialTest(true /* should_enable */) {} + + private: + DISALLOW_COPY_AND_ASSIGN(EnabledStrictOriginIsolationFieldTrialTest); +}; + +class DisabledStrictOriginIsolationFieldTrialTest + : public StrictOriginIsolationFieldTrialTest { + public: + DisabledStrictOriginIsolationFieldTrialTest() + : StrictOriginIsolationFieldTrialTest(false /* should_enable */) {} + + private: + DISALLOW_COPY_AND_ASSIGN(DisabledStrictOriginIsolationFieldTrialTest); +}; + +// Check that when strict origin isolation is enabled via a field trial, and +// the device is above the memory threshold, disabling it via the command line +// takes precedence. +TEST_F(EnabledStrictOriginIsolationFieldTrialTest, + DisabledViaCommandLineOverride) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // If no memory threshold is defined, strict origin isolation should be + // enabled on desktop. It should be disabled on Android, because Android + // defaults to a 1900MB memory threshold, which is above the 512MB physical + // memory that this test simulates. +#if defined(OS_ANDROID) + EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); +#else + EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); +#endif + + // Define a memory threshold at 128MB. Since this is below the 512MB of + // physical memory that this test simulates, strict origin isolation should + // still be enabled. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); + EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); + + // Simulate disabling strict origin isolation from command line. (Note that + // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine + // internally, and that disabling the feature via chrome://flags follows the + // same override path as well.) + base::test::ScopedFeatureList strict_origin_isolation_feature; + strict_origin_isolation_feature.InitAndDisableFeature( + ::features::kStrictOriginIsolation); + EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); +} + +// This test verifies that when strict origin isolation is disabled +// via field trials but force-enabled via command line, it takes effect even +// when below the memory threshold. See https://crbug.com/1009828. +TEST_F(DisabledStrictOriginIsolationFieldTrialTest, + EnabledViaCommandLineOverride_BelowThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // Strict origin isolation should be disabled at this point. + EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); + + // Simulate enabling strict origin isolation from command line. (Note that + // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine + // internally, and that triggering the feature via chrome://flags follows the + // same override path as well.) + base::test::ScopedFeatureList strict_origin_isolation_feature; + strict_origin_isolation_feature.InitAndEnableFeature( + ::features::kStrictOriginIsolation); + + // If no memory threshold is defined, strict origin isolation should be + // enabled. + EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); + + // Define a memory threshold at 768MB. This is above the 512MB of physical + // memory that this test simulates, but strict origin isolation should still + // be enabled, because the test has simulated the user manually overriding + // this feature via command line. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); + + EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled()); +} + +// The following tests verify that the list of Android's built-in isolated +// origins takes effect. This list is only used in official builds, and only +// when above the memory threshold. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_ANDROID) +class BuiltInIsolatedOriginsTest : public SiteIsolationPolicyTest { + public: + BuiltInIsolatedOriginsTest() = default; + + protected: + void SetUp() override { + // Simulate a 512MB device. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableLowEndDeviceMode); + EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(BuiltInIsolatedOriginsTest); +}; + +// Check that the list of preloaded isolated origins is properly applied when +// device RAM is above the site isolation memory threshold. +TEST_F(BuiltInIsolatedOriginsTest, DefaultThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // Define a memory threshold at 128MB. This is below the 512MB of physical + // memory that this test simulates, so preloaded isolated origins should take + // effect. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); + + // Ensure that isolated origins that are normally loaded on browser + // startup are applied. + content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); + + EXPECT_TRUE( + content::SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled()); + + auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); + std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins( + content::ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN); + + // The list of built-in origins is fairly large; we don't want to hardcode + // the size here as it might change, so just check that there are at least 10 + // origins. + EXPECT_GT(isolated_origins.size(), 10u); + + // Check that a couple of well-known origins are on the list. + EXPECT_THAT( + isolated_origins, + ::testing::Contains(url::Origin::Create(GURL("https://google.com/")))); + EXPECT_THAT( + isolated_origins, + ::testing::Contains(url::Origin::Create(GURL("https://amazon.com/")))); + EXPECT_THAT( + isolated_origins, + ::testing::Contains(url::Origin::Create(GURL("https://facebook.com/")))); + + cpsp->ClearIsolatedOriginsForTesting(); +} + +TEST_F(BuiltInIsolatedOriginsTest, BelowThreshold) { + if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) + return; + + // Define a memory threshold at 768MB. This is above the 512MB of physical + // memory that this test simulates, so preloaded isolated origins shouldn't + // take effect. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); + + // Ensure that isolated origins that are normally loaded on browser + // startup are applied. + content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); + + EXPECT_FALSE( + content::SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled()); + + auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); + std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins( + content::ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN); + + // There shouldn't be any built-in origins on Android. (Note that desktop has + // some built-in origins that are applied regardless of memory threshold.) + EXPECT_EQ(isolated_origins.size(), 0u); + + cpsp->ClearIsolatedOriginsForTesting(); +} + +// Check that the list of preloaded isolated origins is not applied when full +// site isolation is used, since in that case the list is redundant. +TEST_F(BuiltInIsolatedOriginsTest, NotAppliedWithFullSiteIsolation) { + // Force full site-per-process mode. + content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); + + // Define a memory threshold at 128MB. This is below the 512MB of physical + // memory that this test simulates, so preloaded isolated origins shouldn't + // be disabled by the memory threshold. + base::test::ScopedFeatureList memory_feature; + memory_feature.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); + + // Ensure that isolated origins that are normally loaded on browser + // startup are applied. + content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); + + // Because full site-per-process is used, the preloaded isolated origins are + // redundant and should not be applied. + EXPECT_FALSE( + content::SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled()); + + auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); + std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins( + content::ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN); + EXPECT_EQ(isolated_origins.size(), 0u); +} +#endif + +} // namespace site_isolation |