Commit 45a07239 authored by Karandeep Bhatia's avatar Karandeep Bhatia Committed by Chromium LUCI CQ

DNR: Raise an error for large regex session-scoped rule.

BUG=1043200

Change-Id: Idec165bcfb959b75d789315703c69151cc6434b8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2551320
Commit-Queue: Karan Bhatia <karandeepb@chromium.org>
Reviewed-by: default avatarKelvin Jiang <kelvinjiang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833808}
parent 9f6d3bc6
...@@ -62,6 +62,7 @@ namespace { ...@@ -62,6 +62,7 @@ namespace {
constexpr char kJSONRulesFilename[] = "rules_file.json"; constexpr char kJSONRulesFilename[] = "rules_file.json";
constexpr char kSmallRegexFilter[] = "http://(yahoo|google)\\.com";
constexpr char kLargeRegexFilter[] = ".{512}x"; constexpr char kLargeRegexFilter[] = ".{512}x";
constexpr char kId1[] = "1.json"; constexpr char kId1[] = "1.json";
...@@ -199,11 +200,12 @@ class DeclarativeNetRequestUnittest : public DNRTestBase { ...@@ -199,11 +200,12 @@ class DeclarativeNetRequestUnittest : public DNRTestBase {
enum class RulesetScope { kDynamic, kSession }; enum class RulesetScope { kDynamic, kSession };
// Runs the updateDynamicRules/updateSessionRules extension function based on // Runs the updateDynamicRules/updateSessionRules extension function based on
// |scope|. // |scope| and verifies the success/failure based on |expected_error|.
bool RunUpdateRulesFunction(const Extension& extension, void RunUpdateRulesFunction(const Extension& extension,
const std::vector<int>& rule_ids_to_remove, const std::vector<int>& rule_ids_to_remove,
const std::vector<TestRule>& rules_to_add, const std::vector<TestRule>& rules_to_add,
RulesetScope scope) { RulesetScope scope,
const std::string* expected_error = nullptr) {
std::unique_ptr<base::Value> ids_to_remove_value = std::unique_ptr<base::Value> ids_to_remove_value =
ListBuilder() ListBuilder()
.Append(rule_ids_to_remove.begin(), rule_ids_to_remove.end()) .Append(rule_ids_to_remove.begin(), rule_ids_to_remove.end())
...@@ -233,8 +235,15 @@ class DeclarativeNetRequestUnittest : public DNRTestBase { ...@@ -233,8 +235,15 @@ class DeclarativeNetRequestUnittest : public DNRTestBase {
} }
update_function->set_extension(&extension); update_function->set_extension(&extension);
update_function->set_has_callback(true); update_function->set_has_callback(true);
return api_test_utils::RunFunction(update_function.get(), json_args, if (!expected_error) {
browser_context()); ASSERT_TRUE(api_test_utils::RunFunction(update_function.get(), json_args,
browser_context()));
return;
}
ASSERT_EQ(*expected_error,
api_test_utils::RunFunctionAndReturnError(
update_function.get(), json_args, browser_context()));
} }
// Runs getDynamicRules/getSessionRules extension function and populates // Runs getDynamicRules/getSessionRules extension function and populates
...@@ -784,7 +793,7 @@ TEST_P(SingleRulesetTest, LargeRegexIgnored) { ...@@ -784,7 +793,7 @@ TEST_P(SingleRulesetTest, LargeRegexIgnored) {
int id = kMinValidID; int id = kMinValidID;
const int kNumSmallRegex = 5; const int kNumSmallRegex = 5;
std::string small_regex = "http://(yahoo|google)\\.com"; std::string small_regex = kSmallRegexFilter;
for (int i = 0; i < kNumSmallRegex; i++, id++) { for (int i = 0; i < kNumSmallRegex; i++, id++) {
rule.id = id; rule.id = id;
rule.condition->regex_filter = small_regex; rule.condition->regex_filter = small_regex;
...@@ -940,7 +949,8 @@ TEST_P(SingleRulesetTest, DynamicRulesetRace) { ...@@ -940,7 +949,8 @@ TEST_P(SingleRulesetTest, DynamicRulesetRace) {
// Add some dynamic rules. // Add some dynamic rules.
std::vector<TestRule> dynamic_rules({CreateGenericRule()}); std::vector<TestRule> dynamic_rules({CreateGenericRule()});
ASSERT_TRUE(RunUpdateRulesFunction(*extension, {} /* rule_ids_to_remove */, ASSERT_NO_FATAL_FAILURE(
RunUpdateRulesFunction(*extension, {} /* rule_ids_to_remove */,
dynamic_rules, RulesetScope::kDynamic)); dynamic_rules, RulesetScope::kDynamic));
// The API function to update the dynamic ruleset should only complete once // The API function to update the dynamic ruleset should only complete once
...@@ -1013,8 +1023,8 @@ TEST_P(SingleRulesetTest, SessionRules) { ...@@ -1013,8 +1023,8 @@ TEST_P(SingleRulesetTest, SessionRules) {
rule_1.id = 1; rule_1.id = 1;
TestRule rule_2 = CreateGenericRule(); TestRule rule_2 = CreateGenericRule();
rule_2.id = 2; rule_2.id = 2;
ASSERT_TRUE(RunUpdateRulesFunction(*extension(), {}, {rule_1, rule_2}, ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(
RulesetScope::kSession)); *extension(), {}, {rule_1, rule_2}, RulesetScope::kSession));
RunGetRulesFunction(*extension(), RulesetScope::kSession, &result); RunGetRulesFunction(*extension(), RulesetScope::kSession, &result);
EXPECT_THAT(result.GetList(), EXPECT_THAT(result.GetList(),
::testing::UnorderedElementsAre( ::testing::UnorderedElementsAre(
...@@ -1027,7 +1037,7 @@ TEST_P(SingleRulesetTest, SessionRules) { ...@@ -1027,7 +1037,7 @@ TEST_P(SingleRulesetTest, SessionRules) {
RunGetRulesFunction(*extension(), RulesetScope::kDynamic, &result); RunGetRulesFunction(*extension(), RulesetScope::kDynamic, &result);
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.empty());
ASSERT_TRUE(RunUpdateRulesFunction(*extension(), {*rule_2.id}, {}, ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(*extension(), {*rule_2.id}, {},
RulesetScope::kSession)); RulesetScope::kSession));
RunGetRulesFunction(*extension(), RulesetScope::kSession, &result); RunGetRulesFunction(*extension(), RulesetScope::kSession, &result);
EXPECT_THAT(result.GetList(), ::testing::UnorderedElementsAre(::testing::Eq( EXPECT_THAT(result.GetList(), ::testing::UnorderedElementsAre(::testing::Eq(
...@@ -1036,6 +1046,32 @@ TEST_P(SingleRulesetTest, SessionRules) { ...@@ -1036,6 +1046,32 @@ TEST_P(SingleRulesetTest, SessionRules) {
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.empty());
} }
// Ensure an error is raised when an extension adds a session-scoped regex rule
// which consumes more memory than allowed.
TEST_P(SingleRulesetTest, LargeRegexError_SessionRules) {
// Load an extension with an empty static ruleset.
RulesetManagerObserver ruleset_waiter(manager());
LoadAndExpectSuccess();
ruleset_waiter.WaitForExtensionsWithRulesetsCount(1);
// Ensure adding a normal regex rule succeeds.
TestRule normal_regex_rule = CreateGenericRule(1);
normal_regex_rule.condition->url_filter.reset();
normal_regex_rule.condition->regex_filter = std::string(kSmallRegexFilter);
ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(
*extension(), {}, {normal_regex_rule}, RulesetScope::kSession));
// Ensure an error is raised on adding a large regex rule.
TestRule large_regex_rule = CreateGenericRule(2);
large_regex_rule.condition->url_filter.reset();
large_regex_rule.condition->regex_filter = std::string(kLargeRegexFilter);
std::string expected_error =
ErrorUtils::FormatErrorMessage(kErrorRegexTooLarge, "2", kRegexFilterKey);
ASSERT_NO_FATAL_FAILURE(
RunUpdateRulesFunction(*extension(), {}, {large_regex_rule},
RulesetScope::kSession, &expected_error));
}
// Test fixture for a single ruleset with the // Test fixture for a single ruleset with the
// |kDeclarativeNetRequestGlobalRules| feature enabled. // |kDeclarativeNetRequestGlobalRules| feature enabled.
class SingleRulesetGlobalRulesTest : public SingleRulesetTest { class SingleRulesetGlobalRulesTest : public SingleRulesetTest {
...@@ -1515,10 +1551,10 @@ TEST_P(MultipleRulesetsTest, UpdateEnabledRulesets_InvalidRulesetID) { ...@@ -1515,10 +1551,10 @@ TEST_P(MultipleRulesetsTest, UpdateEnabledRulesets_InvalidRulesetID) {
// Ensure we can't enable/disable dynamic or session-scoped rulesets using // Ensure we can't enable/disable dynamic or session-scoped rulesets using
// updateEnabledRulesets. // updateEnabledRulesets.
ASSERT_TRUE(RunUpdateRulesFunction(*extension(), {}, {CreateGenericRule()}, ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(
RulesetScope::kDynamic)); *extension(), {}, {CreateGenericRule()}, RulesetScope::kDynamic));
ASSERT_TRUE(RunUpdateRulesFunction(*extension(), {}, {CreateGenericRule()}, ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(
RulesetScope::kSession)); *extension(), {}, {CreateGenericRule()}, RulesetScope::kSession));
VerifyPublicRulesetIDs(*extension(), {kId1, kId3, dnr_api::DYNAMIC_RULESET_ID, VerifyPublicRulesetIDs(*extension(), {kId1, kId3, dnr_api::DYNAMIC_RULESET_ID,
dnr_api::SESSION_RULESET_ID}); dnr_api::SESSION_RULESET_ID});
RunUpdateEnabledRulesetsFunction( RunUpdateEnabledRulesetsFunction(
...@@ -1646,10 +1682,10 @@ TEST_P(MultipleRulesetsTest, UpdateAndGetEnabledRulesets_Success) { ...@@ -1646,10 +1682,10 @@ TEST_P(MultipleRulesetsTest, UpdateAndGetEnabledRulesets_Success) {
// Add dynamic and session-scoped rules and ensure that the setEnabledRulesets // Add dynamic and session-scoped rules and ensure that the setEnabledRulesets
// call doesn't have any effect on their associated rulesets. Also ensure that // call doesn't have any effect on their associated rulesets. Also ensure that
// the getEnabledRulesets call excludes these rulesets. // the getEnabledRulesets call excludes these rulesets.
ASSERT_TRUE(RunUpdateRulesFunction(*extension(), {}, {CreateGenericRule()}, ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(
RulesetScope::kDynamic)); *extension(), {}, {CreateGenericRule()}, RulesetScope::kDynamic));
ASSERT_TRUE(RunUpdateRulesFunction(*extension(), {}, {CreateGenericRule()}, ASSERT_NO_FATAL_FAILURE(RunUpdateRulesFunction(
RulesetScope::kSession)); *extension(), {}, {CreateGenericRule()}, RulesetScope::kSession));
VerifyPublicRulesetIDs(*extension(), {kId2, kId3, dnr_api::DYNAMIC_RULESET_ID, VerifyPublicRulesetIDs(*extension(), {kId2, kId3, dnr_api::DYNAMIC_RULESET_ID,
dnr_api::SESSION_RULESET_ID}); dnr_api::SESSION_RULESET_ID});
VerifyGetEnabledRulesetsFunction(*extension(), {kId2, kId3}); VerifyGetEnabledRulesetsFunction(*extension(), {kId2, kId3});
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "extensions/common/api/declarative_net_request/constants.h" #include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h" #include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
#include "extensions/common/api/declarative_net_request/utils.h" #include "extensions/common/api/declarative_net_request/utils.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_id.h" #include "extensions/common/extension_id.h"
#include "tools/json_schema_compiler/util.h" #include "tools/json_schema_compiler/util.h"
...@@ -105,14 +106,22 @@ std::unique_ptr<RulesetMatcher> CreateSessionScopedMatcher( ...@@ -105,14 +106,22 @@ std::unique_ptr<RulesetMatcher> CreateSessionScopedMatcher(
RulesetSource source(kSessionRulesetID, kSessionRulesetLimit, extension_id, RulesetSource source(kSessionRulesetID, kSessionRulesetLimit, extension_id,
true /* enabled */); true /* enabled */);
// TODO(crbug.com/1043200): Rules which exceed the regex memory limit
// |info.regex_limit_exceeded_rules()| should be treated as errors.
ParseInfo info = source.IndexRules(std::move(rules)); ParseInfo info = source.IndexRules(std::move(rules));
if (info.has_error()) { if (info.has_error()) {
*error = info.error(); *error = info.error();
return nullptr; return nullptr;
} }
// Treat rules which exceed the regex memory limit as errors; just surface an
// error for the first such rule.
if (!info.regex_limit_exceeded_rules().empty()) {
*error = ErrorUtils::FormatErrorMessage(
kErrorRegexTooLarge,
base::NumberToString(info.regex_limit_exceeded_rules()[0]),
kRegexFilterKey);
return nullptr;
}
base::span<const uint8_t> buffer = info.GetBuffer(); base::span<const uint8_t> buffer = info.GetBuffer();
std::unique_ptr<RulesetMatcher> matcher; std::unique_ptr<RulesetMatcher> matcher;
LoadRulesetResult result = source.CreateVerifiedMatcher( LoadRulesetResult result = source.CreateVerifiedMatcher(
......
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