Commit 0672f8a0 authored by Lukasz Anforowicz's avatar Lukasz Anforowicz Committed by Commit Bot

Support for field trials of origin isolation.

CL overview
===========

This CL adds a base::Feature for origin isolation to support turning on
this feature in a field trial.  List of origins to isolate can be
specified via a field trial param (see also internal documentation at
cs/finch/experiment-params.md).


Testing
=======

I've tested this CL with the following repro steps:

1. Build Chrome with the CL patched-in (and with r518725 included).

2. Test the default behavior.
   2.1. Launch Chrome without any special command-line flags
        (except --user-data-dir).
   2.2. Go to https://csreis.github.io/tests/cross-site-iframe.html
   2.3. Click "Go cross-site (complex-page)" button
   2.4. In Chrome Task Manager verify that the subframe
        stays in the main frame's process

3. Test the field trial behavior.
   3.1. Launch Chrome with the following command-line flags:
      --enable-features="IsolateOrigins<MyTrialName" \
      --force-fieldtrials=MyTrialName/MyTrialGroup \
      --force-fieldtrial-params=MyTrialName.MyTrialGroup:OriginsList/https%3A%2F%2Fchromium-build.appspot.com
   3.2. Go to https://csreis.github.io/tests/cross-site-iframe.html
   3.3. Click "Go cross-site (complex-page)" button
   3.4. In Chrome Task Manager verify that there are 3 separate
        processes:
      - One for main frame (https://csreis.github.io/)
      - One for the isolated origin (https://chromium-build.appspot.com)
      - One for a subframe inside the isolated origin
        (https://chromium-status.appspot.com)

Note that in step 3.1 some characters in the field trial param had to be
escaped using percent encoding.


Other notes
===========

This CL refactors SiteIsolationPolicy and
ChildProcessSecurityPolicyImpl, so that

1) One can add a set of isolated origins to ChildProcessSecurityPolicyImpl
   regardless of the source (ContentBrowserClient vs cmdline/field-trial).
   After this CL, ChildProcessSecurityPolicyImpl exposes only a single
       void AddIsolatedOrigins(std::vector<url::Origin> origins);
   method (and doesn't anymore offer adding a single origin or
   parsing cmdline).

   One extra benefit of this change is that the
   ChildProcessSecurityPolicyImpl::lock_ is not taken and released
   once per every single origin (after this CL it is taken and released
   only once per batch of origins passed to AddIsolatedOrigins).

2) Parsing of a string with a list of origins can be reused for parsing
   cmdline arg and for parsing a field trial param.  After this CL,
   parsing is done via SiteIsolationPolicy::ParseIsolatedOrigins.
   Unit tests have correspondingly been moved from
   child_process_security_policy_unittest.cc to
   site_isolation_policy_unittest.cc


Bug: 780133
Change-Id: I28578bfd7f141ea8bdf0330f2342a1fb77619148
Reviewed-on: https://chromium-review.googlesource.com/786276
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#520360}
parent 3c11bd5d
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
#include "content/browser/webui/url_data_manager.h" #include "content/browser/webui/url_data_manager.h"
#include "content/common/content_switches_internal.h" #include "content/common/content_switches_internal.h"
#include "content/common/service_manager/service_manager_connection_impl.h" #include "content/common/service_manager/service_manager_connection_impl.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/task_scheduler.h" #include "content/common/task_scheduler.h"
#include "content/public/browser/browser_main_parts.h" #include "content/public/browser/browser_main_parts.h"
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
...@@ -909,19 +910,11 @@ int BrowserMainLoop::PreCreateThreads() { ...@@ -909,19 +910,11 @@ int BrowserMainLoop::PreCreateThreads() {
// Initialize origins that are whitelisted for process isolation. Must be // Initialize origins that are whitelisted for process isolation. Must be
// done after base::FeatureList is initialized, but before any navigations // done after base::FeatureList is initialized, but before any navigations
// can happen. // can happen.
std::vector<url::Origin> origins =
GetContentClient()->browser()->GetOriginsRequiringDedicatedProcess();
ChildProcessSecurityPolicyImpl* policy = ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance(); ChildProcessSecurityPolicyImpl::GetInstance();
for (auto origin : origins) policy->AddIsolatedOrigins(SiteIsolationPolicy::GetIsolatedOrigins());
policy->AddIsolatedOrigin(origin); policy->AddIsolatedOrigins(
GetContentClient()->browser()->GetOriginsRequiringDedicatedProcess());
// The command line values must be read after `parts_->PreCreateThreads()` so
// that embedders can append values via policy.
if (parsed_command_line_.HasSwitch(switches::kIsolateOrigins)) {
policy->AddIsolatedOriginsFromCommandLine(
parsed_command_line_.GetSwitchValueASCII(switches::kIsolateOrigins));
}
return result_code_; return result_code_;
} }
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/browser/isolated_origin_util.h" #include "content/browser/isolated_origin_util.h"
...@@ -1146,28 +1145,24 @@ bool ChildProcessSecurityPolicyImpl::CanSendMidiSysExMessage(int child_id) { ...@@ -1146,28 +1145,24 @@ bool ChildProcessSecurityPolicyImpl::CanSendMidiSysExMessage(int child_id) {
return state->second->can_send_midi_sysex(); return state->second->can_send_midi_sysex();
} }
void ChildProcessSecurityPolicyImpl::AddIsolatedOrigin( void ChildProcessSecurityPolicyImpl::AddIsolatedOrigins(
const url::Origin& origin) { std::vector<url::Origin> origins_to_add) {
CHECK(IsolatedOriginUtil::IsValidIsolatedOrigin(origin)); // Filter out origins that cannot be used as an isolated origin.
auto end_of_valid_origins =
base::AutoLock lock(lock_); std::remove_if(origins_to_add.begin(), origins_to_add.end(),
if (isolated_origins_.count(origin)) { [](const url::Origin& origin) {
LOG(ERROR) << "Ignoring duplicate isolated origin: " << origin.Serialize(); if (IsolatedOriginUtil::IsValidIsolatedOrigin(origin))
return; return false; // Don't remove.
}
isolated_origins_.insert(origin); LOG(ERROR) << "Invalid isolated origin: " << origin;
} return true; // Remove.
});
origins_to_add.erase(end_of_valid_origins, origins_to_add.end());
void ChildProcessSecurityPolicyImpl::AddIsolatedOriginsFromCommandLine( // Taking the lock once and doing a batch insertion via base::flat_set::insert
const std::string& origin_list) { // is important because of performance characteristics of base::flat_set.
for (const base::StringPiece& origin_piece : base::AutoLock lock(lock_);
base::SplitStringPiece(origin_list, ",", base::TRIM_WHITESPACE, isolated_origins_.insert(origins_to_add.begin(), origins_to_add.end());
base::SPLIT_WANT_NONEMPTY)) {
url::Origin origin = url::Origin::Create((GURL(origin_piece)));
if (!origin.unique())
AddIsolatedOrigin(origin);
}
} }
bool ChildProcessSecurityPolicyImpl::IsIsolatedOrigin( bool ChildProcessSecurityPolicyImpl::IsIsolatedOrigin(
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <vector> #include <vector>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
...@@ -208,7 +209,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl ...@@ -208,7 +209,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// Returns true if sending system exclusive messages is allowed. // Returns true if sending system exclusive messages is allowed.
bool CanSendMidiSysExMessage(int child_id); bool CanSendMidiSysExMessage(int child_id);
// Add an origin to the list of origins that require process isolation. // Add |origins| to the list of origins that require process isolation.
// When making process model decisions for such origins, the full // When making process model decisions for such origins, the full
// scheme+host+port tuple rather than scheme and eTLD+1 will be used. // scheme+host+port tuple rather than scheme and eTLD+1 will be used.
// SiteInstances for these origins will also use the full origin as site URL. // SiteInstances for these origins will also use the full origin as site URL.
...@@ -218,7 +219,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl ...@@ -218,7 +219,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// isolated origin, then https://bar.isolated.foo.com will be considered part // isolated origin, then https://bar.isolated.foo.com will be considered part
// of the site for https://isolated.foo.com. // of the site for https://isolated.foo.com.
// //
// Note that |origin| must not be unique. URLs that render with // Note that origins from |origins| must not be unique - URLs that render with
// unique origins, such as data: URLs, are not supported. Suborigins (see // unique origins, such as data: URLs, are not supported. Suborigins (see
// https://w3c.github.io/webappsec-suborigins/ -- not to be confused with // https://w3c.github.io/webappsec-suborigins/ -- not to be confused with
// subdomains) and non-standard schemes are also not supported. Sandboxed // subdomains) and non-standard schemes are also not supported. Sandboxed
...@@ -228,13 +229,10 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl ...@@ -228,13 +229,10 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// origin opens an about:blank popup, it will stay in the isolated origin's // origin opens an about:blank popup, it will stay in the isolated origin's
// process. Nested URLs (filesystem: and blob:) retain process isolation // process. Nested URLs (filesystem: and blob:) retain process isolation
// behavior of their inner origin. // behavior of their inner origin.
void AddIsolatedOrigin(const url::Origin& origin); //
// Note that it is okay if |origins| contains duplicates - the set of origins
// Register a set of isolated origins as specified on the command line with // will be deduplicated inside the method.
// the --isolate-origins flag. |origin_list| is the flag's value, which void AddIsolatedOrigins(std::vector<url::Origin> origins);
// contains the list of comma-separated scheme-host-port origins. See
// AddIsolatedOrigin for definition of an isolated origin.
void AddIsolatedOriginsFromCommandLine(const std::string& origin_list);
// Check whether |origin| requires origin-wide process isolation. // Check whether |origin| requires origin-wide process isolation.
// //
...@@ -287,8 +285,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl ...@@ -287,8 +285,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyInProcessBrowserTest, FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyInProcessBrowserTest,
NoLeak); NoLeak);
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, FilePermissions); FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, FilePermissions);
FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, AddIsolatedOrigins);
IsolateOriginsFromCommandLine);
class SecurityState; class SecurityState;
...@@ -377,7 +374,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl ...@@ -377,7 +374,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// when making process model decisions, rather than the origin's scheme and // 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 // eTLD+1. Each of these origins requires a dedicated process. This set is
// protected by |lock_|. // protected by |lock_|.
std::set<url::Origin> isolated_origins_; base::flat_set<url::Origin> isolated_origins_;
DISALLOW_COPY_AND_ASSIGN(ChildProcessSecurityPolicyImpl); DISALLOW_COPY_AND_ASSIGN(ChildProcessSecurityPolicyImpl);
}; };
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <string> #include <string>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/logging.h"
#include "base/test/mock_log.h"
#include "content/browser/child_process_security_policy_impl.h" #include "content/browser/child_process_security_policy_impl.h"
#include "content/public/common/url_constants.h" #include "content/public/common/url_constants.h"
#include "content/test/test_content_browser_client.h" #include "content/test/test_content_browser_client.h"
...@@ -13,6 +15,7 @@ ...@@ -13,6 +15,7 @@
#include "storage/browser/fileapi/file_system_url.h" #include "storage/browser/fileapi/file_system_url.h"
#include "storage/browser/fileapi/isolated_context.h" #include "storage/browser/fileapi/isolated_context.h"
#include "storage/common/fileapi/file_system_types.h" #include "storage/common/fileapi/file_system_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/origin.h" #include "url/origin.h"
...@@ -972,32 +975,59 @@ TEST_F(ChildProcessSecurityPolicyTest, OriginGranting) { ...@@ -972,32 +975,59 @@ TEST_F(ChildProcessSecurityPolicyTest, OriginGranting) {
p->Remove(kRendererID); p->Remove(kRendererID);
} }
// Verifies ChildProcessSecurityPolicyImpl::AddIsolatedOrigins method.
TEST_F(ChildProcessSecurityPolicyTest, AddIsolatedOrigins) {
url::Origin foo = url::Origin::Create(GURL("https://foo.com/"));
url::Origin bar = url::Origin::Create(GURL("https://bar.com/"));
url::Origin baz = url::Origin::Create(GURL("https://baz.com/"));
url::Origin foobar = url::Origin::Create(GURL("https://foobar.com/"));
url::Origin baz_http_8000 = url::Origin::Create(GURL("http://baz.com:8000/"));
url::Origin baz_https_8000 =
url::Origin::Create(GURL("https://baz.com:8000/"));
url::Origin invalid_etld = url::Origin::Create(GURL("https://gov/"));
ChildProcessSecurityPolicyImpl* p =
ChildProcessSecurityPolicyImpl::GetInstance();
// Verifies parsing logic that extracts origins from --isolate-origins. // Initially there should be no isolated origins.
TEST_F(ChildProcessSecurityPolicyTest, IsolateOriginsFromCommandLine) { EXPECT_THAT(p->isolated_origins_, testing::IsEmpty());
// Invalid and unique origins are not permitted.
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); // Verify deduplication of the argument.
policy->AddIsolatedOriginsFromCommandLine("foo"); p->AddIsolatedOrigins({foo, bar, bar});
policy->AddIsolatedOriginsFromCommandLine(""); EXPECT_THAT(p->isolated_origins_, testing::UnorderedElementsAre(foo, bar));
policy->AddIsolatedOriginsFromCommandLine("about:blank");
EXPECT_EQ(0U, policy->isolated_origins_.size()); // Verify that the old set is extended (not replaced).
p->AddIsolatedOrigins({baz});
policy->AddIsolatedOriginsFromCommandLine("http://isolated.foo.com"); EXPECT_THAT(p->isolated_origins_,
EXPECT_EQ(1U, policy->isolated_origins_.size()); testing::UnorderedElementsAre(foo, bar, baz));
EXPECT_TRUE(policy->IsIsolatedOrigin(
url::Origin::Create(GURL("http://isolated.foo.com")))); // Verify deduplication against the old set.
p->AddIsolatedOrigins({foo});
policy->AddIsolatedOriginsFromCommandLine( EXPECT_THAT(p->isolated_origins_,
"http://a.com,https://b.com,,https://c.com:8000"); testing::UnorderedElementsAre(foo, bar, baz));
EXPECT_EQ(4U, policy->isolated_origins_.size());
EXPECT_TRUE(policy->IsIsolatedOrigin( // Verify deduplication considers scheme and port differences.
url::Origin::Create(GURL("http://isolated.foo.com")))); p->AddIsolatedOrigins({baz, baz_http_8000, baz_https_8000});
EXPECT_TRUE( EXPECT_THAT(p->isolated_origins_,
policy->IsIsolatedOrigin(url::Origin::Create(GURL("http://a.com")))); testing::UnorderedElementsAre(foo, bar, baz, baz_http_8000,
EXPECT_TRUE( baz_https_8000));
policy->IsIsolatedOrigin(url::Origin::Create(GURL("https://b.com"))));
EXPECT_TRUE(policy->IsIsolatedOrigin( // Verify that adding an origin that is invalid for isolation will 1) log a
url::Origin::Create(GURL("https://c.com:8000")))); // warning and 2) won't CHECK or crash the browser process, 3) will not add
// the invalid origin, but will add the remaining origins passed to
// AddIsolatedOrigins.
{
base::test::MockLog mock_log;
EXPECT_CALL(mock_log,
Log(::logging::LOG_ERROR, testing::_, testing::_, testing::_,
testing::HasSubstr(invalid_etld.Serialize())))
.Times(1);
mock_log.StartCapturingLogs();
p->AddIsolatedOrigins({foobar, invalid_etld});
EXPECT_THAT(p->isolated_origins_,
testing::UnorderedElementsAre(foo, bar, baz, baz_http_8000,
baz_https_8000, foobar));
}
} }
} // namespace content } // namespace content
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/command_line.h" #include "base/command_line.h"
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/bad_message.h" #include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h" #include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/storage_partition_impl.h" #include "content/browser/storage_partition_impl.h"
#include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/common/browser_side_navigation_policy.h" #include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test.h"
...@@ -55,6 +58,9 @@ class IsolatedOriginTest : public ContentBrowserTest { ...@@ -55,6 +58,9 @@ class IsolatedOriginTest : public ContentBrowserTest {
"document.body.appendChild(link);" "document.body.appendChild(link);"
"link.click();")); "link.click();"));
} }
private:
DISALLOW_COPY_AND_ASSIGN(IsolatedOriginTest);
}; };
// Check that navigating a main frame from an non-isolated origin to an // Check that navigating a main frame from an non-isolated origin to an
...@@ -897,6 +903,8 @@ class StoragePartitonInterceptor ...@@ -897,6 +903,8 @@ class StoragePartitonInterceptor
// Keep a pointer to the original implementation of the service, so all // Keep a pointer to the original implementation of the service, so all
// calls can be forwarded to it. // calls can be forwarded to it.
mojom::StoragePartitionService* storage_partition_service_; mojom::StoragePartitionService* storage_partition_service_;
DISALLOW_COPY_AND_ASSIGN(StoragePartitonInterceptor);
}; };
void CreateTestStoragePartitionService( void CreateTestStoragePartitionService(
...@@ -930,4 +938,28 @@ IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, LocalStorageOriginEnforcement) { ...@@ -930,4 +938,28 @@ IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, LocalStorageOriginEnforcement) {
crash_observer.Wait(); crash_observer.Wait();
} }
class IsolatedOriginFieldTrialTest : public ContentBrowserTest {
public:
IsolatedOriginFieldTrialTest() {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
features::kIsolateOrigins,
{{features::kIsolateOriginsFieldTrialParamName,
"https://field.trial.com/,https://bar.com/"}});
}
~IsolatedOriginFieldTrialTest() override {}
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(IsolatedOriginFieldTrialTest);
};
IN_PROC_BROWSER_TEST_F(IsolatedOriginFieldTrialTest, Test) {
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
EXPECT_TRUE(policy->IsIsolatedOrigin(
url::Origin::Create(GURL("https://field.trial.com/"))));
EXPECT_TRUE(
policy->IsIsolatedOrigin(url::Origin::Create(GURL("https://bar.com/"))));
}
} // namespace content } // namespace content
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#include "base/command_line.h" #include "base/command_line.h"
...@@ -47,7 +48,7 @@ const char kPrivilegedScheme[] = "privileged"; ...@@ -47,7 +48,7 @@ const char kPrivilegedScheme[] = "privileged";
class SiteInstanceTestBrowserClient : public TestContentBrowserClient { class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
public: public:
explicit SiteInstanceTestBrowserClient() SiteInstanceTestBrowserClient()
: privileged_process_id_(-1), : privileged_process_id_(-1),
site_instance_delete_count_(0), site_instance_delete_count_(0),
browsing_instance_delete_count_(0) { browsing_instance_delete_count_(0) {
...@@ -896,7 +897,7 @@ TEST_F(SiteInstanceTest, IsolatedOrigins) { ...@@ -896,7 +897,7 @@ TEST_F(SiteInstanceTest, IsolatedOrigins) {
EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_foo_url))); EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_foo_url)));
EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, foo_url, isolated_foo_url)); EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, foo_url, isolated_foo_url));
policy->AddIsolatedOrigin(url::Origin::Create(isolated_foo_url)); policy->AddIsolatedOrigins({url::Origin::Create(isolated_foo_url)});
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_foo_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_foo_url)));
EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin::Create(foo_url))); EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin::Create(foo_url)));
EXPECT_FALSE( EXPECT_FALSE(
...@@ -908,7 +909,7 @@ TEST_F(SiteInstanceTest, IsolatedOrigins) { ...@@ -908,7 +909,7 @@ TEST_F(SiteInstanceTest, IsolatedOrigins) {
EXPECT_FALSE(policy->IsIsolatedOrigin( EXPECT_FALSE(policy->IsIsolatedOrigin(
url::Origin::Create(GURL("http://isolated.foo.com:12345")))); url::Origin::Create(GURL("http://isolated.foo.com:12345"))));
policy->AddIsolatedOrigin(url::Origin::Create(isolated_bar_url)); policy->AddIsolatedOrigins({url::Origin::Create(isolated_bar_url)});
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_bar_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_bar_url)));
// IsSameWebSite should compare origins rather than sites if either URL is an // IsSameWebSite should compare origins rather than sites if either URL is an
...@@ -998,7 +999,7 @@ TEST_F(SiteInstanceTest, SubdomainOnIsolatedSite) { ...@@ -998,7 +999,7 @@ TEST_F(SiteInstanceTest, SubdomainOnIsolatedSite) {
GURL foo_isolated_url("http://foo.isolated.com"); GURL foo_isolated_url("http://foo.isolated.com");
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
policy->AddIsolatedOrigin(url::Origin::Create(isolated_url)); policy->AddIsolatedOrigins({url::Origin::Create(isolated_url)});
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_url)));
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(foo_isolated_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(foo_isolated_url)));
...@@ -1032,7 +1033,7 @@ TEST_F(SiteInstanceTest, SubdomainOnIsolatedSite) { ...@@ -1032,7 +1033,7 @@ TEST_F(SiteInstanceTest, SubdomainOnIsolatedSite) {
// Don't try to match subdomains on IP addresses. // Don't try to match subdomains on IP addresses.
GURL isolated_ip("http://127.0.0.1"); GURL isolated_ip("http://127.0.0.1");
policy->AddIsolatedOrigin(url::Origin::Create(isolated_ip)); policy->AddIsolatedOrigins({url::Origin::Create(isolated_ip)});
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_ip))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_ip)));
EXPECT_FALSE(policy->IsIsolatedOrigin( EXPECT_FALSE(policy->IsIsolatedOrigin(
url::Origin::Create(GURL("http://42.127.0.0.1")))); url::Origin::Create(GURL("http://42.127.0.0.1"))));
...@@ -1048,7 +1049,7 @@ TEST_F(SiteInstanceTest, SubdomainOnIsolatedOrigin) { ...@@ -1048,7 +1049,7 @@ TEST_F(SiteInstanceTest, SubdomainOnIsolatedOrigin) {
GURL baz_isolated_foo_url("http://baz.isolated.foo.com"); GURL baz_isolated_foo_url("http://baz.isolated.foo.com");
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
policy->AddIsolatedOrigin(url::Origin::Create(isolated_foo_url)); policy->AddIsolatedOrigins({url::Origin::Create(isolated_foo_url)});
EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin::Create(foo_url))); EXPECT_FALSE(policy->IsIsolatedOrigin(url::Origin::Create(foo_url)));
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_foo_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_foo_url)));
...@@ -1102,8 +1103,8 @@ TEST_F(SiteInstanceTest, MultipleIsolatedOriginsWithCommonSite) { ...@@ -1102,8 +1103,8 @@ TEST_F(SiteInstanceTest, MultipleIsolatedOriginsWithCommonSite) {
GURL qux_baz_bar_foo_url("http://qux.baz.bar.foo.com"); GURL qux_baz_bar_foo_url("http://qux.baz.bar.foo.com");
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
policy->AddIsolatedOrigin(url::Origin::Create(foo_url)); policy->AddIsolatedOrigins(
policy->AddIsolatedOrigin(url::Origin::Create(baz_bar_foo_url)); {url::Origin::Create(foo_url), url::Origin::Create(baz_bar_foo_url)});
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(foo_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(foo_url)));
EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(bar_foo_url))); EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(bar_foo_url)));
......
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
#include "content/common/site_isolation_policy.h" #include "content/common/site_isolation_policy.h"
#include <string>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_split.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "url/gurl.h"
namespace content { namespace content {
...@@ -29,12 +34,43 @@ bool SiteIsolationPolicy::IsTopDocumentIsolationEnabled() { ...@@ -29,12 +34,43 @@ bool SiteIsolationPolicy::IsTopDocumentIsolationEnabled() {
// static // static
bool SiteIsolationPolicy::AreIsolatedOriginsEnabled() { bool SiteIsolationPolicy::AreIsolatedOriginsEnabled() {
// TODO(alexmos): This currently assumes that isolated origins are only added
// via the command-line switch, which may not be true in the future. Remove
// this function when AreCrossProcessFramesPossible becomes true on Android
// above.
return base::CommandLine::ForCurrentProcess()->HasSwitch( return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIsolateOrigins); switches::kIsolateOrigins) ||
base::FeatureList::IsEnabled(features::kIsolateOrigins);
}
// static
std::vector<url::Origin> SiteIsolationPolicy::GetIsolatedOrigins() {
std::string cmdline_arg =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kIsolateOrigins);
if (!cmdline_arg.empty())
return ParseIsolatedOrigins(cmdline_arg);
if (base::FeatureList::IsEnabled(features::kIsolateOrigins)) {
std::string field_trial_arg = base::GetFieldTrialParamValueByFeature(
features::kIsolateOrigins,
features::kIsolateOriginsFieldTrialParamName);
return ParseIsolatedOrigins(field_trial_arg);
}
return std::vector<url::Origin>();
}
// static
std::vector<url::Origin> SiteIsolationPolicy::ParseIsolatedOrigins(
base::StringPiece arg) {
std::vector<base::StringPiece> origin_strings = base::SplitStringPiece(
arg, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::vector<url::Origin> origins;
origins.reserve(origin_strings.size());
for (const base::StringPiece& origin_string : origin_strings) {
url::Origin origin = url::Origin::Create(GURL(origin_string));
if (!origin.unique())
origins.push_back(origin);
}
return origins;
} }
} // namespace content } // namespace content
...@@ -5,9 +5,13 @@ ...@@ -5,9 +5,13 @@
#ifndef CONTENT_COMMON_SITE_ISOLATION_POLICY_H_ #ifndef CONTENT_COMMON_SITE_ISOLATION_POLICY_H_
#define CONTENT_COMMON_SITE_ISOLATION_POLICY_H_ #define CONTENT_COMMON_SITE_ISOLATION_POLICY_H_
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string_piece_forward.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "url/gurl.h" #include "url/origin.h"
namespace content { namespace content {
...@@ -15,7 +19,7 @@ namespace content { ...@@ -15,7 +19,7 @@ namespace content {
// site isolation, --site-per-process, and related features. // site isolation, --site-per-process, and related features.
// //
// This is currently static because all these modes are controlled by command- // This is currently static because all these modes are controlled by command-
// line flags. // line flags or field trials.
// //
// These methods can be called from any thread. // These methods can be called from any thread.
class CONTENT_EXPORT SiteIsolationPolicy { class CONTENT_EXPORT SiteIsolationPolicy {
...@@ -27,14 +31,21 @@ class CONTENT_EXPORT SiteIsolationPolicy { ...@@ -27,14 +31,21 @@ class CONTENT_EXPORT SiteIsolationPolicy {
// different process from the main frame. // different process from the main frame.
static bool IsTopDocumentIsolationEnabled(); static bool IsTopDocumentIsolationEnabled();
// Returns true if there exist origins that require process isolation. Such // Returns true if isolated origins feature is enabled.
// origins require a dedicated process, and hence they make cross-process
// iframes possible.
static bool AreIsolatedOriginsEnabled(); static bool AreIsolatedOriginsEnabled();
// Returns the origins to isolate. See also AreIsolatedOriginsEnabled.
// This list applies globally to the whole browser in all profiles.
// TODO(lukasza): Make sure this list also includes the origins returned by
// ContentBrowserClient::GetOriginsRequiringDedicatedProcess.
static std::vector<url::Origin> GetIsolatedOrigins();
private: private:
SiteIsolationPolicy(); // Not instantiable. SiteIsolationPolicy(); // Not instantiable.
FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, ParseIsolatedOrigins);
static std::vector<url::Origin> ParseIsolatedOrigins(base::StringPiece arg);
DISALLOW_COPY_AND_ASSIGN(SiteIsolationPolicy); DISALLOW_COPY_AND_ASSIGN(SiteIsolationPolicy);
}; };
......
// Copyright 2017 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 "content/common/site_isolation_policy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
// Verifies parsing logic in SiteIsolationPolicy::ParseIsolatedOrigins.
TEST(SiteIsolationPolicyTest, ParseIsolatedOrigins) {
// Invalid and unique origins are not permitted.
EXPECT_THAT(SiteIsolationPolicy::ParseIsolatedOrigins("foo"),
testing::IsEmpty());
EXPECT_THAT(SiteIsolationPolicy::ParseIsolatedOrigins(""),
testing::IsEmpty());
EXPECT_THAT(SiteIsolationPolicy::ParseIsolatedOrigins("about:blank"),
testing::IsEmpty());
// Single simple, valid origin.
EXPECT_THAT(
SiteIsolationPolicy::ParseIsolatedOrigins("http://isolated.foo.com"),
testing::ElementsAre(
url::Origin::Create(GURL("http://isolated.foo.com"))));
// Multiple comma-separated origins.
EXPECT_THAT(
SiteIsolationPolicy::ParseIsolatedOrigins(
"http://a.com,https://b.com,,https://c.com:8000"),
testing::ElementsAre(url::Origin::Create(GURL("http://a.com")),
url::Origin::Create(GURL("https://b.com")),
url::Origin::Create(GURL("https://c.com:8000"))));
// ParseIsolatedOrigins should not do any deduplication (that is the job of
// ChildProcessSecurityPolicyImpl::AddIsolatedOrigins).
EXPECT_THAT(
SiteIsolationPolicy::ParseIsolatedOrigins(
"https://b.com,https://b.com,https://b.com:1234"),
testing::ElementsAre(url::Origin::Create(GURL("https://b.com")),
url::Origin::Create(GURL("https://b.com")),
url::Origin::Create(GURL("https://b.com:1234"))));
}
} // namespace content
...@@ -420,6 +420,13 @@ const base::Feature kWebUsb{"WebUSB", base::FEATURE_ENABLED_BY_DEFAULT}; ...@@ -420,6 +420,13 @@ const base::Feature kWebUsb{"WebUSB", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kImageCaptureAPI{"ImageCaptureAPI", const base::Feature kImageCaptureAPI{"ImageCaptureAPI",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
// Alternative to switches::kIsolateOrigins, for turning on origin isolation.
// List of origins to isolate has to be specified via
// kIsolateOriginsFieldTrialParamName.
const base::Feature kIsolateOrigins{"IsolateOrigins",
base::FEATURE_DISABLED_BY_DEFAULT};
const char kIsolateOriginsFieldTrialParamName[] = "OriginsList";
const base::Feature kKeepAliveRendererForKeepaliveRequests{ const base::Feature kKeepAliveRendererForKeepaliveRequests{
"KeepAliveRendererForKeepaliveRequests", base::FEATURE_ENABLED_BY_DEFAULT}; "KeepAliveRendererForKeepaliveRequests", base::FEATURE_ENABLED_BY_DEFAULT};
......
...@@ -42,6 +42,8 @@ CONTENT_EXPORT extern const base::Feature kGamepadExtensions; ...@@ -42,6 +42,8 @@ CONTENT_EXPORT extern const base::Feature kGamepadExtensions;
CONTENT_EXPORT extern const base::Feature kGuestViewCrossProcessFrames; CONTENT_EXPORT extern const base::Feature kGuestViewCrossProcessFrames;
CONTENT_EXPORT extern const base::Feature kHeapCompaction; CONTENT_EXPORT extern const base::Feature kHeapCompaction;
CONTENT_EXPORT extern const base::Feature kImageCaptureAPI; CONTENT_EXPORT extern const base::Feature kImageCaptureAPI;
CONTENT_EXPORT extern const base::Feature kIsolateOrigins;
CONTENT_EXPORT extern const char kIsolateOriginsFieldTrialParamName[];
CONTENT_EXPORT extern const base::Feature CONTENT_EXPORT extern const base::Feature
kKeepAliveRendererForKeepaliveRequests; kKeepAliveRendererForKeepaliveRequests;
CONTENT_EXPORT extern const base::Feature kLazyInitializeMediaControls; CONTENT_EXPORT extern const base::Feature kLazyInitializeMediaControls;
......
...@@ -1491,6 +1491,7 @@ test("content_unittests") { ...@@ -1491,6 +1491,7 @@ test("content_unittests") {
"../common/service_manager/service_manager_connection_impl_unittest.cc", "../common/service_manager/service_manager_connection_impl_unittest.cc",
"../common/service_worker/service_worker_types_unittest.cc", "../common/service_worker/service_worker_types_unittest.cc",
"../common/service_worker/service_worker_utils_unittest.cc", "../common/service_worker/service_worker_utils_unittest.cc",
"../common/site_isolation_policy_unittest.cc",
"../common/throttling_url_loader_unittest.cc", "../common/throttling_url_loader_unittest.cc",
"../common/unique_name_helper_unittest.cc", "../common/unique_name_helper_unittest.cc",
"../common/webplugininfo_unittest.cc", "../common/webplugininfo_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment