diff options
author | veranika <veranika@chromium.org> | 2016-02-19 08:58:06 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-19 16:59:15 +0000 |
commit | fbe7992cbb2da2bf1f129c3e2b6ca7271da86dc8 (patch) | |
tree | 46db631a2fd62bb198f4b7fcd571295090b06183 | |
parent | e59898e64e0a0473cf1c3bf263d3e331d92ccfcf (diff) | |
download | chromium_src-fbe7992cbb2da2bf1f129c3e2b6ca7271da86dc8.zip chromium_src-fbe7992cbb2da2bf1f129c3e2b6ca7271da86dc8.tar.gz chromium_src-fbe7992cbb2da2bf1f129c3e2b6ca7271da86dc8.tar.bz2 |
Support new Safe Browsing list "goog-badresource-shavar" in SafeBrowsingDatabase.
Load the list from servers. Check URLs for presence in the database.
BUG=582204
Review URL: https://codereview.chromium.org/1673733002
Cr-Commit-Position: refs/heads/master@{#376460}
15 files changed, 447 insertions, 56 deletions
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc index 9763d6e..38395ff 100644 --- a/chrome/browser/safe_browsing/local_database_manager.cc +++ b/chrome/browser/safe_browsing/local_database_manager.cc @@ -5,6 +5,7 @@ #include "chrome/browser/safe_browsing/local_database_manager.h" #include <algorithm> +#include <limits> #include "base/bind.h" #include "base/bind_helpers.h" @@ -72,6 +73,34 @@ bool IsExpectedThreat( threat_type); } +// Returns threat level of the list. Lists with lower threat levels are more +// severe than lists with higher threat levels. Zero is the severest threat +// level possible. +int GetThreatSeverity(ListType threat) { + switch (threat) { + case MALWARE: // Falls through. + case PHISH: // Falls through. + case BINURL: // Falls through. + case CSDWHITELIST: // Falls through. + case DOWNLOADWHITELIST: // Falls through. + case INCLUSIONWHITELIST: // Falls through. + case MODULEWHITELIST: // Falls through. + case EXTENSIONBLACKLIST: // Falls through. + case IPBLACKLIST: + return 0; + case UNWANTEDURL: + // UNWANTEDURL is considered less severe than other threats. + return 1; + case RESOURCEBLACKLIST: + // RESOURCEBLACKLIST is even less severe than UNWANTEDURL. + return 2; + case INVALID: + return std::numeric_limits<int>::max(); + } + NOTREACHED(); + return -1; +} + // Return the severest list id from the results in |full_hashes| which matches // |hash|, or INVALID if none match. ListType GetHashSeverestThreatListType( @@ -79,35 +108,20 @@ ListType GetHashSeverestThreatListType( const std::vector<SBFullHashResult>& full_hashes, size_t* index) { ListType pending_threat = INVALID; + int pending_threat_severity = GetThreatSeverity(INVALID); for (size_t i = 0; i < full_hashes.size(); ++i) { if (SBFullHashEqual(hash, full_hashes[i].hash)) { const ListType threat = static_cast<ListType>(full_hashes[i].list_id); - switch (threat) { - case INVALID: - // |full_hashes| should never contain INVALID as a |list_id|. - NOTREACHED(); - break; - case MALWARE: // Falls through. - case PHISH: // Falls through. - case BINURL: // Falls through. - case CSDWHITELIST: // Falls through. - case DOWNLOADWHITELIST: // Falls through. - case INCLUSIONWHITELIST: // Falls through. - case MODULEWHITELIST: // Falls through. - case EXTENSIONBLACKLIST: // Falls through. - case IPBLACKLIST: - if (index) - *index = i; - return threat; - case UNWANTEDURL: - // UNWANTEDURL is considered less severe than other threats, keep - // looking. - pending_threat = threat; - if (index) - *index = i; - break; + int threat_severity = GetThreatSeverity(threat); + if (threat_severity < pending_threat_severity) { + pending_threat = threat; + pending_threat_severity = threat_severity; + if (index) + *index = i; } + if (pending_threat_severity == 0) + return pending_threat; } } return pending_threat; @@ -127,29 +141,17 @@ ListType GetUrlSeverestThreatListType( GeneratePatternsToCheck(url, &patterns); ListType pending_threat = INVALID; + int pending_threat_severity = GetThreatSeverity(INVALID); for (size_t i = 0; i < patterns.size(); ++i) { ListType threat = GetHashSeverestThreatListType( SBFullHashForString(patterns[i]), full_hashes, index); - switch (threat) { - case INVALID: - // Ignore patterns with no matching threat. - break; - case MALWARE: // Falls through. - case PHISH: // Falls through. - case BINURL: // Falls through. - case CSDWHITELIST: // Falls through. - case DOWNLOADWHITELIST: // Falls through. - case INCLUSIONWHITELIST: // Falls through. - case MODULEWHITELIST: // Falls through. - case EXTENSIONBLACKLIST: // Falls through. - case IPBLACKLIST: - return threat; - case UNWANTEDURL: - // UNWANTEDURL is considered less severe than other threats, keep - // looking. - pending_threat = threat; - break; + int threat_severity = GetThreatSeverity(threat); + if (threat_severity < pending_threat_severity) { + pending_threat = threat; + pending_threat_severity = threat_severity; } + if (pending_threat_severity == 0) + return pending_threat; } return pending_threat; } @@ -166,6 +168,8 @@ SBThreatType GetThreatTypeFromListType(ListType list_type) { return SB_THREAT_TYPE_BINARY_MALWARE_URL; case EXTENSIONBLACKLIST: return SB_THREAT_TYPE_EXTENSION; + case RESOURCEBLACKLIST: + return SB_THREAT_TYPE_BLACKLISTED_RESOURCE; default: DVLOG(1) << "Unknown safe browsing list id " << list_type; return SB_THREAT_TYPE_SAFE; @@ -200,6 +204,7 @@ LocalSafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck( : urls(urls), url_results(urls.size(), SB_THREAT_TYPE_SAFE), url_metadata(urls.size()), + url_hit_hash(urls.size()), full_hashes(full_hashes), full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE), client(client), @@ -235,6 +240,11 @@ void LocalSafeBrowsingDatabaseManager::SafeBrowsingCheck:: client->OnCheckDownloadUrlResult( urls, *std::max_element(url_results.begin(), url_results.end())); break; + case RESOURCEBLACKLIST: + DCHECK_EQ(1u, urls.size()); + client->OnCheckResourceUrlResult(urls[0], url_results[0], + url_hit_hash[0]); + break; default: NOTREACHED(); } @@ -389,6 +399,36 @@ bool LocalSafeBrowsingDatabaseManager::CheckExtensionIDs( return false; } +bool LocalSafeBrowsingDatabaseManager::CheckResourceUrl( + const GURL& url, Client* client) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (!enabled_ || !CanCheckUrl(url)) + return true; + + std::vector<SBThreatType> expected_threats = + {SB_THREAT_TYPE_BLACKLISTED_RESOURCE}; + + if (!MakeDatabaseAvailable()) { + QueuedCheck queued_check(RESOURCEBLACKLIST, client, url, + expected_threats, base::TimeTicks::Now()); + queued_checks_.push_back(queued_check); + return false; + } + + SafeBrowsingCheck* check = + new SafeBrowsingCheck({url}, std::vector<SBFullHash>(), client, + RESOURCEBLACKLIST, expected_threats); + + std::vector<SBPrefix> prefixes; + SafeBrowsingDatabase::GetDownloadUrlPrefixes(check->urls, &prefixes); + StartSafeBrowsingCheck( + check, + base::Bind(&LocalSafeBrowsingDatabaseManager::CheckResourceUrlOnSBThread, + this, prefixes)); + return false; +} + bool LocalSafeBrowsingDatabaseManager::MatchMalwareIP( const std::string& ip_address) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -1110,6 +1150,9 @@ bool LocalSafeBrowsingDatabaseManager::HandleOneCheck( if (threat != SB_THREAT_TYPE_SAFE) { check->url_results[i] = threat; check->url_metadata[i] = expected_full_hashes[threat_index].metadata; + const SBFullHash& hash = expected_full_hashes[threat_index].hash; + check->url_hit_hash[i] = std::string(hash.full_hash, + arraysize(hash.full_hash)); is_threat = true; } } @@ -1167,6 +1210,18 @@ LocalSafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread( return prefix_hits; } +std::vector<SBPrefix> +LocalSafeBrowsingDatabaseManager::CheckResourceUrlOnSBThread( + const std::vector<SBPrefix>& prefixes) { + DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); + + std::vector<SBPrefix> prefix_hits; + const bool result = + database_->ContainsResourceUrlPrefixes(prefixes, &prefix_hits); + DCHECK_EQ(result, !prefix_hits.empty()); + return prefix_hits; +} + void LocalSafeBrowsingDatabaseManager::TimeoutCallback( SafeBrowsingCheck* check) { DCHECK_CURRENTLY_ON(BrowserThread::IO); diff --git a/chrome/browser/safe_browsing/local_database_manager.h b/chrome/browser/safe_browsing/local_database_manager.h index ef543e9..c163503 100644 --- a/chrome/browser/safe_browsing/local_database_manager.h +++ b/chrome/browser/safe_browsing/local_database_manager.h @@ -66,9 +66,13 @@ class LocalSafeBrowsingDatabaseManager // Either |urls| or |full_hashes| is used to lookup database. |*_results| // are parallel vectors containing the results. They are initialized to // contain SB_THREAT_TYPE_SAFE. + // |url_hit_hash| and |url_metadata| are parallel vectors containing full + // hash and metadata of a database record provided the result. They are + // initialized to be empty strings. std::vector<GURL> urls; std::vector<SBThreatType> url_results; std::vector<std::string> url_metadata; + std::vector<std::string> url_hit_hash; std::vector<SBFullHash> full_hashes; std::vector<SBThreatType> full_hash_results; @@ -115,6 +119,7 @@ class LocalSafeBrowsingDatabaseManager Client* client) override; bool CheckExtensionIDs(const std::set<std::string>& extension_ids, Client* client) override; + bool CheckResourceUrl(const GURL& url, Client* client) override; bool MatchCsdWhitelistUrl(const GURL& url) override; bool MatchMalwareIP(const std::string& ip_address) override; bool MatchDownloadWhitelistUrl(const GURL& url) override; @@ -286,6 +291,10 @@ class LocalSafeBrowsingDatabaseManager std::vector<SBPrefix> CheckExtensionIDsOnSBThread( const std::vector<SBPrefix>& prefixes); + // Checks all resource URL hashes on |safe_browsing_task_runner_|. + std::vector<SBPrefix> CheckResourceUrlOnSBThread( + const std::vector<SBPrefix>& prefixes); + // Helper function that calls safe browsing client and cleans up |checks_|. void SafeBrowsingCheckDone(SafeBrowsingCheck* check); diff --git a/chrome/browser/safe_browsing/local_database_manager_unittest.cc b/chrome/browser/safe_browsing/local_database_manager_unittest.cc index 5ea449d..96f3236 100644 --- a/chrome/browser/safe_browsing/local_database_manager_unittest.cc +++ b/chrome/browser/safe_browsing/local_database_manager_unittest.cc @@ -149,6 +149,9 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { const GURL kUnwantedUrl("http://www.unwanted.com/page.html"); const GURL kUnwantedAndMalwareUrl( "http://www.unwantedandmalware.com/page.html"); + const GURL kBlacklistedResourceUrl("http://www.blacklisted.com/script.js"); + const GURL kUnwantedResourceUrl("http://www.unwantedresource.com/script.js"); + const GURL kMalwareResourceUrl("http://www.malwareresource.com/script.js"); const GURL kSafeUrl("http://www.safe.com/page.html"); const SBFullHash kMalwareHostHash = SBFullHashForString("malware.com/"); @@ -156,6 +159,12 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { const SBFullHash kUnwantedHostHash = SBFullHashForString("unwanted.com/"); const SBFullHash kUnwantedAndMalwareHostHash = SBFullHashForString("unwantedandmalware.com/"); + const SBFullHash kBlacklistedResourceHostHash = + SBFullHashForString("blacklisted.com/"); + const SBFullHash kUnwantedResourceHostHash = + SBFullHashForString("unwantedresource.com/"); + const SBFullHash kMalwareResourceHostHash = + SBFullHashForString("malwareresource.com/"); const SBFullHash kSafeHostHash = SBFullHashForString("www.safe.com/"); { @@ -180,6 +189,13 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { } { + SBFullHashResult full_hash; + full_hash.hash = kBlacklistedResourceHostHash; + full_hash.list_id = static_cast<int>(RESOURCEBLACKLIST); + full_hashes.push_back(full_hash); + } + + { // Add both MALWARE and UNWANTEDURL list IDs for // kUnwantedAndMalwareHostHash. SBFullHashResult full_hash_malware; @@ -193,6 +209,26 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { full_hashes.push_back(full_hash_unwanted); } + { + SBFullHashResult full_hash_unwanted = + {kUnwantedResourceHostHash, static_cast<int>(UNWANTEDURL)}; + full_hashes.push_back(full_hash_unwanted); + + SBFullHashResult full_hash_resource = + {kUnwantedResourceHostHash, static_cast<int>(RESOURCEBLACKLIST)}; + full_hashes.push_back(full_hash_resource); + } + + { + SBFullHashResult full_hash_malware = + {kMalwareResourceHostHash, static_cast<int>(MALWARE)}; + full_hashes.push_back(full_hash_malware); + + SBFullHashResult full_hash_resource = + {kMalwareResourceHostHash, static_cast<int>(RESOURCEBLACKLIST)}; + full_hashes.push_back(full_hash_resource); + } + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, LocalSafeBrowsingDatabaseManager::GetHashSeverestThreatType( kMalwareHostHash, full_hashes)); @@ -209,6 +245,18 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { LocalSafeBrowsingDatabaseManager::GetHashSeverestThreatType( kUnwantedAndMalwareHostHash, full_hashes)); + EXPECT_EQ(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, + LocalSafeBrowsingDatabaseManager::GetHashSeverestThreatType( + kBlacklistedResourceHostHash, full_hashes)); + + EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, + LocalSafeBrowsingDatabaseManager::GetHashSeverestThreatType( + kUnwantedResourceHostHash, full_hashes)); + + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, + LocalSafeBrowsingDatabaseManager::GetHashSeverestThreatType( + kMalwareResourceHostHash, full_hashes)); + EXPECT_EQ(SB_THREAT_TYPE_SAFE, LocalSafeBrowsingDatabaseManager::GetHashSeverestThreatType( kSafeHostHash, full_hashes)); @@ -230,10 +278,25 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { kUnwantedUrl, full_hashes, &index)); EXPECT_EQ(2U, index); + EXPECT_EQ(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, + LocalSafeBrowsingDatabaseManager::GetUrlSeverestThreatType( + kBlacklistedResourceUrl, full_hashes, &index)); + EXPECT_EQ(3U, index); + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, LocalSafeBrowsingDatabaseManager::GetUrlSeverestThreatType( kUnwantedAndMalwareUrl, full_hashes, &index)); - EXPECT_EQ(3U, index); + EXPECT_EQ(4U, index); + + EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, + LocalSafeBrowsingDatabaseManager::GetUrlSeverestThreatType( + kUnwantedResourceUrl, full_hashes, &index)); + EXPECT_EQ(6U, index); + + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, + LocalSafeBrowsingDatabaseManager::GetUrlSeverestThreatType( + kMalwareResourceUrl, full_hashes, &index)); + EXPECT_EQ(8U, index); index = kArbitraryValue; EXPECT_EQ(SB_THREAT_TYPE_SAFE, diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc index 26f1eea..cd78d76 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database.cc @@ -72,6 +72,9 @@ const base::FilePath::CharType kUnwantedSoftwareDBFile[] = FILE_PATH_LITERAL(" UwS List"); const base::FilePath::CharType kModuleWhitelistDBFile[] = FILE_PATH_LITERAL(" Module Whitelist"); +// Filename suffix for the resource blacklist store. +const base::FilePath::CharType kResourceBlacklistDBFile[] = + FILE_PATH_LITERAL(" Resource Blacklist"); // Filename suffix for browse store. // TODO(shess): "Safe Browsing Bloom Prefix Set" is full of win. @@ -293,7 +296,8 @@ class SafeBrowsingDatabaseFactoryImpl : public SafeBrowsingDatabaseFactory { CreateStore(enable_extension_blacklist, db_task_runner), CreateStore(enable_ip_blacklist, db_task_runner), CreateStore(enable_unwanted_software_list, db_task_runner), - CreateStore(enable_module_whitelist, db_task_runner)); + CreateStore(enable_module_whitelist, db_task_runner), + CreateStore(true, db_task_runner)); // resource_blacklist_store } SafeBrowsingDatabaseFactoryImpl() {} @@ -404,6 +408,12 @@ base::FilePath SafeBrowsingDatabase::ModuleWhitelistDBFilename( } // static +base::FilePath SafeBrowsingDatabase::ResourceBlacklistDBFilename( + const base::FilePath& db_filename) { + return base::FilePath(db_filename.value() + kResourceBlacklistDBFile); +} + +// static void SafeBrowsingDatabase::GetDownloadUrlPrefixes( const std::vector<GURL>& urls, std::vector<SBPrefix>* prefixes) { @@ -437,6 +447,8 @@ SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { return unwanted_software_store_.get(); } else if (list_id == MODULEWHITELIST) { return module_whitelist_store_.get(); + } else if (list_id == RESOURCEBLACKLIST) { + return resource_blacklist_store_.get(); } return NULL; } @@ -624,7 +636,8 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew( SafeBrowsingStore* extension_blacklist_store, SafeBrowsingStore* ip_blacklist_store, SafeBrowsingStore* unwanted_software_store, - SafeBrowsingStore* module_whitelist_store) + SafeBrowsingStore* module_whitelist_store, + SafeBrowsingStore* resource_blacklist_store) : db_task_runner_(db_task_runner), state_manager_(db_task_runner_), db_state_manager_(db_task_runner_), @@ -637,6 +650,7 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew( ip_blacklist_store_(ip_blacklist_store), unwanted_software_store_(unwanted_software_store), module_whitelist_store_(module_whitelist_store), + resource_blacklist_store_(resource_blacklist_store), reset_factory_(this) { DCHECK(browse_store_.get()); } @@ -801,6 +815,13 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) { state_manager_.BeginWriteTransaction()->WhitelistEverything( SBWhitelistId::MODULE); // Just to be safe. } + + if (resource_blacklist_store_.get()) { + resource_blacklist_store_->Init( + ResourceBlacklistDBFilename(db_state_manager_.filename_base()), + base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase, + base::Unretained(this))); + } } bool SafeBrowsingDatabaseNew::ResetDatabase() { @@ -983,6 +1004,18 @@ bool SafeBrowsingDatabaseNew::ContainsMalwareIP(const std::string& ip_address) { return false; } +bool SafeBrowsingDatabaseNew::ContainsResourceUrlPrefixes( + const std::vector<SBPrefix>& prefixes, + std::vector<SBPrefix>* prefix_hits) { + DCHECK(db_task_runner_->RunsTasksOnCurrentThread()); + + if (!resource_blacklist_store_) + return false; + + return MatchAddPrefixes(resource_blacklist_store_.get(), + RESOURCEBLACKLIST % 2, prefixes, prefix_hits); +} + bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedString( const std::string& str) { std::vector<SBFullHash> hashes; @@ -1227,6 +1260,12 @@ bool SafeBrowsingDatabaseNew::UpdateStarted( return false; } + if (resource_blacklist_store_ && !resource_blacklist_store_->BeginUpdate()) { + RecordFailure(FAILURE_RESOURCE_BLACKLIST_UPDATE_BEGIN); + HandleCorruptDatabase(); + return false; + } + // Cached fullhash results must be cleared on every database update (whether // successful or not). state_manager_.BeginWriteTransaction()->clear_prefix_gethash_cache(); @@ -1259,6 +1298,9 @@ bool SafeBrowsingDatabaseNew::UpdateStarted( UpdateChunkRangesForList(module_whitelist_store_.get(), kModuleWhitelist, lists); + UpdateChunkRangesForList(resource_blacklist_store_.get(), kResourceBlacklist, + lists); + db_state_manager_.reset_corruption_detected(); db_state_manager_.reset_change_detected(); return true; @@ -1310,6 +1352,11 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { if (module_whitelist_store_ && !module_whitelist_store_->CheckValidity()) { DLOG(ERROR) << "Module digest whitelist database corrupt."; } + + if (resource_blacklist_store_ && + !resource_blacklist_store_->CheckValidity()) { + DLOG(ERROR) << "Resources blacklist url list database corrupt."; + } } if (db_state_manager_.corruption_detected()) @@ -1339,6 +1386,8 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { unwanted_software_store_->CancelUpdate(); if (module_whitelist_store_) module_whitelist_store_->CancelUpdate(); + if (resource_blacklist_store_) + resource_blacklist_store_->CancelUpdate(); return; } @@ -1386,6 +1435,13 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { ModuleWhitelistDBFilename(db_state_manager_.filename_base()), module_whitelist_store_.get(), SBWhitelistId::MODULE); } + + if (resource_blacklist_store_) { + UpdateHashPrefixStore( + ResourceBlacklistDBFilename(db_state_manager_.filename_base()), + resource_blacklist_store_.get(), + FAILURE_RESOURCE_BLACKLIST_UPDATE_FINISH); + } } void SafeBrowsingDatabaseNew::UpdateWhitelistStore( @@ -1669,7 +1725,12 @@ bool SafeBrowsingDatabaseNew::Delete() { if (!r10) RecordFailure(FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE); - return r1 && r2 && r3 && r4 && r5 && r6 && r7 && r8 && r9 && r10; + const bool r11 = base::DeleteFile( + ResourceBlacklistDBFilename(db_state_manager_.filename_base()), false); + if (!r11) + RecordFailure(FAILURE_RESOURCE_BLACKLIST_DELETE); + + return r1 && r2 && r3 && r4 && r5 && r6 && r7 && r8 && r9 && r10 && r11; } void SafeBrowsingDatabaseNew::WritePrefixSet(const base::FilePath& db_filename, @@ -1845,6 +1906,9 @@ void SafeBrowsingDatabaseNew::RecordFileSizeHistogram( else if (base::EndsWith(filename, kModuleWhitelistDBFile, base::CompareCase::SENSITIVE)) histogram_name.append(".ModuleWhitelist"); + else if (base::EndsWith(filename, kResourceBlacklistDBFile, + base::CompareCase::SENSITIVE)) + histogram_name.append(".ResourceBlacklist"); else NOTREACHED(); // Add support for new lists above. diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h index 719241f..eb7d0d3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.h +++ b/chrome/browser/safe_browsing/safe_browsing_database.h @@ -175,6 +175,14 @@ class SafeBrowsingDatabase { // This function is safe to call from any thread. virtual bool ContainsMalwareIP(const std::string& ip_address) = 0; + // Populates |prefix_hits| with any prefixes in |prefixes| that have matches + // in the database. Returns true iff there were any matches. + // + // This function can ONLY by accessed from the creation thread. + virtual bool ContainsResourceUrlPrefixes( + const std::vector<SBPrefix>& prefixes, + std::vector<SBPrefix>* prefix_hits) = 0; + // A database transaction should look like: // // std::vector<SBListChunkRanges> lists; @@ -270,6 +278,9 @@ class SafeBrowsingDatabase { static base::FilePath ModuleWhitelistDBFilename( const base::FilePath& db_filename); + static base::FilePath ResourceBlacklistDBFilename( + const base::FilePath& db_filename); + // Get the prefixes matching the download |urls|. static void GetDownloadUrlPrefixes(const std::vector<GURL>& urls, std::vector<SBPrefix>* prefixes); @@ -313,6 +324,9 @@ class SafeBrowsingDatabase { FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ = 32, FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE = 33, FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE = 34, + FAILURE_RESOURCE_BLACKLIST_UPDATE_BEGIN = 35, + FAILURE_RESOURCE_BLACKLIST_UPDATE_FINISH = 36, + FAILURE_RESOURCE_BLACKLIST_DELETE = 37, // Memory space for histograms is determined by the max. ALWAYS // ADD NEW VALUES BEFORE THIS ONE. @@ -343,7 +357,8 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { SafeBrowsingStore* extension_blacklist_store, SafeBrowsingStore* ip_blacklist_store, SafeBrowsingStore* unwanted_software_store, - SafeBrowsingStore* module_whitelist_store); + SafeBrowsingStore* module_whitelist_store, + SafeBrowsingStore* resource_blacklist_store); ~SafeBrowsingDatabaseNew() override; @@ -374,6 +389,9 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { bool ContainsExtensionPrefixes(const std::vector<SBPrefix>& prefixes, std::vector<SBPrefix>* prefix_hits) override; bool ContainsMalwareIP(const std::string& ip_address) override; + bool ContainsResourceUrlPrefixes(const std::vector<SBPrefix>& prefixes, + std::vector<SBPrefix>* prefix_hits) override; + bool UpdateStarted(std::vector<SBListChunkRanges>* lists) override; void InsertChunks( const std::string& list_name, @@ -696,6 +714,8 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // identical to browsing lists). // - |module_whitelist_store_|: For module whitelist. This list only // contains 256 bit hashes. + // - |resource_blacklist_store_|: For script resource list (format identical + // to browsing lists). // // The stores themselves will be modified throughout the existence of this // database, but shouldn't ever be swapped out (hence the const scoped_ptr -- @@ -711,6 +731,7 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { const scoped_ptr<SafeBrowsingStore> ip_blacklist_store_; const scoped_ptr<SafeBrowsingStore> unwanted_software_store_; const scoped_ptr<SafeBrowsingStore> module_whitelist_store_; + const scoped_ptr<SafeBrowsingStore> resource_blacklist_store_; // Used to schedule resetting the database because of corruption. This factory // and the WeakPtrs it issues should only be used on the database's main diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc index b405ad1..6d27a1f 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc @@ -22,6 +22,7 @@ #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" #include "crypto/sha2.h" #include "net/base/ip_address_number.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" #include "url/gurl.h" @@ -282,11 +283,13 @@ class SafeBrowsingDatabaseTest : public PlatformTest { new SafeBrowsingStoreFile(task_runner_); SafeBrowsingStoreFile* module_whitelist_store = new SafeBrowsingStoreFile(task_runner_); + SafeBrowsingStoreFile* resource_blacklist_store = + new SafeBrowsingStoreFile(task_runner_); database_.reset(new SafeBrowsingDatabaseNew( task_runner_, browse_store, download_store, csd_whitelist_store, download_whitelist_store, inclusion_whitelist_store, extension_blacklist_store, ip_blacklist_store, unwanted_software_store, - module_whitelist_store)); + module_whitelist_store, resource_blacklist_store)); database_->Init(database_filename_); } @@ -297,6 +300,16 @@ class SafeBrowsingDatabaseTest : public PlatformTest { return database_->ContainsDownloadUrlPrefixes(prefixes, prefix_hits); } + bool ContainsResourceUrl(const GURL& url, + std::vector<SBPrefix>* prefix_hits) { + std::vector<SBFullHash> full_hashes; + UrlToFullHashes(url, false, &full_hashes); + std::vector<SBPrefix> prefixes(full_hashes.size()); + for (size_t i = 0; i < full_hashes.size(); ++i) + prefixes[i] = full_hashes[i].prefix; + return database_->ContainsResourceUrlPrefixes(prefixes, prefix_hits); + } + void GetListsInfo(std::vector<SBListChunkRanges>* lists) { lists->clear(); ASSERT_TRUE(database_->UpdateStarted(lists)); @@ -446,10 +459,14 @@ TEST_F(SafeBrowsingDatabaseTest, ListNames) { chunks.push_back(AddChunkPrefixValue(12, "chrome.dll")); database_->InsertChunks(kModuleWhitelist, chunks); + chunks.clear(); + chunks.push_back(AddChunkPrefixValue(13, "foo.com/script.js")); + database_->InsertChunks(kResourceBlacklist, chunks); + database_->UpdateFinished(true); GetListsInfo(&lists); - ASSERT_EQ(10U, lists.size()); + ASSERT_EQ(11U, lists.size()); EXPECT_EQ(kMalwareList, lists[0].name); EXPECT_EQ("1", lists[0].adds); EXPECT_TRUE(lists[0].subs.empty()); @@ -480,6 +497,9 @@ TEST_F(SafeBrowsingDatabaseTest, ListNames) { EXPECT_EQ(kModuleWhitelist, lists[9].name); EXPECT_EQ("12", lists[9].adds); EXPECT_TRUE(lists[9].subs.empty()); + EXPECT_EQ(kResourceBlacklist, lists[10].name); + EXPECT_EQ("13", lists[10].adds); + EXPECT_TRUE(lists[10].subs.empty()); database_.reset(); } @@ -1162,7 +1182,8 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) { base::MessageLoop loop; SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile(task_runner_); database_.reset(new SafeBrowsingDatabaseNew( - task_runner_, store, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + task_runner_, store, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL)); database_->Init(database_filename_); // This will cause an empty database to be created. @@ -1303,6 +1324,45 @@ TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrlPrefixes) { database_.reset(); } +TEST_F(SafeBrowsingDatabaseTest, ContainsResourceUrlPrefixes) { + const char* kBadUrl1 = "bad1.com/"; + const char* kBadUrl2 = "bad2.com/script.js"; + const SBPrefix kBadPrefix1 = SBPrefixForString(kBadUrl1); + const SBPrefix kBadPrefix2 = SBPrefixForString(kBadUrl2); + + // Populate database + std::vector<scoped_ptr<SBChunkData>> chunks; + chunks.push_back(AddChunkPrefix2Value(1, kBadUrl1, kBadUrl2)); + + std::vector<SBListChunkRanges> lists; + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(kResourceBlacklist, chunks); + database_->UpdateFinished(true); + + struct { + std::string url; + bool found_in_db; + std::vector<SBPrefix> prefix_hits; + } test_cases[] = { + {std::string("http://") + kBadUrl1, true, {kBadPrefix1}}, + {std::string("https://") + kBadUrl2, true, {kBadPrefix2}}, + {std::string("ftp://") + kBadUrl1, true, {kBadPrefix1}}, + {std::string("http://") + kBadUrl1 + "a/b/?arg=value", true, {kBadPrefix1}}, + {std::string("http://") + kBadUrl1 + "script.js", true, {kBadPrefix1}}, + {std::string("http://www.domain.") + kBadUrl2, true, {kBadPrefix2}}, + {"http://www.good.org/script.js", false, std::vector<SBPrefix>()}, + }; + + std::vector<SBPrefix> prefix_hits; + for (const auto& test_case : test_cases) { + EXPECT_EQ(test_case.found_in_db, + ContainsResourceUrl(GURL(test_case.url), &prefix_hits)); + EXPECT_THAT(prefix_hits, testing::ElementsAreArray(test_case.prefix_hits)); + } + + database_.reset(); +} + // Checks that the whitelists are handled properly. TEST_F(SafeBrowsingDatabaseTest, Whitelists) { struct TestCase { @@ -1343,7 +1403,7 @@ TEST_F(SafeBrowsingDatabaseTest, Whitelists) { // If the whitelist is disabled everything should match the whitelist. database_.reset(new SafeBrowsingDatabaseNew( task_runner_, new SafeBrowsingStoreFile(task_runner_), NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL)); + NULL, NULL, NULL, NULL, NULL, NULL)); database_->Init(database_filename_); for (const auto& test_case : kTestCases) { SCOPED_TRACE(std::string("Tested list at fault => ") + diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index 73f6655..8807d14 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc @@ -263,6 +263,13 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { bool ContainsMalwareIP(const std::string& ip_address) override { return true; } + bool ContainsResourceUrlPrefixes( + const std::vector<SBPrefix>& prefixes, + std::vector<SBPrefix>* prefix_hits) override { + prefix_hits->clear(); + return ContainsUrlPrefixes(RESOURCEBLACKLIST, RESOURCEBLACKLIST, + prefixes, prefix_hits); + } bool UpdateStarted(std::vector<SBListChunkRanges>* lists) override { ADD_FAILURE() << "Not implemented."; return false; @@ -1141,6 +1148,8 @@ class TestSBClient : public base::RefCountedThreadSafe<TestSBClient>, SBThreatType GetThreatType() const { return threat_type_; } + std::string GetThreatHash() const { return threat_hash_; } + void CheckDownloadUrl(const std::vector<GURL>& url_chain) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -1155,6 +1164,13 @@ class TestSBClient : public base::RefCountedThreadSafe<TestSBClient>, content::RunMessageLoop(); // Will stop in OnCheckBrowseUrlResult. } + void CheckResourceUrl(const GURL& url) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&TestSBClient::CheckResourceUrlOnIOThread, this, url)); + content::RunMessageLoop(); // Will stop in OnCheckResourceUrlResult. + } + private: friend class base::RefCountedThreadSafe<TestSBClient>; ~TestSBClient() override {} @@ -1182,6 +1198,16 @@ class TestSBClient : public base::RefCountedThreadSafe<TestSBClient>, } } + void CheckResourceUrlOnIOThread(const GURL& url) { + bool synchronous_safe_signal = + safe_browsing_service_->database_manager()->CheckResourceUrl(url, this); + if (synchronous_safe_signal) { + threat_type_ = SB_THREAT_TYPE_SAFE; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TestSBClient::CheckDone, this)); + } + } + // Called when the result of checking a download URL is known. void OnCheckDownloadUrlResult(const std::vector<GURL>& /* url_chain */, SBThreatType threat_type) override { @@ -1199,9 +1225,20 @@ class TestSBClient : public base::RefCountedThreadSafe<TestSBClient>, base::Bind(&TestSBClient::CheckDone, this)); } + // Called when the result of checking a resource URL is known. + void OnCheckResourceUrlResult(const GURL& /* url */, + SBThreatType threat_type, + const std::string& threat_hash) override { + threat_type_ = threat_type; + threat_hash_ = threat_hash; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TestSBClient::CheckDone, this)); + } + void CheckDone() { base::MessageLoopForUI::current()->QuitWhenIdle(); } SBThreatType threat_type_; + std::string threat_hash_; SafeBrowsingService* safe_browsing_service_; DISALLOW_COPY_AND_ASSIGN(TestSBClient); @@ -1337,6 +1374,47 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrlRedirects) { EXPECT_EQ(SB_THREAT_TYPE_BINARY_MALWARE_URL, client->GetThreatType()); } +IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckResourceUrl) { + const char* kBlacklistResource = "/blacklisted/script.js"; + GURL blacklist_resource = embedded_test_server()->GetURL(kBlacklistResource); + std::string blacklist_resource_hash; + const char* kMaliciousResource = "/malware/script.js"; + GURL malware_resource = embedded_test_server()->GetURL(kMaliciousResource); + std::string malware_resource_hash; + + { + SBFullHashResult full_hash; + GenUrlFullhashResult(blacklist_resource, RESOURCEBLACKLIST, &full_hash); + SetupResponseForUrl(blacklist_resource, full_hash); + blacklist_resource_hash = std::string(full_hash.hash.full_hash, + full_hash.hash.full_hash + 32); + } + { + SBFullHashResult full_hash; + GenUrlFullhashResult(malware_resource, MALWARE, &full_hash); + SetupResponseForUrl(malware_resource, full_hash); + full_hash.list_id = RESOURCEBLACKLIST; + SetupResponseForUrl(malware_resource, full_hash); + malware_resource_hash = std::string(full_hash.hash.full_hash, + full_hash.hash.full_hash + 32); + } + + scoped_refptr<TestSBClient> client(new TestSBClient); + client->CheckResourceUrl(blacklist_resource); + EXPECT_EQ(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, client->GetThreatType()); + EXPECT_EQ(blacklist_resource_hash, client->GetThreatHash()); + + // Since we're checking a resource url, we should receive result that it's + // a blacklisted resource, not a malware. + client = new TestSBClient; + client->CheckResourceUrl(malware_resource); + EXPECT_EQ(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, client->GetThreatType()); + EXPECT_EQ(malware_resource_hash, client->GetThreatHash()); + + client->CheckResourceUrl(embedded_test_server()->GetURL(kEmptyPage)); + EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType()); +} + #if defined(OS_WIN) // http://crbug.com/396409 #define MAYBE_CheckDownloadUrlTimedOut DISABLED_CheckDownloadUrlTimedOut diff --git a/components/safe_browsing_db/database_manager.h b/components/safe_browsing_db/database_manager.h index 8167b3a..fd8a276 100644 --- a/components/safe_browsing_db/database_manager.h +++ b/components/safe_browsing_db/database_manager.h @@ -49,6 +49,11 @@ class SafeBrowsingDatabaseManager // Called when the result of checking the API blacklist is known. virtual void OnCheckApiBlacklistUrlResult(const GURL& url, const std::string& metadata) {} + + // Called when the result of checking the resource blacklist is known. + virtual void OnCheckResourceUrlResult(const GURL& url, + SBThreatType threat_type, + const std::string& threat_hash) {} }; @@ -90,6 +95,11 @@ class SafeBrowsingDatabaseManager virtual bool CheckExtensionIDs(const std::set<std::string>& extension_ids, Client* client) = 0; + // Check if |url| is in the resources blacklist. Returns true if not, false + // if further checks need to be made in which case the result will be passed + // to callback in |client|. + virtual bool CheckResourceUrl(const GURL& url, Client* client) = 0; + // Check if the |url| matches any of the full-length hashes from the client- // side phishing detection whitelist. Returns true if there was a match and // false otherwise. To make sure we are conservative we will return true if diff --git a/components/safe_browsing_db/remote_database_manager.cc b/components/safe_browsing_db/remote_database_manager.cc index 8b1c480..e699b30 100644 --- a/components/safe_browsing_db/remote_database_manager.cc +++ b/components/safe_browsing_db/remote_database_manager.cc @@ -213,6 +213,12 @@ bool RemoteSafeBrowsingDatabaseManager::MatchModuleWhitelistString( return true; } +bool RemoteSafeBrowsingDatabaseManager::CheckResourceUrl(const GURL& url, + Client* client) { + NOTREACHED(); + return true; +} + bool RemoteSafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() { NOTREACHED(); return true; diff --git a/components/safe_browsing_db/remote_database_manager.h b/components/safe_browsing_db/remote_database_manager.h index 89c71f5..6b2c764 100644 --- a/components/safe_browsing_db/remote_database_manager.h +++ b/components/safe_browsing_db/remote_database_manager.h @@ -55,6 +55,7 @@ class RemoteSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager { bool MatchDownloadWhitelistString(const std::string& str) override; bool MatchInclusionWhitelistUrl(const GURL& url) override; bool MatchModuleWhitelistString(const std::string& str) override; + bool CheckResourceUrl(const GURL& url, Client* client) override; bool IsMalwareKillSwitchOn() override; bool IsCsdWhitelistKillSwitchOn() override; diff --git a/components/safe_browsing_db/test_database_manager.cc b/components/safe_browsing_db/test_database_manager.cc index 454c358..d24cb6a 100644 --- a/components/safe_browsing_db/test_database_manager.cc +++ b/components/safe_browsing_db/test_database_manager.cc @@ -64,6 +64,12 @@ bool TestSafeBrowsingDatabaseManager::CheckExtensionIDs( return true; } +bool TestSafeBrowsingDatabaseManager::CheckResourceUrl(const GURL& url, + Client* client) { + NOTIMPLEMENTED(); + return true; +} + bool TestSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { NOTIMPLEMENTED(); return true; diff --git a/components/safe_browsing_db/test_database_manager.h b/components/safe_browsing_db/test_database_manager.h index aa25c51..2b01c20 100644 --- a/components/safe_browsing_db/test_database_manager.h +++ b/components/safe_browsing_db/test_database_manager.h @@ -31,6 +31,7 @@ class TestSafeBrowsingDatabaseManager Client* client) override; bool CheckExtensionIDs(const std::set<std::string>& extension_ids, Client* client) override; + bool CheckResourceUrl(const GURL& url, Client* client) override; bool MatchCsdWhitelistUrl(const GURL& url) override; bool MatchMalwareIP(const std::string& ip_address) override; bool MatchDownloadWhitelistUrl(const GURL& url) override; diff --git a/components/safe_browsing_db/util.cc b/components/safe_browsing_db/util.cc index 7289a0f..2eaf630 100644 --- a/components/safe_browsing_db/util.cc +++ b/components/safe_browsing_db/util.cc @@ -53,11 +53,12 @@ const char kIPBlacklist[] = "goog-badip-digest256"; const char kUnwantedUrlList[] = "goog-unwanted-shavar"; const char kInclusionWhitelist[] = "goog-csdinclusionwhite-sha256"; const char kModuleWhitelist[] = "goog-whitemodule-digest256"; +const char kResourceBlacklist[] = "goog-badresource-shavar"; -const char* kAllLists[10] = { +const char* kAllLists[11] = { kMalwareList, kPhishingList, kBinUrlList, kCsdWhiteList, kDownloadWhiteList, kExtensionBlacklist, kIPBlacklist, kUnwantedUrlList, - kInclusionWhitelist, kModuleWhitelist, + kInclusionWhitelist, kModuleWhitelist, kResourceBlacklist, }; ListType GetListId(const base::StringPiece& name) { @@ -82,6 +83,8 @@ ListType GetListId(const base::StringPiece& name) { id = INCLUSIONWHITELIST; } else if (name == kModuleWhitelist) { id = MODULEWHITELIST; + } else if (name == kResourceBlacklist) { + id = RESOURCEBLACKLIST; } else { id = INVALID; } @@ -119,6 +122,8 @@ bool GetListName(ListType list_id, std::string* list) { break; case MODULEWHITELIST: *list = kModuleWhitelist; + case RESOURCEBLACKLIST: + *list = kResourceBlacklist; break; default: return false; diff --git a/components/safe_browsing_db/util.h b/components/safe_browsing_db/util.h index d350e10..643e0a4 100644 --- a/components/safe_browsing_db/util.h +++ b/components/safe_browsing_db/util.h @@ -47,6 +47,10 @@ enum SBThreatType { // Url detected by the client-side malware IP list. This IP list is part // of the client side detection model. SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL, + + // Url leads to a blacklisted resource script. Note that no warnings should be + // shown on this threat type, but an incident report might be sent. + SB_THREAT_TYPE_BLACKLISTED_RESOURCE, }; @@ -102,8 +106,10 @@ extern const char kUnwantedUrlList[]; extern const char kInclusionWhitelist[]; // SafeBrowsing module whitelist list name. extern const char kModuleWhitelist[]; -// This array must contain all Safe Browsing lists. -extern const char* kAllLists[10]; +// Blacklisted resource URLs list name. +extern const char kResourceBlacklist[]; +/// This array must contain all Safe Browsing lists. +extern const char* kAllLists[11]; enum ListType { INVALID = -1, @@ -129,6 +135,8 @@ enum ListType { // See above comment. Leave 17 available. MODULEWHITELIST = 18, // See above comment. Leave 19 available. + RESOURCEBLACKLIST = 20, + // See above comment. Leave 21 available. }; inline bool SBFullHashEqual(const SBFullHash& a, const SBFullHash& b) { diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 9ddd445..f5c8104 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -77553,6 +77553,9 @@ To add a new entry, add it with any value and run test to compute valid value. <int value="32" label="FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ"/> <int value="33" label="FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE"/> <int value="34" label="FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE"/> + <int value="35" label="FAILURE_RESOURCE_BLACKLIST_UPDATE_BEGIN"/> + <int value="36" label="FAILURE_RESOURCE_BLACKLIST_UPDATE_FINISH"/> + <int value="37" label="FAILURE_RESOURCE_BLACKLIST_DELETE"/> </enum> <enum name="SB2DownloadChecks" type="int"> @@ -87337,6 +87340,7 @@ To add a new entry, add it with any value and run test to compute valid value. </suffix> <suffix name="IPBlacklist" label="IPBlacklist"/> <suffix name="UnwantedSoftware" label="UnwantedSoftware"/> + <suffix name="ResourceBlacklist" label="ResourceBlacklist"/> <affected-histogram name="SB2.DatabaseSizeKilobytes"/> <affected-histogram name="SB2.PrefixSetSizeKilobytes"/> </histogram_suffixes> |