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

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

Issue 2228393003: PVer4: DecodeHashes needs to sort the output of the Rice decoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@01_checksum
Patch Set: DecodeBytes->DecodePrefixes. More detailed comment. Created 4 years, 4 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 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 state_ = response->new_client_state(); 204 state_ = response->new_client_state();
205 return APPLY_UPDATE_SUCCESS; 205 return APPLY_UPDATE_SUCCESS;
206 } 206 }
207 207
208 void V4Store::ApplyUpdate( 208 void V4Store::ApplyUpdate(
209 std::unique_ptr<ListUpdateResponse> response, 209 std::unique_ptr<ListUpdateResponse> response,
210 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, 210 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
211 UpdatedStoreReadyCallback callback) { 211 UpdatedStoreReadyCallback callback) {
212 std::unique_ptr<V4Store> new_store( 212 std::unique_ptr<V4Store> new_store(
213 new V4Store(this->task_runner_, this->store_path_)); 213 new V4Store(this->task_runner_, this->store_path_));
214
215 ApplyUpdateResult apply_update_result; 214 ApplyUpdateResult apply_update_result;
216 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { 215 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) {
217 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( 216 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk(
218 hash_prefix_map_, std::move(response)); 217 hash_prefix_map_, std::move(response));
219 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { 218 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) {
220 apply_update_result = 219 apply_update_result =
221 new_store->ProcessFullUpdateAndWriteToDisk(std::move(response)); 220 new_store->ProcessFullUpdateAndWriteToDisk(std::move(response));
222 } else { 221 } else {
223 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; 222 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE;
224 NOTREACHED() << "Unexpected response type: " << response->response_type(); 223 NOTREACHED() << "Failure: Unexpected response type: "
224 << response->response_type();
225 } 225 }
226 226
227 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 227 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
228 // new_store is done updating, pass it to the callback. 228 // new_store is done updating, pass it to the callback.
229 callback_task_runner->PostTask( 229 callback_task_runner->PostTask(
230 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); 230 FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
231 } else { 231 } else {
232 DVLOG(1) << "ApplyUpdate failed: reason: " << apply_update_result 232 DVLOG(1) << "Failure: ApplyUpdate: reason: " << apply_update_result
233 << "; store: " << *this; 233 << "; store: " << *this;
234 // new_store failed updating. Pass a nullptr to the callback. 234 // new_store failed updating. Pass a nullptr to the callback.
235 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); 235 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
236 } 236 }
237 237
238 RecordApplyUpdateResult(apply_update_result); 238 RecordApplyUpdateResult(apply_update_result);
239 } 239 }
240 240
241 // static 241 // static
242 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( 242 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions(
243 const RepeatedPtrField<ThreatEntrySet>& additions, 243 const RepeatedPtrField<ThreatEntrySet>& additions,
244 HashPrefixMap* additions_map) { 244 HashPrefixMap* additions_map) {
245 for (const auto& addition : additions) { 245 for (const auto& addition : additions) {
246 ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS; 246 ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS;
247 const CompressionType compression_type = addition.compression_type(); 247 const CompressionType compression_type = addition.compression_type();
248 if (compression_type == RAW) { 248 if (compression_type == RAW) {
249 DCHECK(addition.has_raw_hashes()); 249 DCHECK(addition.has_raw_hashes());
250 DCHECK(addition.raw_hashes().has_raw_hashes()); 250 DCHECK(addition.raw_hashes().has_raw_hashes());
251 251
252 apply_update_result = 252 apply_update_result =
253 AddUnlumpedHashes(addition.raw_hashes().prefix_size(), 253 AddUnlumpedHashes(addition.raw_hashes().prefix_size(),
254 addition.raw_hashes().raw_hashes(), additions_map); 254 addition.raw_hashes().raw_hashes(), additions_map);
255 } else if (compression_type == RICE) { 255 } else if (compression_type == RICE) {
256 DCHECK(addition.has_rice_hashes()); 256 DCHECK(addition.has_rice_hashes());
257 257
258 const RiceDeltaEncoding& rice_hashes = addition.rice_hashes(); 258 const RiceDeltaEncoding& rice_hashes = addition.rice_hashes();
259 std::string raw_hashes; 259 std::vector<uint32_t> raw_hashes;
260 V4DecodeResult decode_result = V4RiceDecoder::DecodeBytes( 260 V4DecodeResult decode_result = V4RiceDecoder::DecodePrefixes(
261 rice_hashes.first_value(), rice_hashes.rice_parameter(), 261 rice_hashes.first_value(), rice_hashes.rice_parameter(),
262 rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes); 262 rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes);
263 RecordDecodeAdditionsResult(decode_result); 263 RecordDecodeAdditionsResult(decode_result);
264 if (decode_result != DECODE_SUCCESS) { 264 if (decode_result != DECODE_SUCCESS) {
265 return RICE_DECODING_FAILURE; 265 return RICE_DECODING_FAILURE;
266 } else { 266 } else {
267 char* raw_hashes_start = reinterpret_cast<char*>(raw_hashes.data());
268 size_t raw_hashes_size = sizeof(uint32_t) * raw_hashes.size();
269
267 // Rice-Golomb encoding is used to send compressed compressed 4-byte 270 // Rice-Golomb encoding is used to send compressed compressed 4-byte
268 // hash prefixes. Hash prefixes longer than 4 bytes will not be 271 // hash prefixes. Hash prefixes longer than 4 bytes will not be
269 // compressed, and will be served in raw format instead. 272 // compressed, and will be served in raw format instead.
270 // Source: https://developers.google.com/safe-browsing/v4/compression 273 // Source: https://developers.google.com/safe-browsing/v4/compression
271 const PrefixSize kPrefixSize = 4; 274 const PrefixSize kPrefixSize = 4;
272 apply_update_result = 275 apply_update_result = AddUnlumpedHashes(kPrefixSize, raw_hashes_start,
273 AddUnlumpedHashes(kPrefixSize, raw_hashes, additions_map); 276 raw_hashes_size, additions_map);
274 } 277 }
275 } else { 278 } else {
276 NOTREACHED() << "Unexpected compression_type type: " << compression_type; 279 NOTREACHED() << "Unexpected compression_type type: " << compression_type;
277 return UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE; 280 return UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE;
278 } 281 }
279 282
280 if (apply_update_result != APPLY_UPDATE_SUCCESS) { 283 if (apply_update_result != APPLY_UPDATE_SUCCESS) {
281 // If there was an error in updating the map, discard the update entirely. 284 // If there was an error in updating the map, discard the update entirely.
282 return apply_update_result; 285 return apply_update_result;
283 } 286 }
284 } 287 }
285 288
286 return APPLY_UPDATE_SUCCESS; 289 return APPLY_UPDATE_SUCCESS;
287 } 290 }
288 291
289 // static 292 // static
290 ApplyUpdateResult V4Store::AddUnlumpedHashes(PrefixSize prefix_size, 293 ApplyUpdateResult V4Store::AddUnlumpedHashes(PrefixSize prefix_size,
291 const std::string& lumped_hashes, 294 const std::string& raw_hashes,
295 HashPrefixMap* additions_map) {
296 return AddUnlumpedHashes(prefix_size, raw_hashes.data(), raw_hashes.size(),
297 additions_map);
298 }
299
300 // static
301 ApplyUpdateResult V4Store::AddUnlumpedHashes(PrefixSize prefix_size,
302 const char* raw_hashes_begin,
303 const size_t raw_hashes_length,
292 HashPrefixMap* additions_map) { 304 HashPrefixMap* additions_map) {
293 if (prefix_size < kMinHashPrefixLength) { 305 if (prefix_size < kMinHashPrefixLength) {
294 NOTREACHED(); 306 NOTREACHED();
295 return PREFIX_SIZE_TOO_SMALL_FAILURE; 307 return PREFIX_SIZE_TOO_SMALL_FAILURE;
296 } 308 }
297 if (prefix_size > kMaxHashPrefixLength) { 309 if (prefix_size > kMaxHashPrefixLength) {
298 NOTREACHED(); 310 NOTREACHED();
299 return PREFIX_SIZE_TOO_LARGE_FAILURE; 311 return PREFIX_SIZE_TOO_LARGE_FAILURE;
300 } 312 }
301 if (lumped_hashes.size() % prefix_size != 0) { 313 if (raw_hashes_length % prefix_size != 0) {
302 return ADDITIONS_SIZE_UNEXPECTED_FAILURE; 314 return ADDITIONS_SIZE_UNEXPECTED_FAILURE;
303 } 315 }
316
304 // TODO(vakh): Figure out a way to avoid the following copy operation. 317 // TODO(vakh): Figure out a way to avoid the following copy operation.
305 (*additions_map)[prefix_size] = lumped_hashes; 318 (*additions_map)[prefix_size] =
319 std::string(raw_hashes_begin, raw_hashes_begin + raw_hashes_length);
306 return APPLY_UPDATE_SUCCESS; 320 return APPLY_UPDATE_SUCCESS;
307 } 321 }
308 322
309 // static 323 // static
310 bool V4Store::GetNextSmallestUnmergedPrefix( 324 bool V4Store::GetNextSmallestUnmergedPrefix(
311 const HashPrefixMap& hash_prefix_map, 325 const HashPrefixMap& hash_prefix_map,
312 const IteratorMap& iterator_map, 326 const IteratorMap& iterator_map,
313 HashPrefix* smallest_hash_prefix) { 327 HashPrefix* smallest_hash_prefix) {
314 HashPrefix current_hash_prefix; 328 HashPrefix current_hash_prefix;
315 bool has_unmerged = false; 329 bool has_unmerged = false;
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 return REMOVALS_INDEX_TOO_LARGE_FAILURE; 475 return REMOVALS_INDEX_TOO_LARGE_FAILURE;
462 } 476 }
463 477
464 if (calculate_checksum) { 478 if (calculate_checksum) {
465 std::string checksum(crypto::kSHA256Length, 0); 479 std::string checksum(crypto::kSHA256Length, 0);
466 checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size()); 480 checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size());
467 if (checksum != expected_checksum) { 481 if (checksum != expected_checksum) {
468 std::string checksum_base64, expected_checksum_base64; 482 std::string checksum_base64, expected_checksum_base64;
469 base::Base64Encode(checksum, &checksum_base64); 483 base::Base64Encode(checksum, &checksum_base64);
470 base::Base64Encode(expected_checksum, &expected_checksum_base64); 484 base::Base64Encode(expected_checksum, &expected_checksum_base64);
471 DVLOG(1) << "Checksum failed: calculated: " << checksum_base64 485 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64
472 << "expected: " << expected_checksum_base64; 486 << " expected: " << expected_checksum_base64;
473 return CHECKSUM_MISMATCH_FAILURE; 487 return CHECKSUM_MISMATCH_FAILURE;
474 } 488 }
475 } 489 }
476 490
477 return APPLY_UPDATE_SUCCESS; 491 return APPLY_UPDATE_SUCCESS;
478 } 492 }
479 493
480 StoreReadResult V4Store::ReadFromDisk() { 494 StoreReadResult V4Store::ReadFromDisk() {
481 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 495 DCHECK(task_runner_->RunsTasksOnCurrentThread());
482 496
483 std::string contents; 497 std::string contents;
484 bool read_success = base::ReadFileToString(store_path_, &contents); 498 bool read_success = base::ReadFileToString(store_path_, &contents);
485 if (!read_success) { 499 if (!read_success) {
486 return FILE_UNREADABLE_FAILURE; 500 return FILE_UNREADABLE_FAILURE;
487 } 501 }
488 502
489 if (contents.empty()) { 503 if (contents.empty()) {
490 return FILE_EMPTY_FAILURE; 504 return FILE_EMPTY_FAILURE;
491 } 505 }
492 506
493 V4StoreFileFormat file_format; 507 V4StoreFileFormat file_format;
494 if (!file_format.ParseFromString(contents)) { 508 if (!file_format.ParseFromString(contents)) {
495 return PROTO_PARSING_FAILURE; 509 return PROTO_PARSING_FAILURE;
496 } 510 }
497 511
498 if (file_format.magic_number() != kFileMagic) { 512 if (file_format.magic_number() != kFileMagic) {
499 DVLOG(1) << "Unexpected magic number found in file: "
500 << file_format.magic_number();
501 return UNEXPECTED_MAGIC_NUMBER_FAILURE; 513 return UNEXPECTED_MAGIC_NUMBER_FAILURE;
502 } 514 }
503 515
504 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead", 516 UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead",
505 file_format.version_number()); 517 file_format.version_number());
506 if (file_format.version_number() != kFileVersion) { 518 if (file_format.version_number() != kFileVersion) {
507 DVLOG(1) << "File version incompatible: " << file_format.version_number()
508 << "; expected: " << kFileVersion;
509 return FILE_VERSION_INCOMPATIBLE_FAILURE; 519 return FILE_VERSION_INCOMPATIBLE_FAILURE;
510 } 520 }
511 521
512 if (!file_format.has_list_update_response()) { 522 if (!file_format.has_list_update_response()) {
513 return HASH_PREFIX_INFO_MISSING_FAILURE; 523 return HASH_PREFIX_INFO_MISSING_FAILURE;
514 } 524 }
515 525
516 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); 526 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse);
517 response->Swap(file_format.mutable_list_update_response()); 527 response->Swap(file_format.mutable_list_update_response());
518 ApplyUpdateResult apply_update_result = ProcessFullUpdate(response); 528 ApplyUpdateResult apply_update_result = ProcessFullUpdate(response);
519 RecordApplyUpdateResultWhenReadingFromDisk(apply_update_result); 529 RecordApplyUpdateResultWhenReadingFromDisk(apply_update_result);
520 if (apply_update_result != APPLY_UPDATE_SUCCESS) { 530 if (apply_update_result != APPLY_UPDATE_SUCCESS) {
521 hash_prefix_map_.clear(); 531 hash_prefix_map_.clear();
522 return HASH_PREFIX_MAP_GENERATION_FAILURE; 532 return HASH_PREFIX_MAP_GENERATION_FAILURE;
523 } 533 }
524 534
525 return READ_SUCCESS; 535 return READ_SUCCESS;
526 } 536 }
527 537
528 StoreWriteResult V4Store::WriteToDisk( 538 StoreWriteResult V4Store::WriteToDisk(
529 std::unique_ptr<ListUpdateResponse> response) const { 539 std::unique_ptr<ListUpdateResponse> response) const {
530 // Do not write partial updates to the disk. 540 // Do not write partial updates to the disk.
531 // After merging the updates, the ListUpdateResponse passed to this method 541 // After merging the updates, the ListUpdateResponse passed to this method
532 // should be a FULL_UPDATE. 542 // should be a FULL_UPDATE.
533 if (!response->has_response_type() || 543 if (!response->has_response_type() ||
534 response->response_type() != ListUpdateResponse::FULL_UPDATE) { 544 response->response_type() != ListUpdateResponse::FULL_UPDATE) {
535 DVLOG(1) << "response->has_response_type(): " 545 DVLOG(1) << "Failure: response->has_response_type(): "
536 << response->has_response_type(); 546 << response->has_response_type()
537 DVLOG(1) << "response->response_type(): " << response->response_type(); 547 << " : response->response_type(): " << response->response_type();
538 return INVALID_RESPONSE_TYPE_FAILURE; 548 return INVALID_RESPONSE_TYPE_FAILURE;
539 } 549 }
540 550
541 // Attempt writing to a temporary file first and at the end, swap the files. 551 // Attempt writing to a temporary file first and at the end, swap the files.
542 const base::FilePath new_filename = TemporaryFileForFilename(store_path_); 552 const base::FilePath new_filename = TemporaryFileForFilename(store_path_);
543 553
544 V4StoreFileFormat file_format; 554 V4StoreFileFormat file_format;
545 file_format.set_magic_number(kFileMagic); 555 file_format.set_magic_number(kFileMagic);
546 file_format.set_version_number(kFileVersion); 556 file_format.set_version_number(kFileVersion);
547 ListUpdateResponse* response_to_write = 557 ListUpdateResponse* response_to_write =
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 if (result == 0) { 604 if (result == 0) {
595 return true; 605 return true;
596 } else if (result < 0) { 606 } else if (result < 0) {
597 return HashPrefixMatches(hash_prefix, begin, mid); 607 return HashPrefixMatches(hash_prefix, begin, mid);
598 } else { 608 } else {
599 return HashPrefixMatches(hash_prefix, mid + prefix_size, end); 609 return HashPrefixMatches(hash_prefix, mid + prefix_size, end);
600 } 610 }
601 } 611 }
602 612
603 } // namespace safe_browsing 613 } // 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