blob: d84ba9a24c7d2d064e4f400501ed2c9d57dfc079 [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/browser_process.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
#include "components/subresource_filter/content/browser/ruleset_service.h"
#include "components/subresource_filter/core/common/common_features.h"
#include "components/subresource_filter/core/common/indexed_ruleset.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace subresource_filter {
namespace {
const mojom::ActivationState kDisabled;
RulesetVerificationStatus GetRulesetVerification() {
RulesetService* service =
g_browser_process->subresource_filter_ruleset_service();
VerifiedRulesetDealer::Handle* dealer_handle = service->GetRulesetDealer();
auto callback_method = [](base::OnceClosure quit_closure,
RulesetVerificationStatus* status,
VerifiedRulesetDealer* verified_dealer) {
*status = verified_dealer->status();
std::move(quit_closure).Run();
};
RulesetVerificationStatus status;
base::RunLoop run_loop;
auto callback =
base::BindRepeating(callback_method, run_loop.QuitClosure(), &status);
dealer_handle->GetDealerAsync(callback);
run_loop.Run();
return status;
}
const char kIndexedRulesetVerifyHistogram[] =
"SubresourceFilter.IndexRuleset.Verify.Status";
} // namespace
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
RulesetVerified_Activation) {
base::HistogramTester histogram_tester;
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
RulesetService* service =
g_browser_process->subresource_filter_ruleset_service();
ASSERT_TRUE(service->GetRulesetDealer());
auto ruleset_handle =
std::make_unique<VerifiedRuleset::Handle>(service->GetRulesetDealer());
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("https://example.com/"), mojom::ActivationLevel::kEnabled, false);
testing::TestActivationStateCallbackReceiver receiver;
AsyncDocumentSubresourceFilter filter(ruleset_handle.get(), std::move(params),
receiver.GetCallback());
receiver.WaitForActivationDecision();
mojom::ActivationState expected_state;
expected_state.activation_level = mojom::ActivationLevel::kEnabled;
receiver.ExpectReceivedOnce(expected_state);
histogram_tester.ExpectUniqueSample(kIndexedRulesetVerifyHistogram,
VerifyStatus::kPassValidChecksum, 1);
}
// TODO(ericrobinson): Add a test using a PRE_ phase that corrupts the ruleset
// on disk to test something closer to an actual execution path for checksum.
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, NoRuleset_NoActivation) {
base::HistogramTester histogram_tester;
// Do not set the ruleset, which results in an invalid ruleset.
RulesetService* service =
g_browser_process->subresource_filter_ruleset_service();
ASSERT_TRUE(service->GetRulesetDealer());
auto ruleset_handle =
std::make_unique<VerifiedRuleset::Handle>(service->GetRulesetDealer());
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("https://example.com/"), mojom::ActivationLevel::kEnabled, false);
testing::TestActivationStateCallbackReceiver receiver;
AsyncDocumentSubresourceFilter filter(ruleset_handle.get(), std::move(params),
receiver.GetCallback());
receiver.WaitForActivationDecision();
receiver.ExpectReceivedOnce(kDisabled);
histogram_tester.ExpectTotalCount(kIndexedRulesetVerifyHistogram, 0);
}
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, InvalidRuleset_Checksum) {
base::HistogramTester histogram_tester;
const char kTestRulesetSuffix[] = "foo";
const int kNumberOfRules = 500;
TestRulesetCreator ruleset_creator;
TestRulesetPair test_ruleset_pair;
ASSERT_NO_FATAL_FAILURE(
ruleset_creator.CreateRulesetToDisallowURLsWithManySuffixes(
kTestRulesetSuffix, kNumberOfRules, &test_ruleset_pair));
RulesetService* service =
g_browser_process->subresource_filter_ruleset_service();
// Publish the good ruleset.
TestRulesetPublisher publisher;
publisher.SetRuleset(test_ruleset_pair.unindexed);
// Now corrupt it by flipping one entry. This can only be detected
// via the checksum, and not the Flatbuffer Verifier. This was determined
// at random by flipping elements until this test failed, then adding
// the checksum code and ensuring it passed.
testing::TestRuleset::CorruptByFilling(test_ruleset_pair.indexed, 28250,
28251, 32);
OpenAndPublishRuleset(service, test_ruleset_pair.indexed.path);
ASSERT_TRUE(service->GetRulesetDealer());
auto ruleset_handle =
std::make_unique<VerifiedRuleset::Handle>(service->GetRulesetDealer());
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("https://example.com/"), mojom::ActivationLevel::kEnabled, false);
testing::TestActivationStateCallbackReceiver receiver;
AsyncDocumentSubresourceFilter filter(ruleset_handle.get(), std::move(params),
receiver.GetCallback());
receiver.WaitForActivationDecision();
receiver.ExpectReceivedOnce(kDisabled);
RulesetVerificationStatus dealer_status = GetRulesetVerification();
EXPECT_EQ(RulesetVerificationStatus::kCorrupt, dealer_status);
// If AdTagging is enabled, then the initial SetRuleset will trigger
// a call to Verify. Make sure we see that and the later failure.
if (base::FeatureList::IsEnabled(kAdTagging)) {
histogram_tester.ExpectBucketCount(kIndexedRulesetVerifyHistogram,
VerifyStatus::kPassValidChecksum, 1);
histogram_tester.ExpectBucketCount(kIndexedRulesetVerifyHistogram,
VerifyStatus::kChecksumFailVerifierPass,
1);
histogram_tester.ExpectTotalCount(kIndexedRulesetVerifyHistogram, 2);
} else {
// Otherwise we see only a single Verify when the new ruleset is accessed,
// and that should be a failure.
histogram_tester.ExpectUniqueSample(kIndexedRulesetVerifyHistogram,
VerifyStatus::kChecksumFailVerifierPass,
1);
}
}
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
InvalidRuleset_NoActivation) {
base::HistogramTester histogram_tester;
const char kTestRulesetSuffix[] = "foo";
const int kNumberOfRules = 500;
TestRulesetCreator ruleset_creator;
TestRulesetPair test_ruleset_pair;
ASSERT_NO_FATAL_FAILURE(
ruleset_creator.CreateRulesetToDisallowURLsWithManySuffixes(
kTestRulesetSuffix, kNumberOfRules, &test_ruleset_pair));
testing::TestRuleset::CorruptByTruncating(test_ruleset_pair.indexed, 123);
// Just publish the corrupt indexed file directly, to simulate it being
// corrupt on startup.
RulesetService* service =
g_browser_process->subresource_filter_ruleset_service();
ASSERT_TRUE(service->GetRulesetDealer());
OpenAndPublishRuleset(service, test_ruleset_pair.indexed.path);
auto ruleset_handle =
std::make_unique<VerifiedRuleset::Handle>(service->GetRulesetDealer());
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("https://example.com/"), mojom::ActivationLevel::kEnabled, false);
testing::TestActivationStateCallbackReceiver receiver;
AsyncDocumentSubresourceFilter filter(ruleset_handle.get(), std::move(params),
receiver.GetCallback());
receiver.WaitForActivationDecision();
receiver.ExpectReceivedOnce(kDisabled);
RulesetVerificationStatus dealer_status = GetRulesetVerification();
EXPECT_EQ(RulesetVerificationStatus::kCorrupt, dealer_status);
histogram_tester.ExpectUniqueSample(kIndexedRulesetVerifyHistogram,
VerifyStatus::kVerifierFailChecksumZero,
1);
}
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, LazyRulesetValidation) {
// The ruleset shouldn't be validated until it's used, unless ad tagging is
// enabled.
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(subresource_filter::kAdTagging);
SetRulesetToDisallowURLsWithPathSuffix("included_script.js");
RulesetVerificationStatus dealer_status = GetRulesetVerification();
EXPECT_EQ(RulesetVerificationStatus::kNotVerified, dealer_status);
}
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
AdsTaggingImmediateRulesetValidation) {
// When Ads Tagging is enabled, the ruleset should be validated as soon as
// it's published.
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(subresource_filter::kAdTagging);
SetRulesetToDisallowURLsWithPathSuffix("included_script.js");
RulesetVerificationStatus dealer_status = GetRulesetVerification();
EXPECT_EQ(RulesetVerificationStatus::kIntact, dealer_status);
}
} // namespace subresource_filter