• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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