Commit b6d5e745 authored by W. James MacLean's avatar W. James MacLean Committed by Commit Bot

Add 'isolation' key to OriginPolicy.

This CL adds an 'isolation' key to OriginPolicy, as per the proposal at
https://github.com/domenic/origin-isolation#example.

Bug: 900995
Change-Id: I8b676070d5a38dfb394427c244cf10936072c229
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1975992
Commit-Queue: James MacLean <wjmaclean@chromium.org>
Reviewed-by: default avatarDomenic Denicola <domenic@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#729719}
parent 21f719bf
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/values.h" #include "base/values.h"
#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/origin.h" #include "url/origin.h"
...@@ -45,6 +46,14 @@ bool OriginPolicyParser::DoParse(base::StringPiece policy_contents_text) { ...@@ -45,6 +46,14 @@ bool OriginPolicyParser::DoParse(base::StringPiece policy_contents_text) {
ParseFeatures(*features); ParseFeatures(*features);
} }
if (base::Value* isolation =
json->FindKeyOfType("isolation", base::Value::Type::BOOLEAN)) {
if (isolation->GetBool())
policy_contents_->isolation_optin_hints = IsolationOptInHints::NO_HINTS;
} else if (base::Value* isolation = json->FindDictKey("isolation")) {
ParseIsolation(*isolation);
}
return csp_ok; return csp_ok;
} }
...@@ -81,4 +90,23 @@ void OriginPolicyParser::ParseFeatures(const base::Value& features) { ...@@ -81,4 +90,23 @@ void OriginPolicyParser::ParseFeatures(const base::Value& features) {
} }
} }
// The parsing is based on the example at
// https://github.com/domenic/origin-isolation#example.
void OriginPolicyParser::ParseIsolation(const base::Value& policy) {
IsolationOptInHints hints = IsolationOptInHints::NO_HINTS;
for (const auto& key_value : policy.DictItems()) {
// If we hit a key with a non-boolean value, skip it.
if (!key_value.second.is_bool())
continue;
if (key_value.second.GetBool()) {
IsolationOptInHints dict_hint =
GetIsolationOptInHintFromString(key_value.first);
// If we hit a key we don't recognise, it will just return NO_HINTS and
// have no effect.
hints |= dict_hint;
}
}
policy_contents_->isolation_optin_hints = hints;
}
} // namespace network } // namespace network
...@@ -42,8 +42,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) OriginPolicyParser { ...@@ -42,8 +42,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) OriginPolicyParser {
bool ParseContentSecurityPolicies(const base::Value&); bool ParseContentSecurityPolicies(const base::Value&);
bool ParseContentSecurityPolicy(const base::Value&); bool ParseContentSecurityPolicy(const base::Value&);
// The following method is implemented according to the newer spec: // The following methods are implemented according to the newer spec:
void ParseFeatures(const base::Value&); void ParseFeatures(const base::Value&);
void ParseIsolation(const base::Value&);
OriginPolicyContentsPtr policy_contents_; OriginPolicyContentsPtr policy_contents_;
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "services/network/origin_policy/origin_policy_parser.h" #include "services/network/origin_policy/origin_policy_parser.h"
#include "base/strings/stringprintf.h"
#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "services/network/public/mojom/origin_policy_manager.mojom.h" #include "services/network/public/mojom/origin_policy_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -228,4 +230,91 @@ TEST(OriginPolicyParser, FeatureNonString) { ...@@ -228,4 +230,91 @@ TEST(OriginPolicyParser, FeatureNonString) {
ASSERT_FALSE(policy_contents->feature_policy.has_value()); ASSERT_FALSE(policy_contents->feature_policy.has_value());
} }
namespace {
void TestHintsHelper(const std::vector<std::string>& target_hints) {
std::string hints_substr;
for (auto hint_str : target_hints) {
hints_substr += base::StringPrintf("%s\"%s\": true",
(!hints_substr.empty() ? ", " : ""),
hint_str.c_str());
}
std::string manifest_string =
base::StringPrintf("{ \"isolation\": { %s }}", hints_substr.c_str());
auto policy_contents = OriginPolicyParser::Parse(manifest_string);
ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
for (auto target_hint_str : target_hints) {
IsolationOptInHints target_hint =
GetIsolationOptInHintFromString(target_hint_str);
EXPECT_EQ(target_hint,
target_hint & policy_contents->isolation_optin_hints.value());
}
}
} // namespace
TEST(OriginPolicyParser, IsolationOptInNoIsolationKey) {
auto policy_contents = OriginPolicyParser::Parse(R"({})");
ASSERT_FALSE(policy_contents->isolation_optin_hints.has_value());
}
TEST(OriginPolicyParser, IsolationOptInNoDict) {
auto policy_contents = OriginPolicyParser::Parse(R"({ "isolation": true })");
ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
EXPECT_EQ(IsolationOptInHints::NO_HINTS,
policy_contents->isolation_optin_hints.value());
ASSERT_FALSE(OriginPolicyParser::Parse(R"({ "isolation": false })")
->isolation_optin_hints.has_value());
}
TEST(OriginPolicyParser, IsolationOptInEmptyDict) {
TestHintsHelper({});
}
TEST(OriginPolicyParser, IsolationOptInTestOneHint) {
TestHintsHelper({"prefer_isolated_event_loop"});
TestHintsHelper({"prefer_isolated_memory"});
TestHintsHelper({"for_side_channel_protection"});
TestHintsHelper({"for_memory_measurement"});
}
TEST(OriginPolicyParser, IsolationOptInTestTwoHints) {
TestHintsHelper({"prefer_isolated_event_loop", "prefer_isolated_memory"});
TestHintsHelper(
{"prefer_isolated_event_loop", "for_side_channel_protection"});
TestHintsHelper({"prefer_isolated_event_loop", "for_memory_measurement"});
TestHintsHelper({"prefer_isolated_memory", "for_side_channel_protection"});
TestHintsHelper({"prefer_isolated_memory", "for_memory_measurement"});
TestHintsHelper({"for_side_channel_protection", "for_memory_measurement"});
}
TEST(OriginPolicyParser, IsolationOptInTestThreeHints) {
TestHintsHelper({"prefer_isolated_event_loop", "prefer_isolated_memory",
"for_side_channel_protection"});
}
TEST(OriginPolicyParser, IsolationOptInIgnoreUnrecognisedKeys) {
std::string manifest_string = R"( { "isolation": {
"prefer_isolated_event_loop": true,
"foo": true }
} )";
auto policy_contents = OriginPolicyParser::Parse(manifest_string);
ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
EXPECT_EQ(IsolationOptInHints::PREFER_ISOLATED_EVENT_LOOP,
policy_contents->isolation_optin_hints.value());
}
TEST(OriginPolicyParser, IsolationOptInIgnoreFalseValues) {
std::string manifest_string = R"( { "isolation": {
"prefer_isolated_event_loop": false
}
} )";
auto policy_contents = OriginPolicyParser::Parse(manifest_string);
ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
EXPECT_EQ(IsolationOptInHints::NO_HINTS,
policy_contents->isolation_optin_hints.value());
}
} // namespace network } // namespace network
...@@ -124,6 +124,8 @@ jumbo_component("cpp_base") { ...@@ -124,6 +124,8 @@ jumbo_component("cpp_base") {
"http_raw_request_response_info.h", "http_raw_request_response_info.h",
"http_request_headers_mojom_traits.cc", "http_request_headers_mojom_traits.cc",
"http_request_headers_mojom_traits.h", "http_request_headers_mojom_traits.h",
"isolation_opt_in_hints.cc",
"isolation_opt_in_hints.h",
"mutable_network_traffic_annotation_tag_mojom_traits.h", "mutable_network_traffic_annotation_tag_mojom_traits.h",
"mutable_partial_network_traffic_annotation_tag_mojom_traits.h", "mutable_partial_network_traffic_annotation_tag_mojom_traits.h",
"net_ipc_param_traits.cc", "net_ipc_param_traits.cc",
......
// 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 "services/network/public/cpp/isolation_opt_in_hints.h"
#include <type_traits>
namespace network {
IsolationOptInHints GetIsolationOptInHintFromString(
const std::string& hint_str) {
if (hint_str == "prefer_isolated_event_loop")
return IsolationOptInHints::PREFER_ISOLATED_EVENT_LOOP;
if (hint_str == "prefer_isolated_memory")
return IsolationOptInHints::PREFER_ISOLATED_MEMORY;
if (hint_str == "for_side_channel_protection")
return IsolationOptInHints::FOR_SIDE_CHANNEL_PROTECTION;
if (hint_str == "for_memory_measurement")
return IsolationOptInHints::FOR_MEMORY_ISOLATION;
return IsolationOptInHints::NO_HINTS;
}
IsolationOptInHints& operator|=(IsolationOptInHints& lhs,
IsolationOptInHints& rhs) {
lhs = static_cast<IsolationOptInHints>(
static_cast<std::underlying_type<IsolationOptInHints>::type>(lhs) |
static_cast<std::underlying_type<IsolationOptInHints>::type>(rhs));
return lhs;
}
IsolationOptInHints& operator&(IsolationOptInHints& lhs,
IsolationOptInHints& rhs) {
lhs = static_cast<IsolationOptInHints>(
static_cast<std::underlying_type<IsolationOptInHints>::type>(lhs) &
static_cast<std::underlying_type<IsolationOptInHints>::type>(rhs));
return lhs;
}
} // namespace network
// 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 SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_OPT_IN_HINTS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_OPT_IN_HINTS_H_
#include <string>
#include "base/component_export.h"
namespace network {
// The following definitions correspond to the draft spec found here:
// https://github.com/domenic/origin-isolation#proposed-hints.
enum class IsolationOptInHints : unsigned {
NO_HINTS = 0x0,
PREFER_ISOLATED_EVENT_LOOP = 0x1,
PREFER_ISOLATED_MEMORY = 0x2,
FOR_SIDE_CHANNEL_PROTECTION = 0x4,
FOR_MEMORY_ISOLATION = 0x8
};
// Converts hint strings into their corresponding IsolationOptInHints values.
// The hint strings are specified at
// https://github.com/domenic/origin-isolation#proposed-hints.
COMPONENT_EXPORT(NETWORK_CPP_BASE)
IsolationOptInHints GetIsolationOptInHintFromString(
const std::string& hint_str);
COMPONENT_EXPORT(NETWORK_CPP_BASE)
IsolationOptInHints& operator|=(IsolationOptInHints& lhs,
IsolationOptInHints& rhs);
COMPONENT_EXPORT(NETWORK_CPP_BASE)
IsolationOptInHints& operator&(IsolationOptInHints& lhs,
IsolationOptInHints& rhs);
} // namespace network
#endif // SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_OPT_IN_HINTS_H_
...@@ -25,11 +25,13 @@ OriginPolicyContents::OriginPolicyContents(const OriginPolicyContents& other) = ...@@ -25,11 +25,13 @@ OriginPolicyContents::OriginPolicyContents(const OriginPolicyContents& other) =
OriginPolicyContents::OriginPolicyContents( OriginPolicyContents::OriginPolicyContents(
const base::Optional<std::string>& feature_policy, const base::Optional<std::string>& feature_policy,
const std::vector<std::string>& content_security_policies, const std::vector<std::string>& content_security_policies,
const std::vector<std::string>& content_security_policies_report_only) const std::vector<std::string>& content_security_policies_report_only,
const base::Optional<IsolationOptInHints>& isolation_optin_hints)
: feature_policy(feature_policy), : feature_policy(feature_policy),
content_security_policies(content_security_policies), content_security_policies(content_security_policies),
content_security_policies_report_only( content_security_policies_report_only(
content_security_policies_report_only) {} content_security_policies_report_only),
isolation_optin_hints(isolation_optin_hints) {}
OriginPolicyContents& OriginPolicyContents::operator=( OriginPolicyContents& OriginPolicyContents::operator=(
const OriginPolicyContents& other) = default; const OriginPolicyContents& other) = default;
...@@ -38,7 +40,8 @@ bool OriginPolicyContents::operator==(const OriginPolicyContents& other) const { ...@@ -38,7 +40,8 @@ bool OriginPolicyContents::operator==(const OriginPolicyContents& other) const {
return feature_policy == other.feature_policy && return feature_policy == other.feature_policy &&
content_security_policies == other.content_security_policies && content_security_policies == other.content_security_policies &&
content_security_policies_report_only == content_security_policies_report_only ==
other.content_security_policies_report_only; other.content_security_policies_report_only &&
isolation_optin_hints == other.isolation_optin_hints;
} }
OriginPolicyContentsPtr OriginPolicyContents::ClonePtr() { OriginPolicyContentsPtr OriginPolicyContents::ClonePtr() {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include "base/optional.h" #include "base/optional.h"
#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace network { namespace network {
...@@ -54,7 +55,8 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) OriginPolicyContents { ...@@ -54,7 +55,8 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) OriginPolicyContents {
OriginPolicyContents( OriginPolicyContents(
const base::Optional<std::string>& feature_policy, const base::Optional<std::string>& feature_policy,
const std::vector<std::string>& content_security_policies, const std::vector<std::string>& content_security_policies,
const std::vector<std::string>& content_security_policies_report_only); const std::vector<std::string>& content_security_policies_report_only,
const base::Optional<IsolationOptInHints>& isolation_optin_hints);
OriginPolicyContents(const OriginPolicyContents& other); OriginPolicyContents(const OriginPolicyContents& other);
OriginPolicyContents& operator=(const OriginPolicyContents& other); OriginPolicyContents& operator=(const OriginPolicyContents& other);
...@@ -83,6 +85,11 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) OriginPolicyContents { ...@@ -83,6 +85,11 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) OriginPolicyContents {
// a "report" disposition. // a "report" disposition.
// https://w3c.github.io/webappsec-csp/#policy-disposition // https://w3c.github.io/webappsec-csp/#policy-disposition
std::vector<std::string> content_security_policies_report_only; std::vector<std::string> content_security_policies_report_only;
// This field, if present, indicates that the origin is opting in to
// origin-based isolation. The int contains zero or more flag bits indicating
// what the origin is hoping to achieve through isolation.
base::Optional<IsolationOptInHints> isolation_optin_hints;
}; };
// Native implementation of mojom::OriginPolicy. This is done so we can pass // Native implementation of mojom::OriginPolicy. This is done so we can pass
......
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