Chromium Code Reviews| Index: components/safe_browsing_db/v4_store.cc |
| diff --git a/components/safe_browsing_db/v4_store.cc b/components/safe_browsing_db/v4_store.cc |
| index 434c6a9751fe03bb088472ff28777ca1451d2b0c..8946ccdbc056a279de7e90c1a5c44ca713e15ee3 100644 |
| --- a/components/safe_browsing_db/v4_store.cc |
| +++ b/components/safe_browsing_db/v4_store.cc |
| @@ -13,6 +13,7 @@ |
| #include "components/safe_browsing_db/v4_rice.h" |
| #include "components/safe_browsing_db/v4_store.h" |
| #include "components/safe_browsing_db/v4_store.pb.h" |
| +#include "content/public/browser/browser_thread.h" |
| #include "crypto/secure_hash.h" |
| #include "crypto/sha2.h" |
| @@ -34,8 +35,6 @@ std::string GetUmaSuffixForStore(const base::FilePath& file_path) { |
| void RecordTimeWithAndWithoutStore(const std::string& metric, |
| base::TimeDelta time, |
| const base::FilePath& file_path) { |
| - std::string suffix = GetUmaSuffixForStore(file_path); |
| - |
| // The histograms below are an expansion of the UMA_HISTOGRAM_LONG_TIMES |
| // macro adapted to allow for a dynamically suffixed histogram name. |
| // Note: The factory creates and owns the histogram. |
| @@ -47,6 +46,7 @@ void RecordTimeWithAndWithoutStore(const std::string& metric, |
| histogram->AddTime(time); |
| } |
| + std::string suffix = GetUmaSuffixForStore(file_path); |
| base::HistogramBase* histogram_suffix = base::Histogram::FactoryTimeGet( |
| metric + suffix, base::TimeDelta::FromMilliseconds(1), |
| base::TimeDelta::FromHours(1), 50, |
| @@ -174,10 +174,21 @@ std::string V4Store::DebugString() const { |
| store_path_.value().c_str(), state_base64.c_str()); |
| } |
| -bool V4Store::Reset() { |
| - // TODO(vakh): Implement skeleton. |
| +void V4Store::Reset() { |
| + DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| + |
| + // Posted to IO thread to avoid the race condition between |
| + // |GetMatchingHashPrefix()|, which runs on the IO thread, and |Reset()|, |
| + // which runs on task runner. |
|
Scott Hess - ex-Googler
2016/10/05 04:42:13
I may be reading things wrong, but I think now wha
vakh (use Gerrit instead)
2016/10/05 23:49:32
I've deleted the Reset code in the V4Database sinc
|
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::IO, FROM_HERE, |
| + base::Bind(&V4Store::ResetOnIOThread, base::Unretained(this))); |
| +} |
| + |
| +void V4Store::ResetOnIOThread() { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + hash_prefix_map_.clear(); |
| state_ = ""; |
| - return true; |
| } |
| ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk( |
| @@ -201,8 +212,8 @@ ApplyUpdateResult V4Store::ProcessFullUpdateAndWriteToDisk( |
| TimeTicks before = TimeTicks::Now(); |
| ApplyUpdateResult result = ProcessFullUpdate(response); |
| if (result == APPLY_UPDATE_SUCCESS) { |
| - RecordStoreWriteResult(WriteToDisk(std::move(response))); |
| RecordProcessFullUpdateTime(TimeTicks::Now() - before, store_path_); |
| + RecordStoreWriteResult(WriteToDisk(std::move(response))); |
| } |
| return result; |
| } |
| @@ -310,7 +321,6 @@ void V4Store::ApplyUpdate( |
| RecordApplyUpdateResult(apply_update_result); |
| } |
| -// static |
| ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( |
| const RepeatedPtrField<ThreatEntrySet>& additions, |
| HashPrefixMap* additions_map) { |
| @@ -448,7 +458,29 @@ ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, |
| const HashPrefixMap& additions_map, |
| const RepeatedField<int32>* raw_removals, |
| const std::string& expected_checksum) { |
| + DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| DCHECK(hash_prefix_map_.empty()); |
| + |
| + bool calculate_checksum = !expected_checksum.empty(); |
| + if (old_prefixes_map.empty()) { |
| + // If the old map is empty, which it is at startup, then just copy over the |
| + // additions map. |
| + DCHECK(!raw_removals); |
| + hash_prefix_map_ = additions_map; |
| + |
| + if (calculate_checksum) { |
| + // Calculate the checksum asynchronously later and if it doesn't match, |
| + // reset the store. This is done so that the SafeBrowsing DB loads |
| + // quickly, because navigation operations are not allowed until the DB |
| + // loads. |
| + task_runner_->PostTask( |
| + FROM_HERE, base::Bind(&V4Store::VerifyChecksumDelayed, |
| + base::Unretained(this), expected_checksum)); |
| + } |
| + |
| + return APPLY_UPDATE_SUCCESS; |
| + } |
| + |
| hash_prefix_map_.clear(); |
| ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_); |
| ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_); |
| @@ -470,7 +502,6 @@ ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, |
| // At least one of the maps still has elements that need to be merged into the |
| // new store. |
| - bool calculate_checksum = !expected_checksum.empty(); |
| std::unique_ptr<crypto::SecureHash> checksum_ctx( |
| crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
| @@ -500,7 +531,7 @@ ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, |
| next_smallest_prefix_size = next_smallest_prefix_old.size(); |
| // Update the iterator map, which means that we have merged one hash |
| - // prefix of size |next_size_for_old| from the old store. |
| + // prefix of size |next_smallest_prefix_size| from the old store. |
| old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size; |
| if (!raw_removals || removals_iter == raw_removals->end() || |
| @@ -559,7 +590,9 @@ ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, |
| base::Base64Encode(checksum, &checksum_base64); |
| base::Base64Encode(expected_checksum, &expected_checksum_base64); |
| DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64 |
| - << " expected: " << expected_checksum_base64; |
| + << "; expected: " << expected_checksum_base64 |
| + << "; store: " << *this; |
| + ; |
| return CHECKSUM_MISMATCH_FAILURE; |
| } |
| } |
| @@ -649,6 +682,7 @@ StoreWriteResult V4Store::WriteToDisk( |
| } |
| HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| // It should never be the case that more than one hash prefixes match a given |
| // full hash. However, if that happens, this method returns any one of them. |
| // It does not guarantee which one of those will be returned. |
| @@ -688,4 +722,48 @@ bool V4Store::HashPrefixMatches(const HashPrefix& hash_prefix, |
| } |
| } |
| +void V4Store::VerifyChecksumDelayed(const std::string& expected_checksum) { |
| + DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| + |
| + IteratorMap iterator_map; |
| + HashPrefix next_smallest_prefix; |
| + InitializeIteratorMap(hash_prefix_map_, &iterator_map); |
| + bool has_unmerged = GetNextSmallestUnmergedPrefix( |
| + hash_prefix_map_, iterator_map, &next_smallest_prefix); |
| + |
| + std::unique_ptr<crypto::SecureHash> checksum_ctx( |
| + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
| + while (has_unmerged) { |
| + PrefixSize next_smallest_prefix_size; |
| + next_smallest_prefix_size = next_smallest_prefix.size(); |
| + |
| + // Update the iterator map, which means that we have read one hash |
| + // prefix of size |next_smallest_prefix_size| from hash_prefix_map_. |
| + iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size; |
| + |
| + checksum_ctx->Update(base::string_as_array(&next_smallest_prefix), |
| + next_smallest_prefix_size); |
| + |
| + // Find the next smallest unmerged element in the map. |
| + has_unmerged = GetNextSmallestUnmergedPrefix(hash_prefix_map_, iterator_map, |
| + &next_smallest_prefix); |
| + } |
| + |
| + std::string checksum(crypto::kSHA256Length, 0); |
| + checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size()); |
| + if (checksum == expected_checksum) { |
| + return; |
| + } |
| + |
| + std::string checksum_base64, expected_checksum_base64; |
| + base::Base64Encode(checksum, &checksum_base64); |
| + base::Base64Encode(expected_checksum, &expected_checksum_base64); |
| + DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64 |
| + << "; expected: " << expected_checksum_base64 |
| + << "; store: " << *this; |
| + RecordApplyUpdateResultWhenReadingFromDisk(CHECKSUM_MISMATCH_FAILURE); |
| + |
| + Reset(); |
| +} |
| + |
| } // namespace safe_browsing |