|  | // | 
|  | // Copyright (C) 2018 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | // | 
|  |  | 
|  | #include "update_engine/payload_consumer/verity_writer_android.h" | 
|  |  | 
|  | #include <fcntl.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <memory> | 
|  |  | 
|  | #include <base/logging.h> | 
|  | #include <base/posix/eintr_wrapper.h> | 
|  |  | 
|  | #include "update_engine/common/utils.h" | 
|  |  | 
|  | namespace chromeos_update_engine { | 
|  |  | 
|  | namespace verity_writer { | 
|  | std::unique_ptr<VerityWriterInterface> CreateVerityWriter() { | 
|  | return std::make_unique<VerityWriterAndroid>(); | 
|  | } | 
|  | }  // namespace verity_writer | 
|  |  | 
|  | bool VerityWriterAndroid::Init(const InstallPlan::Partition& partition) { | 
|  | partition_ = &partition; | 
|  |  | 
|  | if (partition_->hash_tree_size != 0) { | 
|  | auto hash_function = | 
|  | HashTreeBuilder::HashFunction(partition_->hash_tree_algorithm); | 
|  | if (hash_function == nullptr) { | 
|  | LOG(ERROR) << "Verity hash algorithm not supported: " | 
|  | << partition_->hash_tree_algorithm; | 
|  | return false; | 
|  | } | 
|  | hash_tree_builder_ = std::make_unique<HashTreeBuilder>( | 
|  | partition_->block_size, hash_function); | 
|  | TEST_AND_RETURN_FALSE(hash_tree_builder_->Initialize( | 
|  | partition_->hash_tree_data_size, partition_->hash_tree_salt)); | 
|  | if (hash_tree_builder_->CalculateSize(partition_->hash_tree_data_size) != | 
|  | partition_->hash_tree_size) { | 
|  | LOG(ERROR) << "Verity hash tree size does not match, stored: " | 
|  | << partition_->hash_tree_size << ", calculated: " | 
|  | << hash_tree_builder_->CalculateSize( | 
|  | partition_->hash_tree_data_size); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerityWriterAndroid::Update(uint64_t offset, | 
|  | const uint8_t* buffer, | 
|  | size_t size) { | 
|  | if (partition_->hash_tree_size != 0) { | 
|  | uint64_t hash_tree_data_end = | 
|  | partition_->hash_tree_data_offset + partition_->hash_tree_data_size; | 
|  | uint64_t start_offset = std::max(offset, partition_->hash_tree_data_offset); | 
|  | uint64_t end_offset = std::min(offset + size, hash_tree_data_end); | 
|  | if (start_offset < end_offset) { | 
|  | TEST_AND_RETURN_FALSE(hash_tree_builder_->Update( | 
|  | buffer + start_offset - offset, end_offset - start_offset)); | 
|  |  | 
|  | if (end_offset == hash_tree_data_end) { | 
|  | // All hash tree data blocks has been hashed, write hash tree to disk. | 
|  | int fd = HANDLE_EINTR(open(partition_->target_path.c_str(), O_WRONLY)); | 
|  | if (fd < 0) { | 
|  | PLOG(ERROR) << "Failed to open " << partition_->target_path | 
|  | << " to write verity data."; | 
|  | return false; | 
|  | } | 
|  | ScopedFdCloser fd_closer(&fd); | 
|  |  | 
|  | LOG(INFO) << "Writing verity hash tree to " << partition_->target_path; | 
|  | TEST_AND_RETURN_FALSE(hash_tree_builder_->BuildHashTree()); | 
|  | TEST_AND_RETURN_FALSE(hash_tree_builder_->WriteHashTreeToFd( | 
|  | fd, partition_->hash_tree_offset)); | 
|  | hash_tree_builder_.reset(); | 
|  | } | 
|  | } | 
|  | } | 
|  | if (partition_->fec_size != 0) { | 
|  | // TODO(senj): Update FEC data. | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace chromeos_update_engine |