blob: 002bd07205e1aac4812f56aa1743a0de2673c746 [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
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
35namespace chromeos_update_engine {
36using std::string;
37
38bool 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
63FileDescriptorPtr 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
116bool 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