1 //
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
29 #include "update_engine/common/utils.h"
30 #include "update_engine/payload_consumer/fec_file_descriptor.h"
31 #include "update_engine/payload_consumer/file_descriptor_utils.h"
32 #include "update_engine/payload_consumer/mount_history.h"
33 #include "update_engine/payload_consumer/partition_writer.h"
34
35 namespace chromeos_update_engine {
36 using std::string;
37
OpenCurrentECCPartition()38 bool VerifiedSourceFd::OpenCurrentECCPartition() {
39 // No support for ECC for full payloads.
40 // Full payload should not have any opeartion that requires ECC partitions.
41 if (source_ecc_fd_)
42 return true;
43
44 if (source_ecc_open_failure_)
45 return false;
46
47 #if USE_FEC
48 FileDescriptorPtr fd(new FecFileDescriptor());
49 if (!fd->Open(source_path_.c_str(), O_RDONLY, 0)) {
50 PLOG(ERROR) << "Unable to open ECC source partition " << source_path_;
51 source_ecc_open_failure_ = true;
52 return false;
53 }
54 source_ecc_fd_ = fd;
55 #else
56 // No support for ECC compiled.
57 source_ecc_open_failure_ = true;
58 #endif // USE_FEC
59
60 return !source_ecc_open_failure_;
61 }
62
ChooseSourceFD(const InstallOperation & operation,ErrorCode * error)63 FileDescriptorPtr VerifiedSourceFd::ChooseSourceFD(
64 const InstallOperation& operation, ErrorCode* error) {
65 if (source_fd_ == nullptr) {
66 LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
67 return nullptr;
68 }
69 if (!operation.has_src_sha256_hash()) {
70 // When the operation doesn't include a source hash, we attempt the error
71 // corrected device first since we can't verify the block in the raw device
72 // at this point, but we first need to make sure all extents are readable
73 // since the error corrected device can be shorter or not available.
74 if (OpenCurrentECCPartition() &&
75 fd_utils::ReadAndHashExtents(
76 source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
77 return source_ecc_fd_;
78 }
79 return source_fd_;
80 }
81
82 brillo::Blob source_hash;
83 brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
84 operation.src_sha256_hash().end());
85 if (fd_utils::ReadAndHashExtents(
86 source_fd_, operation.src_extents(), block_size_, &source_hash) &&
87 source_hash == expected_source_hash) {
88 return source_fd_;
89 }
90 // We fall back to use the error corrected device if the hash of the raw
91 // device doesn't match or there was an error reading the source partition.
92 if (!OpenCurrentECCPartition()) {
93 // The following function call will return false since the source hash
94 // mismatches, but we still want to call it so it prints the appropriate
95 // log message.
96 PartitionWriter::ValidateSourceHash(
97 source_hash, operation, source_fd_, error);
98 return nullptr;
99 }
100 LOG(WARNING) << "Source hash from RAW device mismatched: found "
101 << base::HexEncode(source_hash.data(), source_hash.size())
102 << ", expected "
103 << base::HexEncode(expected_source_hash.data(),
104 expected_source_hash.size());
105
106 if (fd_utils::ReadAndHashExtents(
107 source_ecc_fd_, operation.src_extents(), block_size_, &source_hash) &&
108 PartitionWriter::ValidateSourceHash(
109 source_hash, operation, source_ecc_fd_, error)) {
110 source_ecc_recovered_failures_++;
111 return source_ecc_fd_;
112 }
113 return nullptr;
114 }
115
Open()116 bool VerifiedSourceFd::Open() {
117 source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
118 if (source_fd_ == nullptr)
119 return false;
120 TEST_AND_RETURN_FALSE_ERRNO(source_fd_->Open(source_path_.c_str(), O_RDONLY));
121 return true;
122 }
123
124 } // namespace chromeos_update_engine
125