125 lines
4.3 KiB
C++
125 lines
4.3 KiB
C++
//
|
|
// Copyright (C) 2021 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
|
|
// limi
|
|
|
|
#include "update_engine/payload_consumer/verified_source_fd.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <base/strings/string_number_conversions.h>
|
|
#include <base/strings/string_util.h>
|
|
#include <base/strings/stringprintf.h>
|
|
|
|
#include "update_engine/common/utils.h"
|
|
#include "update_engine/payload_consumer/fec_file_descriptor.h"
|
|
#include "update_engine/payload_consumer/file_descriptor_utils.h"
|
|
#include "update_engine/payload_consumer/mount_history.h"
|
|
#include "update_engine/payload_consumer/partition_writer.h"
|
|
|
|
namespace chromeos_update_engine {
|
|
using std::string;
|
|
|
|
bool VerifiedSourceFd::OpenCurrentECCPartition() {
|
|
// No support for ECC for full payloads.
|
|
// Full payload should not have any opeartion that requires ECC partitions.
|
|
if (source_ecc_fd_)
|
|
return true;
|
|
|
|
if (source_ecc_open_failure_)
|
|
return false;
|
|
|
|
#if USE_FEC
|
|
FileDescriptorPtr fd(new FecFileDescriptor());
|
|
if (!fd->Open(source_path_.c_str(), O_RDONLY, 0)) {
|
|
PLOG(ERROR) << "Unable to open ECC source partition " << source_path_;
|
|
source_ecc_open_failure_ = true;
|
|
return false;
|
|
}
|
|
source_ecc_fd_ = fd;
|
|
#else
|
|
// No support for ECC compiled.
|
|
source_ecc_open_failure_ = true;
|
|
#endif // USE_FEC
|
|
|
|
return !source_ecc_open_failure_;
|
|
}
|
|
|
|
FileDescriptorPtr VerifiedSourceFd::ChooseSourceFD(
|
|
const InstallOperation& operation, ErrorCode* error) {
|
|
if (source_fd_ == nullptr) {
|
|
LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
|
|
return nullptr;
|
|
}
|
|
if (!operation.has_src_sha256_hash()) {
|
|
// When the operation doesn't include a source hash, we attempt the error
|
|
// corrected device first since we can't verify the block in the raw device
|
|
// at this point, but we first need to make sure all extents are readable
|
|
// since the error corrected device can be shorter or not available.
|
|
if (OpenCurrentECCPartition() &&
|
|
fd_utils::ReadAndHashExtents(
|
|
source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
|
|
return source_ecc_fd_;
|
|
}
|
|
return source_fd_;
|
|
}
|
|
|
|
brillo::Blob source_hash;
|
|
brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
|
|
operation.src_sha256_hash().end());
|
|
if (fd_utils::ReadAndHashExtents(
|
|
source_fd_, operation.src_extents(), block_size_, &source_hash) &&
|
|
source_hash == expected_source_hash) {
|
|
return source_fd_;
|
|
}
|
|
// We fall back to use the error corrected device if the hash of the raw
|
|
// device doesn't match or there was an error reading the source partition.
|
|
if (!OpenCurrentECCPartition()) {
|
|
// The following function call will return false since the source hash
|
|
// mismatches, but we still want to call it so it prints the appropriate
|
|
// log message.
|
|
PartitionWriter::ValidateSourceHash(
|
|
source_hash, operation, source_fd_, error);
|
|
return nullptr;
|
|
}
|
|
LOG(WARNING) << "Source hash from RAW device mismatched: found "
|
|
<< base::HexEncode(source_hash.data(), source_hash.size())
|
|
<< ", expected "
|
|
<< base::HexEncode(expected_source_hash.data(),
|
|
expected_source_hash.size());
|
|
|
|
if (fd_utils::ReadAndHashExtents(
|
|
source_ecc_fd_, operation.src_extents(), block_size_, &source_hash) &&
|
|
PartitionWriter::ValidateSourceHash(
|
|
source_hash, operation, source_ecc_fd_, error)) {
|
|
source_ecc_recovered_failures_++;
|
|
return source_ecc_fd_;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool VerifiedSourceFd::Open() {
|
|
source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
|
|
if (source_fd_ == nullptr)
|
|
return false;
|
|
TEST_AND_RETURN_FALSE_ERRNO(source_fd_->Open(source_path_.c_str(), O_RDONLY));
|
|
return true;
|
|
}
|
|
|
|
} // namespace chromeos_update_engine
|