| 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 |