Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: components/safe_browsing_db/v4_store.cc

Issue 2384893002: PVer4: Test checksum on startup outside the hotpath of DB load (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/base64.h" 5 #include "base/base64.h"
6 #include "base/bind.h" 6 #include "base/bind.h"
7 #include "base/files/file_util.h" 7 #include "base/files/file_util.h"
8 #include "base/memory/ptr_util.h" 8 #include "base/memory/ptr_util.h"
9 #include "base/metrics/histogram_macros.h" 9 #include "base/metrics/histogram_macros.h"
10 #include "base/metrics/sparse_histogram.h" 10 #include "base/metrics/sparse_histogram.h"
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 123
124 std::string V4Store::DebugString() const { 124 std::string V4Store::DebugString() const {
125 std::string state_base64; 125 std::string state_base64;
126 base::Base64Encode(state_, &state_base64); 126 base::Base64Encode(state_, &state_base64);
127 127
128 return base::StringPrintf("path: %" PRIsFP "; state: %s", 128 return base::StringPrintf("path: %" PRIsFP "; state: %s",
129 store_path_.value().c_str(), state_base64.c_str()); 129 store_path_.value().c_str(), state_base64.c_str());
130 } 130 }
131 131
132 bool V4Store::Reset() { 132 bool V4Store::Reset() {
133 // TODO(vakh): Implement skeleton. 133 hash_prefix_map_.clear();
Nathan Parker 2016/10/03 02:26:49 This should delete the file too, according to the
vakh (use Gerrit instead) 2016/10/04 07:14:39 Done. Don't need to delete the file since it would
134 state_ = ""; 134 state_ = "";
135 return true; 135 return true;
136 } 136 }
137 137
138 ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk( 138 ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk(
139 const HashPrefixMap& hash_prefix_map_old, 139 const HashPrefixMap& hash_prefix_map_old,
140 std::unique_ptr<ListUpdateResponse> response) { 140 std::unique_ptr<ListUpdateResponse> response) {
141 DCHECK(response->has_response_type()); 141 DCHECK(response->has_response_type());
142 DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type()); 142 DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type());
143 143
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 expected_checksum = response->checksum().sha256(); 223 expected_checksum = response->checksum().sha256();
224 } 224 }
225 225
226 base::TimeTicks before = base::TimeTicks::Now(); 226 base::TimeTicks before = base::TimeTicks::Now();
227 apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map, 227 apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map,
228 raw_removals, expected_checksum); 228 raw_removals, expected_checksum);
229 base::TimeTicks after = base::TimeTicks::Now(); 229 base::TimeTicks after = base::TimeTicks::Now();
230 if (apply_update_result != APPLY_UPDATE_SUCCESS) { 230 if (apply_update_result != APPLY_UPDATE_SUCCESS) {
231 return apply_update_result; 231 return apply_update_result;
232 } 232 }
233 RecordMergeUpdateTime(after - before); 233 RecordMergeUpdateTime(after - before);
Nathan Parker 2016/10/03 02:26:48 This mergeupdatetime entry will be for a different
vakh (use Gerrit instead) 2016/10/04 07:14:39 Done. With the latest patch, the time metrics are
vakh (use Gerrit instead) 2016/10/04 20:34:50 Actually, I removed that change to keep this CL si
234 234
235 state_ = response->new_client_state(); 235 state_ = response->new_client_state();
236 return APPLY_UPDATE_SUCCESS; 236 return APPLY_UPDATE_SUCCESS;
237 } 237 }
238 238
239 void V4Store::ApplyUpdate( 239 void V4Store::ApplyUpdate(
240 std::unique_ptr<ListUpdateResponse> response, 240 std::unique_ptr<ListUpdateResponse> response,
241 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, 241 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
242 UpdatedStoreReadyCallback callback) { 242 UpdatedStoreReadyCallback callback) {
243 std::unique_ptr<V4Store> new_store( 243 std::unique_ptr<V4Store> new_store(
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 402
403 (*prefix_map_to_update)[prefix_size].reserve(existing_capacity + 403 (*prefix_map_to_update)[prefix_size].reserve(existing_capacity +
404 prefix_length_to_add); 404 prefix_length_to_add);
405 } 405 }
406 } 406 }
407 407
408 ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, 408 ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map,
409 const HashPrefixMap& additions_map, 409 const HashPrefixMap& additions_map,
410 const RepeatedField<int32>* raw_removals, 410 const RepeatedField<int32>* raw_removals,
411 const std::string& expected_checksum) { 411 const std::string& expected_checksum) {
412 DCHECK(task_runner_->RunsTasksOnCurrentThread());
412 DCHECK(hash_prefix_map_.empty()); 413 DCHECK(hash_prefix_map_.empty());
414
415 bool calculate_checksum = !expected_checksum.empty();
416 if (old_prefixes_map.empty()) {
417 // If the old map is empty, which it is at startup, then just copy over the
418 // additions map.
419 DCHECK(!raw_removals);
420 hash_prefix_map_ = additions_map;
421
422 if (calculate_checksum) {
423 task_runner_->PostTask(
Nathan Parker 2016/10/03 02:26:49 Add a comment to why this is not run synchronously
vakh (use Gerrit instead) 2016/10/04 07:14:39 Done.
424 FROM_HERE, base::Bind(&V4Store::VerifyChecksum,
Nathan Parker 2016/10/03 02:26:49 How many CPU seconds will this take, when it does
vakh (use Gerrit instead) 2016/10/04 07:14:39 It takes 2-3 seconds on my machine.
425 base::Unretained(this), expected_checksum));
426 }
427
428 return APPLY_UPDATE_SUCCESS;
429 }
430
413 hash_prefix_map_.clear(); 431 hash_prefix_map_.clear();
414 ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_); 432 ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_);
415 ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_); 433 ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_);
416 434
417 IteratorMap old_iterator_map; 435 IteratorMap old_iterator_map;
418 HashPrefix next_smallest_prefix_old; 436 HashPrefix next_smallest_prefix_old;
419 InitializeIteratorMap(old_prefixes_map, &old_iterator_map); 437 InitializeIteratorMap(old_prefixes_map, &old_iterator_map);
420 bool old_has_unmerged = GetNextSmallestUnmergedPrefix( 438 bool old_has_unmerged = GetNextSmallestUnmergedPrefix(
421 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old); 439 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
422 440
423 IteratorMap additions_iterator_map; 441 IteratorMap additions_iterator_map;
424 HashPrefix next_smallest_prefix_additions; 442 HashPrefix next_smallest_prefix_additions;
425 InitializeIteratorMap(additions_map, &additions_iterator_map); 443 InitializeIteratorMap(additions_map, &additions_iterator_map);
426 bool additions_has_unmerged = GetNextSmallestUnmergedPrefix( 444 bool additions_has_unmerged = GetNextSmallestUnmergedPrefix(
427 additions_map, additions_iterator_map, &next_smallest_prefix_additions); 445 additions_map, additions_iterator_map, &next_smallest_prefix_additions);
428 446
429 // Classical merge sort. 447 // Classical merge sort.
430 // The two constructs to merge are maps: old_prefixes_map, additions_map. 448 // The two constructs to merge are maps: old_prefixes_map, additions_map.
431 // At least one of the maps still has elements that need to be merged into the 449 // At least one of the maps still has elements that need to be merged into the
432 // new store. 450 // new store.
433 451
434 bool calculate_checksum = !expected_checksum.empty();
435 std::unique_ptr<crypto::SecureHash> checksum_ctx( 452 std::unique_ptr<crypto::SecureHash> checksum_ctx(
436 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); 453 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
437 454
438 // Keep track of the number of elements picked from the old map. This is used 455 // Keep track of the number of elements picked from the old map. This is used
439 // to determine which elements to drop based on the raw_removals. Note that 456 // to determine which elements to drop based on the raw_removals. Note that
440 // picked is not the same as merged. A picked element isn't merged if its 457 // picked is not the same as merged. A picked element isn't merged if its
441 // index is on the raw_removals list. 458 // index is on the raw_removals list.
442 int total_picked_from_old = 0; 459 int total_picked_from_old = 0;
443 const int* removals_iter = raw_removals ? raw_removals->begin() : nullptr; 460 const int* removals_iter = raw_removals ? raw_removals->begin() : nullptr;
444 while (old_has_unmerged || additions_has_unmerged) { 461 while (old_has_unmerged || additions_has_unmerged) {
445 // If the same hash prefix appears in the existing store and the additions 462 // If the same hash prefix appears in the existing store and the additions
446 // list, something is clearly wrong. Discard the update. 463 // list, something is clearly wrong. Discard the update.
447 if (old_has_unmerged && additions_has_unmerged && 464 if (old_has_unmerged && additions_has_unmerged &&
448 next_smallest_prefix_old == next_smallest_prefix_additions) { 465 next_smallest_prefix_old == next_smallest_prefix_additions) {
449 return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE; 466 return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE;
450 } 467 }
451 468
452 // Select which map to pick the next hash prefix from to keep the result in 469 // Select which map to pick the next hash prefix from to keep the result in
453 // lexographically sorted order. 470 // lexographically sorted order.
454 bool pick_from_old = 471 bool pick_from_old =
455 old_has_unmerged && 472 old_has_unmerged &&
456 (!additions_has_unmerged || 473 (!additions_has_unmerged ||
457 (next_smallest_prefix_old < next_smallest_prefix_additions)); 474 (next_smallest_prefix_old < next_smallest_prefix_additions));
458 475
459 PrefixSize next_smallest_prefix_size; 476 PrefixSize next_smallest_prefix_size;
460 if (pick_from_old) { 477 if (pick_from_old) {
461 next_smallest_prefix_size = next_smallest_prefix_old.size(); 478 next_smallest_prefix_size = next_smallest_prefix_old.size();
462 479
463 // Update the iterator map, which means that we have merged one hash 480 // Update the iterator map, which means that we have merged one hash
464 // prefix of size |next_size_for_old| from the old store. 481 // prefix of size |next_smallest_prefix_size| from the old store.
465 old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size; 482 old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
466 483
467 if (!raw_removals || removals_iter == raw_removals->end() || 484 if (!raw_removals || removals_iter == raw_removals->end() ||
468 *removals_iter != total_picked_from_old) { 485 *removals_iter != total_picked_from_old) {
469 // Append the smallest hash to the appropriate list. 486 // Append the smallest hash to the appropriate list.
470 hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old; 487 hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old;
471 488
472 if (calculate_checksum) { 489 if (calculate_checksum) {
473 checksum_ctx->Update(base::string_as_array(&next_smallest_prefix_old), 490 checksum_ctx->Update(base::string_as_array(&next_smallest_prefix_old),
474 next_smallest_prefix_size); 491 next_smallest_prefix_size);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 } 530 }
514 531
515 if (calculate_checksum) { 532 if (calculate_checksum) {
516 std::string checksum(crypto::kSHA256Length, 0); 533 std::string checksum(crypto::kSHA256Length, 0);
517 checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size()); 534 checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size());
518 if (checksum != expected_checksum) { 535 if (checksum != expected_checksum) {
519 std::string checksum_base64, expected_checksum_base64; 536 std::string checksum_base64, expected_checksum_base64;
520 base::Base64Encode(checksum, &checksum_base64); 537 base::Base64Encode(checksum, &checksum_base64);
521 base::Base64Encode(expected_checksum, &expected_checksum_base64); 538 base::Base64Encode(expected_checksum, &expected_checksum_base64);
522 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64 539 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64
523 << " expected: " << expected_checksum_base64; 540 << "; expected: " << expected_checksum_base64
541 << "; store: " << *this;
542 ;
524 return CHECKSUM_MISMATCH_FAILURE; 543 return CHECKSUM_MISMATCH_FAILURE;
525 } 544 }
526 } 545 }
527 546
528 return APPLY_UPDATE_SUCCESS; 547 return APPLY_UPDATE_SUCCESS;
529 } 548 }
530 549
531 StoreReadResult V4Store::ReadFromDisk() { 550 StoreReadResult V4Store::ReadFromDisk() {
532 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 551 DCHECK(task_runner_->RunsTasksOnCurrentThread());
533 552
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 int result = hash_prefix.compare(mid_prefix); 662 int result = hash_prefix.compare(mid_prefix);
644 if (result == 0) { 663 if (result == 0) {
645 return true; 664 return true;
646 } else if (result < 0) { 665 } else if (result < 0) {
647 return HashPrefixMatches(hash_prefix, begin, mid); 666 return HashPrefixMatches(hash_prefix, begin, mid);
648 } else { 667 } else {
649 return HashPrefixMatches(hash_prefix, mid + prefix_size, end); 668 return HashPrefixMatches(hash_prefix, mid + prefix_size, end);
650 } 669 }
651 } 670 }
652 671
672 void V4Store::VerifyChecksum(const std::string& expected_checksum) {
Nathan Parker 2016/10/03 02:26:49 Maybe call this VerifyChecksumDelayed, so as to di
vakh (use Gerrit instead) 2016/10/04 07:14:39 Done.
673 DCHECK(task_runner_->RunsTasksOnCurrentThread());
674
675 IteratorMap iterator_map;
676 HashPrefix next_smallest_prefix;
677 InitializeIteratorMap(hash_prefix_map_, &iterator_map);
678 bool has_unmerged = GetNextSmallestUnmergedPrefix(
679 hash_prefix_map_, iterator_map, &next_smallest_prefix);
680
681 std::unique_ptr<crypto::SecureHash> checksum_ctx(
682 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
683 while (has_unmerged) {
684 PrefixSize next_smallest_prefix_size;
685 next_smallest_prefix_size = next_smallest_prefix.size();
686
687 // Update the iterator map, which means that we have read one hash
688 // prefix of size |next_smallest_prefix_size| from hash_prefix_map_.
689 iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
690
691 checksum_ctx->Update(base::string_as_array(&next_smallest_prefix),
692 next_smallest_prefix_size);
693
694 // Find the next smallest unmerged element in the map.
695 has_unmerged = GetNextSmallestUnmergedPrefix(hash_prefix_map_, iterator_map,
696 &next_smallest_prefix);
697 }
698
699 std::string checksum(crypto::kSHA256Length, 0);
700 checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size());
701 if (checksum == expected_checksum) {
702 return;
703 }
704
705 std::string checksum_base64, expected_checksum_base64;
706 base::Base64Encode(checksum, &checksum_base64);
707 base::Base64Encode(expected_checksum, &expected_checksum_base64);
708 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64
709 << "; expected: " << expected_checksum_base64
710 << "; store: " << *this;
711 RecordApplyUpdateResultWhenReadingFromDisk(CHECKSUM_MISMATCH_FAILURE);
Nathan Parker 2016/10/03 02:26:49 This should probably be a different enum, since ch
vakh (use Gerrit instead) 2016/10/04 07:14:39 Yes, but it is different. This one is: RecordApply
712
713 Reset();
Nathan Parker 2016/10/03 02:26:49 This is a race if someone is accessing the store o
vakh (use Gerrit instead) 2016/10/04 07:14:39 Done.
714 }
715
653 } // namespace safe_browsing 716 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « components/safe_browsing_db/v4_store.h ('k') | components/safe_browsing_db/v4_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698