OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS 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 "update_engine/delta_performer.h" | 5 #include "update_engine/delta_performer.h" |
6 | 6 |
7 #include <endian.h> | 7 #include <endian.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 } | 183 } |
184 // We have the full proto buffer in buffer_. Parse it. | 184 // We have the full proto buffer in buffer_. Parse it. |
185 const int offset = strlen(kDeltaMagic) + kDeltaVersionLength + | 185 const int offset = strlen(kDeltaMagic) + kDeltaVersionLength + |
186 kDeltaProtobufLengthLength; | 186 kDeltaProtobufLengthLength; |
187 if (!manifest_.ParseFromArray(&buffer_[offset], protobuf_length)) { | 187 if (!manifest_.ParseFromArray(&buffer_[offset], protobuf_length)) { |
188 LOG(ERROR) << "Unable to parse manifest in update file."; | 188 LOG(ERROR) << "Unable to parse manifest in update file."; |
189 return -EINVAL; | 189 return -EINVAL; |
190 } | 190 } |
191 // Remove protobuf and header info from buffer_, so buffer_ contains | 191 // Remove protobuf and header info from buffer_, so buffer_ contains |
192 // just data blobs | 192 // just data blobs |
193 size_t metadata_size = strlen(kDeltaMagic) + kDeltaVersionLength + | 193 manifest_metadata_size_ = strlen(kDeltaMagic) + kDeltaVersionLength + |
194 kDeltaProtobufLengthLength + protobuf_length; | 194 kDeltaProtobufLengthLength + protobuf_length; |
195 DiscardBufferHeadBytes(metadata_size, | 195 DiscardBufferHeadBytes(manifest_metadata_size_); |
196 true); // do_hash | |
197 LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize, | 196 LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize, |
198 metadata_size)) | 197 manifest_metadata_size_)) |
199 << "Unable to save the manifest metadata size."; | 198 << "Unable to save the manifest metadata size."; |
200 manifest_valid_ = true; | 199 manifest_valid_ = true; |
201 block_size_ = manifest_.block_size(); | 200 block_size_ = manifest_.block_size(); |
202 } | 201 } |
203 ssize_t total_operations = manifest_.install_operations_size() + | 202 ssize_t total_operations = manifest_.install_operations_size() + |
204 manifest_.kernel_install_operations_size(); | 203 manifest_.kernel_install_operations_size(); |
205 while (next_operation_num_ < total_operations) { | 204 while (next_operation_num_ < total_operations) { |
206 const DeltaArchiveManifest_InstallOperation &op = | 205 const DeltaArchiveManifest_InstallOperation &op = |
207 next_operation_num_ < manifest_.install_operations_size() ? | 206 next_operation_num_ < manifest_.install_operations_size() ? |
208 manifest_.install_operations(next_operation_num_) : | 207 manifest_.install_operations(next_operation_num_) : |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 CHECK(operation.type() == \ | 273 CHECK(operation.type() == \ |
275 DeltaArchiveManifest_InstallOperation_Type_REPLACE || \ | 274 DeltaArchiveManifest_InstallOperation_Type_REPLACE || \ |
276 operation.type() == \ | 275 operation.type() == \ |
277 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); | 276 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); |
278 | 277 |
279 // Since we delete data off the beginning of the buffer as we use it, | 278 // Since we delete data off the beginning of the buffer as we use it, |
280 // the data we need should be exactly at the beginning of the buffer. | 279 // the data we need should be exactly at the beginning of the buffer. |
281 CHECK_EQ(buffer_offset_, operation.data_offset()); | 280 CHECK_EQ(buffer_offset_, operation.data_offset()); |
282 CHECK_GE(buffer_.size(), operation.data_length()); | 281 CHECK_GE(buffer_.size(), operation.data_length()); |
283 | 282 |
284 // Don't include the signature data blob in the hash. | 283 // Extract the signature message if it's in this operation. |
285 bool do_hash = !ExtractSignatureMessage(operation); | 284 ExtractSignatureMessage(operation); |
286 | 285 |
287 DirectExtentWriter direct_writer; | 286 DirectExtentWriter direct_writer; |
288 ZeroPadExtentWriter zero_pad_writer(&direct_writer); | 287 ZeroPadExtentWriter zero_pad_writer(&direct_writer); |
289 scoped_ptr<BzipExtentWriter> bzip_writer; | 288 scoped_ptr<BzipExtentWriter> bzip_writer; |
290 | 289 |
291 // Since bzip decompression is optional, we have a variable writer that will | 290 // Since bzip decompression is optional, we have a variable writer that will |
292 // point to one of the ExtentWriter objects above. | 291 // point to one of the ExtentWriter objects above. |
293 ExtentWriter* writer = NULL; | 292 ExtentWriter* writer = NULL; |
294 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE) { | 293 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE) { |
295 writer = &zero_pad_writer; | 294 writer = &zero_pad_writer; |
(...skipping 12 matching lines...) Expand all Loading... |
308 } | 307 } |
309 | 308 |
310 int fd = is_kernel_partition ? kernel_fd_ : fd_; | 309 int fd = is_kernel_partition ? kernel_fd_ : fd_; |
311 | 310 |
312 TEST_AND_RETURN_FALSE(writer->Init(fd, extents, block_size_)); | 311 TEST_AND_RETURN_FALSE(writer->Init(fd, extents, block_size_)); |
313 TEST_AND_RETURN_FALSE(writer->Write(&buffer_[0], operation.data_length())); | 312 TEST_AND_RETURN_FALSE(writer->Write(&buffer_[0], operation.data_length())); |
314 TEST_AND_RETURN_FALSE(writer->End()); | 313 TEST_AND_RETURN_FALSE(writer->End()); |
315 | 314 |
316 // Update buffer | 315 // Update buffer |
317 buffer_offset_ += operation.data_length(); | 316 buffer_offset_ += operation.data_length(); |
318 DiscardBufferHeadBytes(operation.data_length(), do_hash); | 317 DiscardBufferHeadBytes(operation.data_length()); |
319 return true; | 318 return true; |
320 } | 319 } |
321 | 320 |
322 bool DeltaPerformer::PerformMoveOperation( | 321 bool DeltaPerformer::PerformMoveOperation( |
323 const DeltaArchiveManifest_InstallOperation& operation, | 322 const DeltaArchiveManifest_InstallOperation& operation, |
324 bool is_kernel_partition) { | 323 bool is_kernel_partition) { |
325 // Calculate buffer size. Note, this function doesn't do a sliding | 324 // Calculate buffer size. Note, this function doesn't do a sliding |
326 // window to copy in case the source and destination blocks overlap. | 325 // window to copy in case the source and destination blocks overlap. |
327 // If we wanted to do a sliding window, we could program the server | 326 // If we wanted to do a sliding window, we could program the server |
328 // to generate deltas that effectively did a sliding window. | 327 // to generate deltas that effectively did a sliding window. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 (last_extent.start_block() + last_extent.num_blocks()) * block_size_; | 450 (last_extent.start_block() + last_extent.num_blocks()) * block_size_; |
452 const uint64_t begin_byte = | 451 const uint64_t begin_byte = |
453 end_byte - (block_size_ - operation.dst_length() % block_size_); | 452 end_byte - (block_size_ - operation.dst_length() % block_size_); |
454 vector<char> zeros(end_byte - begin_byte); | 453 vector<char> zeros(end_byte - begin_byte); |
455 TEST_AND_RETURN_FALSE( | 454 TEST_AND_RETURN_FALSE( |
456 utils::PWriteAll(fd, &zeros[0], end_byte - begin_byte, begin_byte)); | 455 utils::PWriteAll(fd, &zeros[0], end_byte - begin_byte, begin_byte)); |
457 } | 456 } |
458 | 457 |
459 // Update buffer. | 458 // Update buffer. |
460 buffer_offset_ += operation.data_length(); | 459 buffer_offset_ += operation.data_length(); |
461 DiscardBufferHeadBytes(operation.data_length(), | 460 DiscardBufferHeadBytes(operation.data_length()); |
462 true); // do_hash | |
463 return true; | 461 return true; |
464 } | 462 } |
465 | 463 |
466 bool DeltaPerformer::ExtractSignatureMessage( | 464 bool DeltaPerformer::ExtractSignatureMessage( |
467 const DeltaArchiveManifest_InstallOperation& operation) { | 465 const DeltaArchiveManifest_InstallOperation& operation) { |
468 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_REPLACE || | 466 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_REPLACE || |
469 !manifest_.has_signatures_offset() || | 467 !manifest_.has_signatures_offset() || |
470 manifest_.signatures_offset() != operation.data_offset()) { | 468 manifest_.signatures_offset() != operation.data_offset()) { |
471 return false; | 469 return false; |
472 } | 470 } |
473 TEST_AND_RETURN_FALSE(manifest_.has_signatures_size() && | 471 TEST_AND_RETURN_FALSE(manifest_.has_signatures_size() && |
474 manifest_.signatures_size() == operation.data_length()); | 472 manifest_.signatures_size() == operation.data_length()); |
475 TEST_AND_RETURN_FALSE(signatures_message_data_.empty()); | 473 TEST_AND_RETURN_FALSE(signatures_message_data_.empty()); |
476 TEST_AND_RETURN_FALSE(buffer_offset_ == manifest_.signatures_offset()); | 474 TEST_AND_RETURN_FALSE(buffer_offset_ == manifest_.signatures_offset()); |
477 TEST_AND_RETURN_FALSE(buffer_.size() >= manifest_.signatures_size()); | 475 TEST_AND_RETURN_FALSE(buffer_.size() >= manifest_.signatures_size()); |
478 signatures_message_data_.insert( | 476 signatures_message_data_.insert( |
479 signatures_message_data_.begin(), | 477 signatures_message_data_.begin(), |
480 buffer_.begin(), | 478 buffer_.begin(), |
481 buffer_.begin() + manifest_.signatures_size()); | 479 buffer_.begin() + manifest_.signatures_size()); |
| 480 // The hash of all data consumed so far should be verified against the signed |
| 481 // hash. |
| 482 signed_hash_context_ = hash_calculator_.GetContext(); |
| 483 LOG_IF(WARNING, !prefs_->SetString(kPrefsUpdateStateSignedSHA256Context, |
| 484 signed_hash_context_)) |
| 485 << "Unable to store the signed hash context."; |
482 LOG(INFO) << "Extracted signature data of size " | 486 LOG(INFO) << "Extracted signature data of size " |
483 << manifest_.signatures_size() << " at " | 487 << manifest_.signatures_size() << " at " |
484 << manifest_.signatures_offset(); | 488 << manifest_.signatures_offset(); |
485 return true; | 489 return true; |
486 } | 490 } |
487 | 491 |
488 bool DeltaPerformer::VerifyPayload(const string& public_key_path) { | 492 bool DeltaPerformer::VerifyPayload( |
| 493 const string& public_key_path, |
| 494 const std::string& update_check_response_hash, |
| 495 const uint64_t update_check_response_size) { |
489 string key_path = public_key_path; | 496 string key_path = public_key_path; |
490 if (key_path.empty()) { | 497 if (key_path.empty()) { |
491 key_path = kUpdatePayloadPublicKeyPath; | 498 key_path = kUpdatePayloadPublicKeyPath; |
492 } | 499 } |
493 LOG(INFO) << "Verifying delta payload. Public key path: " << key_path; | 500 LOG(INFO) << "Verifying delta payload. Public key path: " << key_path; |
| 501 |
| 502 // Verifies the download hash. |
| 503 const string& download_hash_data = hash_calculator_.hash(); |
| 504 TEST_AND_RETURN_FALSE(!download_hash_data.empty()); |
| 505 TEST_AND_RETURN_FALSE(download_hash_data == update_check_response_hash); |
| 506 |
| 507 // Verifies the download size. |
| 508 TEST_AND_RETURN_FALSE(update_check_response_size == |
| 509 manifest_metadata_size_ + buffer_offset_); |
| 510 |
| 511 // Verifies the signed payload hash. |
494 if (!utils::FileExists(key_path.c_str())) { | 512 if (!utils::FileExists(key_path.c_str())) { |
495 LOG(WARNING) << "Not verifying delta payload due to missing public key."; | 513 LOG(WARNING) << "Not verifying signed delta payload -- missing public key."; |
496 return true; | 514 return true; |
497 } | 515 } |
498 TEST_AND_RETURN_FALSE(!signatures_message_data_.empty()); | 516 TEST_AND_RETURN_FALSE(!signatures_message_data_.empty()); |
499 vector<char> signed_hash_data; | 517 vector<char> signed_hash_data; |
500 TEST_AND_RETURN_FALSE(PayloadSigner::VerifySignature(signatures_message_data_, | 518 TEST_AND_RETURN_FALSE(PayloadSigner::VerifySignature(signatures_message_data_, |
501 key_path, | 519 key_path, |
502 &signed_hash_data)); | 520 &signed_hash_data)); |
503 const vector<char>& hash_data = hash_calculator_.raw_hash(); | 521 OmahaHashCalculator signed_hasher; |
| 522 // TODO(petkov): Make sure signed_hash_context_ is loaded when resuming an |
| 523 // update. |
| 524 TEST_AND_RETURN_FALSE(signed_hasher.SetContext(signed_hash_context_)); |
| 525 TEST_AND_RETURN_FALSE(signed_hasher.Finalize()); |
| 526 const vector<char>& hash_data = signed_hasher.raw_hash(); |
504 TEST_AND_RETURN_FALSE(!hash_data.empty()); | 527 TEST_AND_RETURN_FALSE(!hash_data.empty()); |
505 return hash_data == signed_hash_data; | 528 TEST_AND_RETURN_FALSE(hash_data == signed_hash_data); |
| 529 return true; |
506 } | 530 } |
507 | 531 |
508 void DeltaPerformer::DiscardBufferHeadBytes(size_t count, bool do_hash) { | 532 void DeltaPerformer::DiscardBufferHeadBytes(size_t count) { |
509 if (do_hash) { | 533 hash_calculator_.Update(&buffer_[0], count); |
510 hash_calculator_.Update(&buffer_[0], count); | |
511 } | |
512 buffer_.erase(buffer_.begin(), buffer_.begin() + count); | 534 buffer_.erase(buffer_.begin(), buffer_.begin() + count); |
513 } | 535 } |
514 | 536 |
515 bool DeltaPerformer::CanResumeUpdate(PrefsInterface* prefs, | 537 bool DeltaPerformer::CanResumeUpdate(PrefsInterface* prefs, |
516 string update_check_response_hash) { | 538 string update_check_response_hash) { |
517 int64_t next_operation = kUpdateStateOperationInvalid; | 539 int64_t next_operation = kUpdateStateOperationInvalid; |
518 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsUpdateStateNextOperation, | 540 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsUpdateStateNextOperation, |
519 &next_operation) && | 541 &next_operation) && |
520 next_operation != kUpdateStateOperationInvalid && | 542 next_operation != kUpdateStateOperationInvalid && |
521 next_operation > 0); | 543 next_operation > 0); |
522 | 544 |
523 string interrupted_hash; | 545 string interrupted_hash; |
524 TEST_AND_RETURN_FALSE(prefs->GetString(kPrefsUpdateCheckResponseHash, | 546 TEST_AND_RETURN_FALSE(prefs->GetString(kPrefsUpdateCheckResponseHash, |
525 &interrupted_hash) && | 547 &interrupted_hash) && |
526 !interrupted_hash.empty() && | 548 !interrupted_hash.empty() && |
527 interrupted_hash == update_check_response_hash); | 549 interrupted_hash == update_check_response_hash); |
528 | 550 |
529 // Sanity check the rest. | 551 // Sanity check the rest. |
530 int64_t next_data_offset = -1; | 552 int64_t next_data_offset = -1; |
531 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsUpdateStateNextDataOffset, | 553 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsUpdateStateNextDataOffset, |
532 &next_data_offset) && | 554 &next_data_offset) && |
533 next_data_offset >= 0); | 555 next_data_offset >= 0); |
534 | 556 |
535 string signed_sha256_context; | 557 string sha256_context; |
536 TEST_AND_RETURN_FALSE( | 558 TEST_AND_RETURN_FALSE( |
537 prefs->GetString(kPrefsUpdateStateSignedSHA256Context, | 559 prefs->GetString(kPrefsUpdateStateSHA256Context, &sha256_context) && |
538 &signed_sha256_context) && | 560 !sha256_context.empty()); |
539 !signed_sha256_context.empty()); | |
540 | 561 |
541 int64_t manifest_metadata_size = 0; | 562 int64_t manifest_metadata_size = 0; |
542 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsManifestMetadataSize, | 563 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsManifestMetadataSize, |
543 &manifest_metadata_size) && | 564 &manifest_metadata_size) && |
544 manifest_metadata_size > 0); | 565 manifest_metadata_size > 0); |
545 | 566 |
546 return true; | 567 return true; |
547 } | 568 } |
548 | 569 |
549 bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs) { | 570 bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs) { |
550 TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation, | 571 TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation, |
551 kUpdateStateOperationInvalid)); | 572 kUpdateStateOperationInvalid)); |
552 return true; | 573 return true; |
553 } | 574 } |
554 | 575 |
555 bool DeltaPerformer::CheckpointUpdateProgress() { | 576 bool DeltaPerformer::CheckpointUpdateProgress() { |
556 // First reset the progress in case we die in the middle of the state update. | 577 // First reset the progress in case we die in the middle of the state update. |
557 ResetUpdateProgress(prefs_); | 578 ResetUpdateProgress(prefs_); |
558 if (last_updated_buffer_offset_ != buffer_offset_) { | 579 if (last_updated_buffer_offset_ != buffer_offset_) { |
559 TEST_AND_RETURN_FALSE( | 580 TEST_AND_RETURN_FALSE( |
560 prefs_->SetString(kPrefsUpdateStateSignedSHA256Context, | 581 prefs_->SetString(kPrefsUpdateStateSHA256Context, |
561 hash_calculator_.GetContext())); | 582 hash_calculator_.GetContext())); |
562 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataOffset, | 583 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataOffset, |
563 buffer_offset_)); | 584 buffer_offset_)); |
564 last_updated_buffer_offset_ = buffer_offset_; | 585 last_updated_buffer_offset_ = buffer_offset_; |
565 } | 586 } |
566 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation, | 587 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation, |
567 next_operation_num_)); | 588 next_operation_num_)); |
568 return true; | 589 return true; |
569 } | 590 } |
570 | 591 |
571 } // namespace chromeos_update_engine | 592 } // namespace chromeos_update_engine |
OLD | NEW |