blob: f35b6a9189481c759c85f42268cee2236ccaf294 [file] [log] [blame]
Kelvin Zhangab3ce602021-02-24 14:46:40 -05001//
2// Copyright (C) 2021 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limi
15
16#include "update_engine/payload_consumer/verified_source_fd.h"
17
18#include <fcntl.h>
19#include <sys/stat.h>
20
21#include <memory>
22#include <utility>
23#include <vector>
24
25#include <base/strings/string_number_conversions.h>
26#include <base/strings/string_util.h>
27#include <base/strings/stringprintf.h>
28
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070029#include "update_engine/common/error_code.h"
30#include "update_engine/common/hash_calculator.h"
Kelvin Zhangab3ce602021-02-24 14:46:40 -050031#include "update_engine/common/utils.h"
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070032#include "update_engine/payload_consumer/extent_writer.h"
33#include "update_engine/payload_consumer/file_descriptor.h"
Kelvin Zhangab3ce602021-02-24 14:46:40 -050034#include "update_engine/payload_consumer/file_descriptor_utils.h"
Kelvin Zhangab3ce602021-02-24 14:46:40 -050035#include "update_engine/payload_consumer/partition_writer.h"
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070036#include "update_engine/update_metadata.pb.h"
37#if USE_FEC
38#include "update_engine/payload_consumer/fec_file_descriptor.h"
39#endif
Kelvin Zhangab3ce602021-02-24 14:46:40 -050040
41namespace chromeos_update_engine {
42using std::string;
43
44bool VerifiedSourceFd::OpenCurrentECCPartition() {
45 // No support for ECC for full payloads.
46 // Full payload should not have any opeartion that requires ECC partitions.
47 if (source_ecc_fd_)
48 return true;
49
50 if (source_ecc_open_failure_)
51 return false;
52
53#if USE_FEC
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070054 auto fd = std::make_shared<FecFileDescriptor>();
Kelvin Zhangab3ce602021-02-24 14:46:40 -050055 if (!fd->Open(source_path_.c_str(), O_RDONLY, 0)) {
56 PLOG(ERROR) << "Unable to open ECC source partition " << source_path_;
57 source_ecc_open_failure_ = true;
58 return false;
59 }
60 source_ecc_fd_ = fd;
61#else
62 // No support for ECC compiled.
63 source_ecc_open_failure_ = true;
64#endif // USE_FEC
65
66 return !source_ecc_open_failure_;
67}
68
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070069bool VerifiedSourceFd::WriteBackCorrectedSourceBlocks(
70 const std::vector<unsigned char>& source_data,
71 const google::protobuf::RepeatedPtrField<Extent>& extents) {
72 auto fd = std::make_shared<EintrSafeFileDescriptor>();
73 TEST_AND_RETURN_FALSE_ERRNO(fd->Open(source_path_.c_str(), O_RDWR));
74 DirectExtentWriter writer(fd);
75 TEST_AND_RETURN_FALSE(writer.Init(extents, block_size_));
76 return writer.Write(source_data.data(), source_data.size());
77}
78
Kelvin Zhangab3ce602021-02-24 14:46:40 -050079FileDescriptorPtr VerifiedSourceFd::ChooseSourceFD(
80 const InstallOperation& operation, ErrorCode* error) {
81 if (source_fd_ == nullptr) {
82 LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
83 return nullptr;
84 }
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070085 if (error) {
86 *error = ErrorCode::kSuccess;
87 }
Kelvin Zhangab3ce602021-02-24 14:46:40 -050088 if (!operation.has_src_sha256_hash()) {
89 // When the operation doesn't include a source hash, we attempt the error
90 // corrected device first since we can't verify the block in the raw device
91 // at this point, but we first need to make sure all extents are readable
92 // since the error corrected device can be shorter or not available.
93 if (OpenCurrentECCPartition() &&
94 fd_utils::ReadAndHashExtents(
95 source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -070096 if (error) {
97 *error = ErrorCode::kDownloadOperationHashMissingError;
98 }
Kelvin Zhangab3ce602021-02-24 14:46:40 -050099 return source_ecc_fd_;
100 }
101 return source_fd_;
102 }
103
104 brillo::Blob source_hash;
105 brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
106 operation.src_sha256_hash().end());
107 if (fd_utils::ReadAndHashExtents(
108 source_fd_, operation.src_extents(), block_size_, &source_hash) &&
109 source_hash == expected_source_hash) {
110 return source_fd_;
111 }
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -0700112 if (error) {
113 *error = ErrorCode::kDownloadOperationHashMismatch;
114 }
Kelvin Zhangab3ce602021-02-24 14:46:40 -0500115 // We fall back to use the error corrected device if the hash of the raw
116 // device doesn't match or there was an error reading the source partition.
117 if (!OpenCurrentECCPartition()) {
118 // The following function call will return false since the source hash
119 // mismatches, but we still want to call it so it prints the appropriate
120 // log message.
121 PartitionWriter::ValidateSourceHash(
122 source_hash, operation, source_fd_, error);
123 return nullptr;
124 }
125 LOG(WARNING) << "Source hash from RAW device mismatched: found "
126 << base::HexEncode(source_hash.data(), source_hash.size())
127 << ", expected "
128 << base::HexEncode(expected_source_hash.data(),
129 expected_source_hash.size());
130
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -0700131 std::vector<unsigned char> source_data;
132 if (!utils::ReadExtents(
133 source_ecc_fd_, operation.src_extents(), &source_data, block_size_)) {
134 return nullptr;
135 }
136 if (!HashCalculator::RawHashOfData(source_data, &source_hash)) {
137 return nullptr;
138 }
139 if (PartitionWriter::ValidateSourceHash(
Kelvin Zhangab3ce602021-02-24 14:46:40 -0500140 source_hash, operation, source_ecc_fd_, error)) {
141 source_ecc_recovered_failures_++;
Kelvin Zhang7dd5a5e2023-05-11 15:30:38 -0700142 if (WriteBackCorrectedSourceBlocks(source_data, operation.src_extents())) {
143 if (error) {
144 *error = ErrorCode::kSuccess;
145 }
146 return source_fd_;
147 }
Kelvin Zhangab3ce602021-02-24 14:46:40 -0500148 return source_ecc_fd_;
149 }
150 return nullptr;
151}
152
153bool VerifiedSourceFd::Open() {
154 source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
155 if (source_fd_ == nullptr)
156 return false;
157 TEST_AND_RETURN_FALSE_ERRNO(source_fd_->Open(source_path_.c_str(), O_RDONLY));
158 return true;
159}
160
161} // namespace chromeos_update_engine