Chromium Code Reviews| Index: chrome/browser/safe_browsing/safe_browsing_database.cc |
| diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc |
| index e035e22926a701f73b6e8715e6a9677ec87d15e2..c844ead7b9070508780ab19430f89a075d79eba9 100644 |
| --- a/chrome/browser/safe_browsing/safe_browsing_database.cc |
| +++ b/chrome/browser/safe_browsing/safe_browsing_database.cc |
| @@ -33,6 +33,9 @@ const FilePath::CharType kDownloadDBFile[] = FILE_PATH_LITERAL(" Download"); |
| // Filename suffix for client-side phishing detection whitelist store. |
| const FilePath::CharType kCsdWhitelistDBFile[] = |
| FILE_PATH_LITERAL(" Csd Whitelist"); |
| +// Filename suffix for the download whitelist store. |
| +const FilePath::CharType kDownloadWhitelistDBFile[] = |
| + FILE_PATH_LITERAL(" Download Whitelist"); |
| // Filename suffix for browse store. |
| // TODO(lzheng): change to a better name when we change the file format. |
| const FilePath::CharType kBrowseDBFile[] = FILE_PATH_LITERAL(" Bloom"); |
| @@ -40,15 +43,15 @@ const FilePath::CharType kBrowseDBFile[] = FILE_PATH_LITERAL(" Bloom"); |
| // The maximum staleness for a cached entry. |
| const int kMaxStalenessMinutes = 45; |
| -// Maximum number of entries we allow in the client-side phishing detection |
| -// whitelist. If the whitelist on disk contains more entries then |
| -// ContainsCsdWhitelistedUrl will always return true. |
| -const size_t kMaxCsdWhitelistSize = 5000; |
| +// Maximum number of entries we allow in any of the two whitelists. |
|
Brian Ryner
2011/09/12 21:45:18
May want to remove "two" so that this comment does
noelutz
2011/09/12 22:09:30
Done.
|
| +// If a whitelist on disk contains more entries then all lookups to |
| +// the whitelist will be considered a match. |
| +const size_t kMaxWhitelistSize = 5000; |
| -// If the hash of this exact expression is on the csd whitelist then |
| -// ContainsCsdWhitelistedUrl will always return true. |
| -const char kCsdKillSwitchUrl[] = |
| - "sb-ssl.google.com/safebrowsing/csd/killswitch"; |
| +// If the hash of this exact expression is on a whitelist then all |
| +// lookups to this whitelist will be considered a match. |
| +const char kWhitelistKillSwitchUrl[] = |
| + "sb-ssl.google.com/safebrowsing/csd/killswitch"; // Don't change this! |
| // To save space, the incoming |chunk_id| and |list_id| are combined |
| // into an |encoded_chunk_id| for storage by shifting the |list_id| |
| @@ -71,7 +74,7 @@ int EncodeChunkId(const int chunk, const int list_id) { |
| // |include_whitelist_hashes| is true we will generate additional path-prefixes |
| // to match against the csd whitelist. E.g., if the path-prefix /foo is on the |
| // whitelist it should also match /foo/bar which is not the case for all the |
| -// other lists. |
| +// other lists. We'll also always add a pattern for the empty path. |
| // TODO(shess): This function is almost the same as |
| // |CompareFullHashes()| in safe_browsing_util.cc, except that code |
| // does an early exit on match. Since match should be the infrequent |
| @@ -91,8 +94,10 @@ void BrowseFullHashesToCheck(const GURL& url, |
| safe_browsing_util::GeneratePathsToCheck(url, &paths); |
| for (size_t i = 0; i < hosts.size(); ++i) { |
| + bool has_empty_path = false; |
|
Brian Ryner
2011/09/12 21:45:18
I'm not sure I understand the extra logic you're a
noelutz
2011/09/12 22:09:30
Duh! I just realized that I misunderstood Generat
|
| for (size_t j = 0; j < paths.size(); ++j) { |
| const std::string& path = paths[j]; |
| + has_empty_path |= (path == "/"); |
| SBFullHash full_hash; |
| crypto::SHA256HashString(hosts[i] + path, &full_hash, |
| sizeof(full_hash)); |
| @@ -109,6 +114,13 @@ void BrowseFullHashesToCheck(const GURL& url, |
| full_hashes->push_back(full_hash); |
| } |
| } |
| + // Add the host with an empty path if we haven't already added |
| + // this expression to the full_hashes vector. |
| + if (!has_empty_path && include_whitelist_hashes) { |
| + SBFullHash full_hash; |
| + crypto::SHA256HashString(hosts[i] + "/", &full_hash, sizeof(full_hash)); |
| + full_hashes->push_back(full_hash); |
| + } |
| } |
| } |
| @@ -395,11 +407,13 @@ class SafeBrowsingDatabaseFactoryImpl : public SafeBrowsingDatabaseFactory { |
| public: |
| virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase( |
| bool enable_download_protection, |
| - bool enable_client_side_whitelist) { |
| + bool enable_client_side_whitelist, |
| + bool enable_download_whitelist) { |
| return new SafeBrowsingDatabaseNew( |
| new SafeBrowsingStoreFile, |
| enable_download_protection ? new SafeBrowsingStoreFile : NULL, |
| - enable_client_side_whitelist ? new SafeBrowsingStoreFile : NULL); |
| + enable_client_side_whitelist ? new SafeBrowsingStoreFile : NULL, |
| + enable_download_whitelist ? new SafeBrowsingStoreFile : NULL); |
| } |
| SafeBrowsingDatabaseFactoryImpl() { } |
| @@ -418,11 +432,13 @@ SafeBrowsingDatabaseFactory* SafeBrowsingDatabase::factory_ = NULL; |
| // callers just construct things directly. |
| SafeBrowsingDatabase* SafeBrowsingDatabase::Create( |
| bool enable_download_protection, |
| - bool enable_client_side_whitelist) { |
| + bool enable_client_side_whitelist, |
| + bool enable_download_whitelist) { |
| if (!factory_) |
| factory_ = new SafeBrowsingDatabaseFactoryImpl(); |
| return factory_->CreateSafeBrowsingDatabase(enable_download_protection, |
| - enable_client_side_whitelist); |
| + enable_client_side_whitelist, |
| + enable_download_whitelist); |
| } |
| SafeBrowsingDatabase::~SafeBrowsingDatabase() { |
| @@ -452,6 +468,12 @@ FilePath SafeBrowsingDatabase::CsdWhitelistDBFilename( |
| return FilePath(db_filename.value() + kCsdWhitelistDBFile); |
| } |
| +// static |
| +FilePath SafeBrowsingDatabase::DownloadWhitelistDBFilename( |
| + const FilePath& db_filename) { |
| + return FilePath(db_filename.value() + kDownloadWhitelistDBFile); |
| +} |
| + |
| SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { |
| if (list_id == safe_browsing_util::PHISH || |
| list_id == safe_browsing_util::MALWARE) { |
| @@ -461,6 +483,8 @@ SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { |
| return download_store_.get(); |
| } else if (list_id == safe_browsing_util::CSDWHITELIST) { |
| return csd_whitelist_store_.get(); |
| + } else if (list_id == safe_browsing_util::DOWNLOADWHITELIST) { |
| + return download_whitelist_store_.get(); |
| } |
| return NULL; |
| } |
| @@ -476,20 +500,24 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew() |
| browse_store_(new SafeBrowsingStoreFile), |
| download_store_(NULL), |
| csd_whitelist_store_(NULL), |
| + download_whitelist_store_(NULL), |
| ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)) { |
| DCHECK(browse_store_.get()); |
| DCHECK(!download_store_.get()); |
| DCHECK(!csd_whitelist_store_.get()); |
| + DCHECK(!download_whitelist_store_.get()); |
| } |
| SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew( |
| SafeBrowsingStore* browse_store, |
| SafeBrowsingStore* download_store, |
| - SafeBrowsingStore* csd_whitelist_store) |
| + SafeBrowsingStore* csd_whitelist_store, |
| + SafeBrowsingStore* download_whitelist_store) |
| : creation_loop_(MessageLoop::current()), |
| browse_store_(browse_store), |
| download_store_(download_store), |
| csd_whitelist_store_(csd_whitelist_store), |
| + download_whitelist_store_(download_whitelist_store), |
| ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)), |
| corruption_detected_(false) { |
| DCHECK(browse_store_.get()); |
| @@ -505,6 +533,7 @@ void SafeBrowsingDatabaseNew::Init(const FilePath& filename_base) { |
| DCHECK(browse_filename_.empty()); |
| DCHECK(download_filename_.empty()); |
| DCHECK(csd_whitelist_filename_.empty()); |
| + DCHECK(download_whitelist_filename_.empty()); |
| browse_filename_ = BrowseDBFilename(filename_base); |
| bloom_filter_filename_ = BloomFilterForFilename(browse_filename_); |
| @@ -541,12 +570,29 @@ void SafeBrowsingDatabaseNew::Init(const FilePath& filename_base) { |
| DVLOG(1) << "Init csd whitelist store: " << csd_whitelist_filename_.value(); |
| std::vector<SBAddFullHash> full_hashes; |
| if (csd_whitelist_store_->GetAddFullHashes(&full_hashes)) { |
| - LoadCsdWhitelist(full_hashes); |
| + LoadWhitelist(full_hashes, &csd_whitelist_); |
| } else { |
| - CsdWhitelistAllUrls(); |
| + WhitelistEverything(&csd_whitelist_); |
| } |
| } else { |
| - CsdWhitelistAllUrls(); // Just to be safe. |
| + WhitelistEverything(&csd_whitelist_); // Just to be safe. |
| + } |
| + |
| + if (download_whitelist_store_.get()) { |
| + download_whitelist_filename_ = DownloadWhitelistDBFilename(filename_base); |
| + download_whitelist_store_->Init( |
| + download_whitelist_filename_, |
| + NewCallback(this, &SafeBrowsingDatabaseNew::HandleCorruptDatabase)); |
| + DVLOG(1) << "Init download whitelist store: " |
| + << download_whitelist_filename_.value(); |
| + std::vector<SBAddFullHash> full_hashes; |
| + if (download_whitelist_store_->GetAddFullHashes(&full_hashes)) { |
| + LoadWhitelist(full_hashes, &download_whitelist_); |
| + } else { |
| + WhitelistEverything(&download_whitelist_); |
|
mattm
2011/09/10 01:55:33
Hm, does this mean that if the whitelist file does
noelutz
2011/09/10 02:30:56
Exactly. That's a precaution to protect the user'
|
| + } |
| + } else { |
| + WhitelistEverything(&download_whitelist_); // Just to be safe. |
| } |
| } |
| @@ -573,7 +619,8 @@ bool SafeBrowsingDatabaseNew::ResetDatabase() { |
| prefix_set_.reset(new safe_browsing::PrefixSet(std::vector<SBPrefix>())); |
| } |
| // Wants to acquire the lock itself. |
| - CsdWhitelistAllUrls(); |
| + WhitelistEverything(&csd_whitelist_); |
| + WhitelistEverything(&download_whitelist_); |
| return true; |
| } |
| @@ -713,15 +760,35 @@ bool SafeBrowsingDatabaseNew::ContainsCsdWhitelistedUrl(const GURL& url) { |
| // This method is theoretically thread-safe but we expect all calls to |
| // originate from the IO thread. |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - base::AutoLock l(lookup_lock_); |
| - if (csd_whitelist_all_urls_) |
| - return true; |
| + std::vector<SBFullHash> full_hashes; |
| + BrowseFullHashesToCheck(url, true, &full_hashes); |
| + return ContainsWhitelistedHashes(csd_whitelist_, full_hashes); |
| +} |
| +bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedUrl(const GURL& url) { |
| std::vector<SBFullHash> full_hashes; |
| BrowseFullHashesToCheck(url, true, &full_hashes); |
| - for (std::vector<SBFullHash>::const_iterator it = full_hashes.begin(); |
| - it != full_hashes.end(); ++it) { |
| - if (std::binary_search(csd_whitelist_.begin(), csd_whitelist_.end(), *it)) |
| + return ContainsWhitelistedHashes(download_whitelist_, full_hashes); |
| +} |
| + |
| +bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedString( |
| + const std::string& str) { |
| + SBFullHash hash; |
| + crypto::SHA256HashString(str, &hash, sizeof(hash)); |
| + std::vector<SBFullHash> hashes; |
| + hashes.push_back(hash); |
| + return ContainsWhitelistedHashes(download_whitelist_, hashes); |
| +} |
| + |
| +bool SafeBrowsingDatabaseNew::ContainsWhitelistedHashes( |
| + const SBWhitelist& whitelist, |
| + const std::vector<SBFullHash>& hashes) { |
| + base::AutoLock l(lookup_lock_); |
| + if (whitelist.second) |
| + return true; |
| + for (std::vector<SBFullHash>::const_iterator it = hashes.begin(); |
| + it != hashes.end(); ++it) { |
| + if (std::binary_search(whitelist.first.begin(), whitelist.first.end(), *it)) |
| return true; |
| } |
| return false; |
| @@ -979,7 +1046,14 @@ bool SafeBrowsingDatabaseNew::UpdateStarted( |
| } |
| if (csd_whitelist_store_.get() && !csd_whitelist_store_->BeginUpdate()) { |
| - RecordFailure(FAILURE_CSD_WHITELIST_DATABASE_UPDATE_BEGIN); |
| + RecordFailure(FAILURE_WHITELIST_DATABASE_UPDATE_BEGIN); |
| + HandleCorruptDatabase(); |
| + return false; |
| + } |
| + |
| + if (download_whitelist_store_.get() && |
| + !download_whitelist_store_->BeginUpdate()) { |
| + RecordFailure(FAILURE_WHITELIST_DATABASE_UPDATE_BEGIN); |
| HandleCorruptDatabase(); |
| return false; |
| } |
| @@ -1003,6 +1077,14 @@ bool SafeBrowsingDatabaseNew::UpdateStarted( |
| csd_whitelist_listnames, lists); |
| } |
| + if (download_whitelist_store_.get()) { |
| + std::vector<std::string> download_whitelist_listnames; |
| + download_whitelist_listnames.push_back( |
| + safe_browsing_util::kDownloadWhiteList); |
| + UpdateChunkRanges(download_whitelist_store_.get(), |
| + download_whitelist_listnames, lists); |
| + } |
| + |
| corruption_detected_ = false; |
| change_detected_ = false; |
| return true; |
| @@ -1025,6 +1107,8 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { |
| download_store_->CancelUpdate(); |
| if (csd_whitelist_store_.get()) |
| csd_whitelist_store_->CancelUpdate(); |
| + if (download_whitelist_store_.get()) |
| + download_whitelist_store_->CancelUpdate(); |
| return; |
| } |
| @@ -1032,39 +1116,45 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { |
| UpdateDownloadStore(); |
| // for browsing |
| UpdateBrowseStore(); |
| - // for csd whitelist |
| - UpdateCsdWhitelistStore(); |
| + // for csd and download whitelists. |
| + UpdateWhitelistStore(csd_whitelist_filename_, |
| + csd_whitelist_store_.get(), |
| + &csd_whitelist_); |
| + UpdateWhitelistStore(download_whitelist_filename_, |
| + download_whitelist_store_.get(), |
| + &download_whitelist_); |
| } |
| -void SafeBrowsingDatabaseNew::UpdateCsdWhitelistStore() { |
| - if (!csd_whitelist_store_.get()) |
| +void SafeBrowsingDatabaseNew::UpdateWhitelistStore( |
| + const FilePath& store_filename, |
| + SafeBrowsingStore* store, |
| + SBWhitelist* whitelist) { |
| + if (!store) |
| return; |
| - // For the csd whitelist, we don't cache and save full hashes since all |
| + // For the whitelists, we don't cache and save full hashes since all |
| // hashes are already full. |
| std::vector<SBAddFullHash> empty_add_hashes; |
| - // Not needed for the csd whitelist. |
| + // Not needed for the whitelists. |
| std::set<SBPrefix> empty_miss_cache; |
| // Note: prefixes will not be empty. The current data store implementation |
| // stores all full-length hashes as both full and prefix hashes. |
| std::vector<SBAddPrefix> prefixes; |
| std::vector<SBAddFullHash> full_hashes; |
| - if (!csd_whitelist_store_->FinishUpdate(empty_add_hashes, |
| - empty_miss_cache, |
| - &prefixes, |
| - &full_hashes)) { |
| - RecordFailure(FAILURE_CSD_WHITELIST_DATABASE_UPDATE_FINISH); |
| - CsdWhitelistAllUrls(); |
| + if (!store->FinishUpdate(empty_add_hashes, empty_miss_cache, &prefixes, |
| + &full_hashes)) { |
| + RecordFailure(FAILURE_WHITELIST_DATABASE_UPDATE_FINISH); |
| + WhitelistEverything(whitelist); |
| return; |
| } |
| #if defined(OS_MACOSX) |
| - base::mac::SetFileBackupExclusion(csd_whitelist_filename_); |
| + base::mac::SetFileBackupExclusion(store_filename); |
| #endif |
| - LoadCsdWhitelist(full_hashes); |
| + LoadWhitelist(full_hashes, whitelist); |
| } |
| void SafeBrowsingDatabaseNew::UpdateDownloadStore() { |
| @@ -1279,10 +1369,15 @@ bool SafeBrowsingDatabaseNew::Delete() { |
| if (!r3) |
| RecordFailure(FAILURE_DATABASE_STORE_DELETE); |
| - const bool r4 = file_util::Delete(bloom_filter_filename_, false); |
| + const bool r4 = download_whitelist_store_.get() ? |
| + download_whitelist_store_->Delete() : true; |
| if (!r4) |
| + RecordFailure(FAILURE_DATABASE_STORE_DELETE); |
| + |
| + const bool r5 = file_util::Delete(bloom_filter_filename_, false); |
| + if (!r5) |
| RecordFailure(FAILURE_DATABASE_FILTER_DELETE); |
| - return r1 && r2 && r3 && r4; |
| + return r1 && r2 && r3 && r4 && r5; |
| } |
| void SafeBrowsingDatabaseNew::WriteBloomFilter() { |
| @@ -1304,37 +1399,38 @@ void SafeBrowsingDatabaseNew::WriteBloomFilter() { |
| #endif |
| } |
| -void SafeBrowsingDatabaseNew::CsdWhitelistAllUrls() { |
| +void SafeBrowsingDatabaseNew::WhitelistEverything(SBWhitelist* whitelist) { |
| base::AutoLock locked(lookup_lock_); |
| - csd_whitelist_all_urls_ = true; |
| - csd_whitelist_.clear(); |
| + whitelist->second = true; |
| + whitelist->first.clear(); |
| } |
| -void SafeBrowsingDatabaseNew::LoadCsdWhitelist( |
| - const std::vector<SBAddFullHash>& full_hashes) { |
| +void SafeBrowsingDatabaseNew::LoadWhitelist( |
| + const std::vector<SBAddFullHash>& full_hashes, |
| + SBWhitelist* whitelist) { |
| DCHECK_EQ(creation_loop_, MessageLoop::current()); |
| - if (full_hashes.size() > kMaxCsdWhitelistSize) { |
| - CsdWhitelistAllUrls(); |
| + if (full_hashes.size() > kMaxWhitelistSize) { |
| + WhitelistEverything(whitelist); |
| return; |
| } |
| - std::vector<SBFullHash> new_csd_whitelist; |
| + std::vector<SBFullHash> new_whitelist; |
| for (std::vector<SBAddFullHash>::const_iterator it = full_hashes.begin(); |
| it != full_hashes.end(); ++it) { |
| - new_csd_whitelist.push_back(it->full_hash); |
| + new_whitelist.push_back(it->full_hash); |
| } |
| - std::sort(new_csd_whitelist.begin(), new_csd_whitelist.end()); |
| + std::sort(new_whitelist.begin(), new_whitelist.end()); |
| SBFullHash kill_switch; |
| - crypto::SHA256HashString(kCsdKillSwitchUrl, &kill_switch, |
| + crypto::SHA256HashString(kWhitelistKillSwitchUrl, &kill_switch, |
| sizeof(kill_switch)); |
| - if (std::binary_search(new_csd_whitelist.begin(), new_csd_whitelist.end(), |
| + if (std::binary_search(new_whitelist.begin(), new_whitelist.end(), |
| kill_switch)) { |
| // The kill switch is whitelisted hence we whitelist all URLs. |
| - CsdWhitelistAllUrls(); |
| + WhitelistEverything(whitelist); |
| } else { |
| base::AutoLock locked(lookup_lock_); |
| - csd_whitelist_all_urls_ = false; |
| - csd_whitelist_.swap(new_csd_whitelist); |
| + whitelist->second = false; |
| + whitelist->first.swap(new_whitelist); |
| } |
| } |