xref: /aosp_15_r20/external/zucchini/patch_reader.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/patch_reader.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <type_traits>
8*a03ca8b9SKrzysztof Kosiński #include <utility>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include "base/numerics/safe_conversions.h"
11*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/algorithm.h"
12*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/crc32.h"
13*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/element_detection.h"
14*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/version_info.h"
15*a03ca8b9SKrzysztof Kosiński 
16*a03ca8b9SKrzysztof Kosiński namespace zucchini {
17*a03ca8b9SKrzysztof Kosiński 
18*a03ca8b9SKrzysztof Kosiński namespace patch {
19*a03ca8b9SKrzysztof Kosiński 
ParseElementMatch(BufferSource * source,ElementMatch * element_match)20*a03ca8b9SKrzysztof Kosiński bool ParseElementMatch(BufferSource* source, ElementMatch* element_match) {
21*a03ca8b9SKrzysztof Kosiński   PatchElementHeader unsafe_element_header;
22*a03ca8b9SKrzysztof Kosiński   if (!source->GetValue(&unsafe_element_header)) {
23*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Impossible to read ElementMatch from source.";
24*a03ca8b9SKrzysztof Kosiński     return false;
25*a03ca8b9SKrzysztof Kosiński   }
26*a03ca8b9SKrzysztof Kosiński   ExecutableType exe_type =
27*a03ca8b9SKrzysztof Kosiński       CastToExecutableType(unsafe_element_header.exe_type);
28*a03ca8b9SKrzysztof Kosiński   if (exe_type == kExeTypeUnknown) {
29*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Invalid ExecutableType found.";
30*a03ca8b9SKrzysztof Kosiński     return false;
31*a03ca8b9SKrzysztof Kosiński   }
32*a03ca8b9SKrzysztof Kosiński   uint16_t element_version = DisassemblerVersionOfType(exe_type);
33*a03ca8b9SKrzysztof Kosiński   if (element_version != unsafe_element_header.version) {
34*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Element version doesn't match. Expected: " << element_version
35*a03ca8b9SKrzysztof Kosiński                << ", Actual:" << unsafe_element_header.version;
36*a03ca8b9SKrzysztof Kosiński     return false;
37*a03ca8b9SKrzysztof Kosiński   }
38*a03ca8b9SKrzysztof Kosiński   if (!unsafe_element_header.old_length || !unsafe_element_header.new_length) {
39*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Empty patch element found.";
40*a03ca8b9SKrzysztof Kosiński     return false;
41*a03ca8b9SKrzysztof Kosiński   }
42*a03ca8b9SKrzysztof Kosiński   // |unsafe_element_header| is now considered to be safe as it has a valid
43*a03ca8b9SKrzysztof Kosiński   // |exe_type| and the length fields are of sufficient size.
44*a03ca8b9SKrzysztof Kosiński   const auto& element_header = unsafe_element_header;
45*a03ca8b9SKrzysztof Kosiński 
46*a03ca8b9SKrzysztof Kosiński   // Caveat: Element offsets and lengths can still be invalid (e.g., exceeding
47*a03ca8b9SKrzysztof Kosiński   // archive bounds), but this will be checked later.
48*a03ca8b9SKrzysztof Kosiński   element_match->old_element.offset = element_header.old_offset;
49*a03ca8b9SKrzysztof Kosiński   element_match->old_element.size = element_header.old_length;
50*a03ca8b9SKrzysztof Kosiński   element_match->new_element.offset = element_header.new_offset;
51*a03ca8b9SKrzysztof Kosiński   element_match->new_element.size = element_header.new_length;
52*a03ca8b9SKrzysztof Kosiński   element_match->old_element.exe_type = exe_type;
53*a03ca8b9SKrzysztof Kosiński   element_match->new_element.exe_type = exe_type;
54*a03ca8b9SKrzysztof Kosiński   return true;
55*a03ca8b9SKrzysztof Kosiński }
56*a03ca8b9SKrzysztof Kosiński 
ParseBuffer(BufferSource * source,BufferSource * buffer)57*a03ca8b9SKrzysztof Kosiński bool ParseBuffer(BufferSource* source, BufferSource* buffer) {
58*a03ca8b9SKrzysztof Kosiński   uint32_t unsafe_size = 0;  // Bytes.
59*a03ca8b9SKrzysztof Kosiński   static_assert(sizeof(size_t) >= sizeof(unsafe_size),
60*a03ca8b9SKrzysztof Kosiński                 "size_t is expected to be larger than uint32_t.");
61*a03ca8b9SKrzysztof Kosiński   if (!source->GetValue(&unsafe_size)) {
62*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Impossible to read buffer size from source.";
63*a03ca8b9SKrzysztof Kosiński     return false;
64*a03ca8b9SKrzysztof Kosiński   }
65*a03ca8b9SKrzysztof Kosiński   if (!source->GetRegion(static_cast<size_t>(unsafe_size), buffer)) {
66*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Impossible to read buffer content from source.";
67*a03ca8b9SKrzysztof Kosiński     return false;
68*a03ca8b9SKrzysztof Kosiński   }
69*a03ca8b9SKrzysztof Kosiński   // Caveat: |buffer| is considered to be safe as it was possible to extract it
70*a03ca8b9SKrzysztof Kosiński   // from the patch. However, this does not mean its contents are safe and when
71*a03ca8b9SKrzysztof Kosiński   // parsed must be validated if possible.
72*a03ca8b9SKrzysztof Kosiński   return true;
73*a03ca8b9SKrzysztof Kosiński }
74*a03ca8b9SKrzysztof Kosiński 
75*a03ca8b9SKrzysztof Kosiński }  // namespace patch
76*a03ca8b9SKrzysztof Kosiński 
77*a03ca8b9SKrzysztof Kosiński /******** EquivalenceSource ********/
78*a03ca8b9SKrzysztof Kosiński 
79*a03ca8b9SKrzysztof Kosiński EquivalenceSource::EquivalenceSource() = default;
80*a03ca8b9SKrzysztof Kosiński EquivalenceSource::EquivalenceSource(const EquivalenceSource&) = default;
81*a03ca8b9SKrzysztof Kosiński EquivalenceSource::~EquivalenceSource() = default;
82*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)83*a03ca8b9SKrzysztof Kosiński bool EquivalenceSource::Initialize(BufferSource* source) {
84*a03ca8b9SKrzysztof Kosiński   return patch::ParseBuffer(source, &src_skip_) &&
85*a03ca8b9SKrzysztof Kosiński          patch::ParseBuffer(source, &dst_skip_) &&
86*a03ca8b9SKrzysztof Kosiński          patch::ParseBuffer(source, &copy_count_);
87*a03ca8b9SKrzysztof Kosiński }
88*a03ca8b9SKrzysztof Kosiński 
GetNext()89*a03ca8b9SKrzysztof Kosiński std::optional<Equivalence> EquivalenceSource::GetNext() {
90*a03ca8b9SKrzysztof Kosiński   if (src_skip_.empty() || dst_skip_.empty() || copy_count_.empty())
91*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
92*a03ca8b9SKrzysztof Kosiński 
93*a03ca8b9SKrzysztof Kosiński   Equivalence equivalence = {};
94*a03ca8b9SKrzysztof Kosiński 
95*a03ca8b9SKrzysztof Kosiński   uint32_t length = 0;
96*a03ca8b9SKrzysztof Kosiński   if (!patch::ParseVarUInt<uint32_t>(&copy_count_, &length))
97*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
98*a03ca8b9SKrzysztof Kosiński   equivalence.length = base::strict_cast<offset_t>(length);
99*a03ca8b9SKrzysztof Kosiński 
100*a03ca8b9SKrzysztof Kosiński   int32_t src_offset_diff = 0;  // Intentionally signed.
101*a03ca8b9SKrzysztof Kosiński   if (!patch::ParseVarInt<int32_t>(&src_skip_, &src_offset_diff))
102*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
103*a03ca8b9SKrzysztof Kosiński   base::CheckedNumeric<offset_t> src_offset =
104*a03ca8b9SKrzysztof Kosiński       previous_src_offset_ + src_offset_diff;
105*a03ca8b9SKrzysztof Kosiński   if (!src_offset.IsValid())
106*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
107*a03ca8b9SKrzysztof Kosiński 
108*a03ca8b9SKrzysztof Kosiński   equivalence.src_offset = src_offset.ValueOrDie();
109*a03ca8b9SKrzysztof Kosiński   previous_src_offset_ = src_offset + equivalence.length;
110*a03ca8b9SKrzysztof Kosiński   if (!previous_src_offset_.IsValid())
111*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
112*a03ca8b9SKrzysztof Kosiński 
113*a03ca8b9SKrzysztof Kosiński   uint32_t dst_offset_diff = 0;  // Intentionally unsigned.
114*a03ca8b9SKrzysztof Kosiński   if (!patch::ParseVarUInt<uint32_t>(&dst_skip_, &dst_offset_diff))
115*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
116*a03ca8b9SKrzysztof Kosiński   base::CheckedNumeric<offset_t> dst_offset =
117*a03ca8b9SKrzysztof Kosiński       previous_dst_offset_ + dst_offset_diff;
118*a03ca8b9SKrzysztof Kosiński   if (!dst_offset.IsValid())
119*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
120*a03ca8b9SKrzysztof Kosiński 
121*a03ca8b9SKrzysztof Kosiński   equivalence.dst_offset = dst_offset.ValueOrDie();
122*a03ca8b9SKrzysztof Kosiński   previous_dst_offset_ = equivalence.dst_offset + equivalence.length;
123*a03ca8b9SKrzysztof Kosiński   if (!previous_dst_offset_.IsValid())
124*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
125*a03ca8b9SKrzysztof Kosiński 
126*a03ca8b9SKrzysztof Kosiński   // Caveat: |equivalence| is assumed to be safe only once the
127*a03ca8b9SKrzysztof Kosiński   // ValidateEquivalencesAndExtraData() method has returned true. Prior to this
128*a03ca8b9SKrzysztof Kosiński   // any equivalence returned is assumed to be unsafe.
129*a03ca8b9SKrzysztof Kosiński   return equivalence;
130*a03ca8b9SKrzysztof Kosiński }
131*a03ca8b9SKrzysztof Kosiński 
132*a03ca8b9SKrzysztof Kosiński /******** ExtraDataSource ********/
133*a03ca8b9SKrzysztof Kosiński 
134*a03ca8b9SKrzysztof Kosiński ExtraDataSource::ExtraDataSource() = default;
135*a03ca8b9SKrzysztof Kosiński ExtraDataSource::ExtraDataSource(const ExtraDataSource&) = default;
136*a03ca8b9SKrzysztof Kosiński ExtraDataSource::~ExtraDataSource() = default;
137*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)138*a03ca8b9SKrzysztof Kosiński bool ExtraDataSource::Initialize(BufferSource* source) {
139*a03ca8b9SKrzysztof Kosiński   return patch::ParseBuffer(source, &extra_data_);
140*a03ca8b9SKrzysztof Kosiński }
141*a03ca8b9SKrzysztof Kosiński 
GetNext(offset_t size)142*a03ca8b9SKrzysztof Kosiński std::optional<ConstBufferView> ExtraDataSource::GetNext(offset_t size) {
143*a03ca8b9SKrzysztof Kosiński   ConstBufferView buffer;
144*a03ca8b9SKrzysztof Kosiński   if (!extra_data_.GetRegion(size, &buffer))
145*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
146*a03ca8b9SKrzysztof Kosiński   // |buffer| is assumed to always be safe/valid.
147*a03ca8b9SKrzysztof Kosiński   return buffer;
148*a03ca8b9SKrzysztof Kosiński }
149*a03ca8b9SKrzysztof Kosiński 
150*a03ca8b9SKrzysztof Kosiński /******** RawDeltaSource ********/
151*a03ca8b9SKrzysztof Kosiński 
152*a03ca8b9SKrzysztof Kosiński RawDeltaSource::RawDeltaSource() = default;
153*a03ca8b9SKrzysztof Kosiński RawDeltaSource::RawDeltaSource(const RawDeltaSource&) = default;
154*a03ca8b9SKrzysztof Kosiński RawDeltaSource::~RawDeltaSource() = default;
155*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)156*a03ca8b9SKrzysztof Kosiński bool RawDeltaSource::Initialize(BufferSource* source) {
157*a03ca8b9SKrzysztof Kosiński   return patch::ParseBuffer(source, &raw_delta_skip_) &&
158*a03ca8b9SKrzysztof Kosiński          patch::ParseBuffer(source, &raw_delta_diff_);
159*a03ca8b9SKrzysztof Kosiński }
160*a03ca8b9SKrzysztof Kosiński 
GetNext()161*a03ca8b9SKrzysztof Kosiński std::optional<RawDeltaUnit> RawDeltaSource::GetNext() {
162*a03ca8b9SKrzysztof Kosiński   if (raw_delta_skip_.empty() || raw_delta_diff_.empty())
163*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
164*a03ca8b9SKrzysztof Kosiński 
165*a03ca8b9SKrzysztof Kosiński   RawDeltaUnit raw_delta = {};
166*a03ca8b9SKrzysztof Kosiński   uint32_t copy_offset_diff = 0;
167*a03ca8b9SKrzysztof Kosiński   if (!patch::ParseVarUInt<uint32_t>(&raw_delta_skip_, &copy_offset_diff))
168*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
169*a03ca8b9SKrzysztof Kosiński   base::CheckedNumeric<offset_t> copy_offset =
170*a03ca8b9SKrzysztof Kosiński       copy_offset_diff + copy_offset_compensation_;
171*a03ca8b9SKrzysztof Kosiński   if (!copy_offset.IsValid())
172*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
173*a03ca8b9SKrzysztof Kosiński   raw_delta.copy_offset = copy_offset.ValueOrDie();
174*a03ca8b9SKrzysztof Kosiński 
175*a03ca8b9SKrzysztof Kosiński   if (!raw_delta_diff_.GetValue<int8_t>(&raw_delta.diff))
176*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
177*a03ca8b9SKrzysztof Kosiński 
178*a03ca8b9SKrzysztof Kosiński   // A 0 value for a delta.diff is considered invalid since it has no meaning.
179*a03ca8b9SKrzysztof Kosiński   if (!raw_delta.diff)
180*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
181*a03ca8b9SKrzysztof Kosiński 
182*a03ca8b9SKrzysztof Kosiński   // We keep track of the compensation needed for next offset, taking into
183*a03ca8b9SKrzysztof Kosiński   // account delta encoding and bias of -1.
184*a03ca8b9SKrzysztof Kosiński   copy_offset_compensation_ = copy_offset + 1;
185*a03ca8b9SKrzysztof Kosiński   if (!copy_offset_compensation_.IsValid())
186*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
187*a03ca8b9SKrzysztof Kosiński   // |raw_delta| is assumed to always be safe/valid.
188*a03ca8b9SKrzysztof Kosiński   return raw_delta;
189*a03ca8b9SKrzysztof Kosiński }
190*a03ca8b9SKrzysztof Kosiński 
191*a03ca8b9SKrzysztof Kosiński /******** ReferenceDeltaSource ********/
192*a03ca8b9SKrzysztof Kosiński 
193*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource::ReferenceDeltaSource() = default;
194*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource::ReferenceDeltaSource(const ReferenceDeltaSource&) =
195*a03ca8b9SKrzysztof Kosiński     default;
196*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource::~ReferenceDeltaSource() = default;
197*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)198*a03ca8b9SKrzysztof Kosiński bool ReferenceDeltaSource::Initialize(BufferSource* source) {
199*a03ca8b9SKrzysztof Kosiński   return patch::ParseBuffer(source, &source_);
200*a03ca8b9SKrzysztof Kosiński }
201*a03ca8b9SKrzysztof Kosiński 
GetNext()202*a03ca8b9SKrzysztof Kosiński std::optional<int32_t> ReferenceDeltaSource::GetNext() {
203*a03ca8b9SKrzysztof Kosiński   if (source_.empty())
204*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
205*a03ca8b9SKrzysztof Kosiński   int32_t ref_delta = 0;
206*a03ca8b9SKrzysztof Kosiński   if (!patch::ParseVarInt<int32_t>(&source_, &ref_delta))
207*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
208*a03ca8b9SKrzysztof Kosiński   // |ref_delta| is assumed to always be safe/valid.
209*a03ca8b9SKrzysztof Kosiński   return ref_delta;
210*a03ca8b9SKrzysztof Kosiński }
211*a03ca8b9SKrzysztof Kosiński 
212*a03ca8b9SKrzysztof Kosiński /******** TargetSource ********/
213*a03ca8b9SKrzysztof Kosiński 
214*a03ca8b9SKrzysztof Kosiński TargetSource::TargetSource() = default;
215*a03ca8b9SKrzysztof Kosiński TargetSource::TargetSource(const TargetSource&) = default;
216*a03ca8b9SKrzysztof Kosiński TargetSource::~TargetSource() = default;
217*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)218*a03ca8b9SKrzysztof Kosiński bool TargetSource::Initialize(BufferSource* source) {
219*a03ca8b9SKrzysztof Kosiński   return patch::ParseBuffer(source, &extra_targets_);
220*a03ca8b9SKrzysztof Kosiński }
221*a03ca8b9SKrzysztof Kosiński 
GetNext()222*a03ca8b9SKrzysztof Kosiński std::optional<offset_t> TargetSource::GetNext() {
223*a03ca8b9SKrzysztof Kosiński   if (extra_targets_.empty())
224*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
225*a03ca8b9SKrzysztof Kosiński 
226*a03ca8b9SKrzysztof Kosiński   uint32_t target_diff = 0;
227*a03ca8b9SKrzysztof Kosiński   if (!patch::ParseVarUInt<uint32_t>(&extra_targets_, &target_diff))
228*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
229*a03ca8b9SKrzysztof Kosiński   base::CheckedNumeric<offset_t> target = target_diff + target_compensation_;
230*a03ca8b9SKrzysztof Kosiński   if (!target.IsValid())
231*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
232*a03ca8b9SKrzysztof Kosiński 
233*a03ca8b9SKrzysztof Kosiński   // We keep track of the compensation needed for next target, taking into
234*a03ca8b9SKrzysztof Kosiński   // account delta encoding and bias of -1.
235*a03ca8b9SKrzysztof Kosiński   target_compensation_ = target + 1;
236*a03ca8b9SKrzysztof Kosiński   if (!target_compensation_.IsValid())
237*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
238*a03ca8b9SKrzysztof Kosiński   // Caveat: |target| will be a valid offset_t, but it's up to the caller to
239*a03ca8b9SKrzysztof Kosiński   // check whether it's a valid offset for an image.
240*a03ca8b9SKrzysztof Kosiński   return offset_t(target.ValueOrDie());
241*a03ca8b9SKrzysztof Kosiński }
242*a03ca8b9SKrzysztof Kosiński 
243*a03ca8b9SKrzysztof Kosiński /******** PatchElementReader ********/
244*a03ca8b9SKrzysztof Kosiński 
245*a03ca8b9SKrzysztof Kosiński PatchElementReader::PatchElementReader() = default;
246*a03ca8b9SKrzysztof Kosiński PatchElementReader::PatchElementReader(PatchElementReader&&) = default;
247*a03ca8b9SKrzysztof Kosiński PatchElementReader::~PatchElementReader() = default;
248*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)249*a03ca8b9SKrzysztof Kosiński bool PatchElementReader::Initialize(BufferSource* source) {
250*a03ca8b9SKrzysztof Kosiński   bool ok =
251*a03ca8b9SKrzysztof Kosiński       patch::ParseElementMatch(source, &element_match_) &&
252*a03ca8b9SKrzysztof Kosiński       equivalences_.Initialize(source) && extra_data_.Initialize(source) &&
253*a03ca8b9SKrzysztof Kosiński       ValidateEquivalencesAndExtraData() && raw_delta_.Initialize(source) &&
254*a03ca8b9SKrzysztof Kosiński       reference_delta_.Initialize(source);
255*a03ca8b9SKrzysztof Kosiński   if (!ok)
256*a03ca8b9SKrzysztof Kosiński     return false;
257*a03ca8b9SKrzysztof Kosiński   uint32_t pool_count = 0;
258*a03ca8b9SKrzysztof Kosiński   if (!source->GetValue(&pool_count)) {
259*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Impossible to read pool_count from source.";
260*a03ca8b9SKrzysztof Kosiński     return false;
261*a03ca8b9SKrzysztof Kosiński   }
262*a03ca8b9SKrzysztof Kosiński   for (uint32_t i = 0; i < pool_count; ++i) {
263*a03ca8b9SKrzysztof Kosiński     uint8_t pool_tag_value = 0;
264*a03ca8b9SKrzysztof Kosiński     if (!source->GetValue(&pool_tag_value)) {
265*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Impossible to read pool_tag from source.";
266*a03ca8b9SKrzysztof Kosiński       return false;
267*a03ca8b9SKrzysztof Kosiński     }
268*a03ca8b9SKrzysztof Kosiński     PoolTag pool_tag(pool_tag_value);
269*a03ca8b9SKrzysztof Kosiński     if (pool_tag == kNoPoolTag) {
270*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Invalid pool_tag encountered in ExtraTargetList.";
271*a03ca8b9SKrzysztof Kosiński       return false;
272*a03ca8b9SKrzysztof Kosiński     }
273*a03ca8b9SKrzysztof Kosiński     auto insert_result = extra_targets_.insert({pool_tag, {}});
274*a03ca8b9SKrzysztof Kosiński     if (!insert_result.second) {  // Element already present.
275*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Multiple ExtraTargetList found for the same pool_tag.";
276*a03ca8b9SKrzysztof Kosiński       return false;
277*a03ca8b9SKrzysztof Kosiński     }
278*a03ca8b9SKrzysztof Kosiński     if (!insert_result.first->second.Initialize(source))
279*a03ca8b9SKrzysztof Kosiński       return false;
280*a03ca8b9SKrzysztof Kosiński   }
281*a03ca8b9SKrzysztof Kosiński   return true;
282*a03ca8b9SKrzysztof Kosiński }
283*a03ca8b9SKrzysztof Kosiński 
ValidateEquivalencesAndExtraData()284*a03ca8b9SKrzysztof Kosiński bool PatchElementReader::ValidateEquivalencesAndExtraData() {
285*a03ca8b9SKrzysztof Kosiński   EquivalenceSource equivalences_copy = equivalences_;
286*a03ca8b9SKrzysztof Kosiński 
287*a03ca8b9SKrzysztof Kosiński   const size_t old_region_size = element_match_.old_element.size;
288*a03ca8b9SKrzysztof Kosiński   const size_t new_region_size = element_match_.new_element.size;
289*a03ca8b9SKrzysztof Kosiński 
290*a03ca8b9SKrzysztof Kosiński   base::CheckedNumeric<uint32_t> total_length = 0;
291*a03ca8b9SKrzysztof Kosiński   // Validate that each |equivalence| falls within the bounds of the
292*a03ca8b9SKrzysztof Kosiński   // |element_match_| and are in order.
293*a03ca8b9SKrzysztof Kosiński   offset_t prev_dst_end = 0;
294*a03ca8b9SKrzysztof Kosiński   for (auto equivalence = equivalences_copy.GetNext(); equivalence.has_value();
295*a03ca8b9SKrzysztof Kosiński        equivalence = equivalences_copy.GetNext()) {
296*a03ca8b9SKrzysztof Kosiński     if (!RangeIsBounded(equivalence->src_offset, equivalence->length,
297*a03ca8b9SKrzysztof Kosiński                         old_region_size) ||
298*a03ca8b9SKrzysztof Kosiński         !RangeIsBounded(equivalence->dst_offset, equivalence->length,
299*a03ca8b9SKrzysztof Kosiński                         new_region_size)) {
300*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Out of bounds equivalence detected.";
301*a03ca8b9SKrzysztof Kosiński       return false;
302*a03ca8b9SKrzysztof Kosiński     }
303*a03ca8b9SKrzysztof Kosiński     if (prev_dst_end > equivalence->dst_end()) {
304*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Out of order equivalence detected.";
305*a03ca8b9SKrzysztof Kosiński       return false;
306*a03ca8b9SKrzysztof Kosiński     }
307*a03ca8b9SKrzysztof Kosiński     prev_dst_end = equivalence->dst_end();
308*a03ca8b9SKrzysztof Kosiński     total_length += equivalence->length;
309*a03ca8b9SKrzysztof Kosiński   }
310*a03ca8b9SKrzysztof Kosiński   if (!total_length.IsValid() ||
311*a03ca8b9SKrzysztof Kosiński       element_match_.new_element.region().size < total_length.ValueOrDie() ||
312*a03ca8b9SKrzysztof Kosiński       extra_data_.extra_data().size() !=
313*a03ca8b9SKrzysztof Kosiński           element_match_.new_element.region().size -
314*a03ca8b9SKrzysztof Kosiński               static_cast<size_t>(total_length.ValueOrDie())) {
315*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Incorrect amount of extra_data.";
316*a03ca8b9SKrzysztof Kosiński     return false;
317*a03ca8b9SKrzysztof Kosiński   }
318*a03ca8b9SKrzysztof Kosiński   return true;
319*a03ca8b9SKrzysztof Kosiński }
320*a03ca8b9SKrzysztof Kosiński 
321*a03ca8b9SKrzysztof Kosiński /******** EnsemblePatchReader ********/
322*a03ca8b9SKrzysztof Kosiński 
Create(ConstBufferView buffer)323*a03ca8b9SKrzysztof Kosiński std::optional<EnsemblePatchReader> EnsemblePatchReader::Create(
324*a03ca8b9SKrzysztof Kosiński     ConstBufferView buffer) {
325*a03ca8b9SKrzysztof Kosiński   BufferSource source(buffer);
326*a03ca8b9SKrzysztof Kosiński   EnsemblePatchReader patch;
327*a03ca8b9SKrzysztof Kosiński   if (!patch.Initialize(&source))
328*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
329*a03ca8b9SKrzysztof Kosiński   return patch;
330*a03ca8b9SKrzysztof Kosiński }
331*a03ca8b9SKrzysztof Kosiński 
332*a03ca8b9SKrzysztof Kosiński EnsemblePatchReader::EnsemblePatchReader() = default;
333*a03ca8b9SKrzysztof Kosiński EnsemblePatchReader::EnsemblePatchReader(EnsemblePatchReader&&) = default;
334*a03ca8b9SKrzysztof Kosiński EnsemblePatchReader::~EnsemblePatchReader() = default;
335*a03ca8b9SKrzysztof Kosiński 
Initialize(BufferSource * source)336*a03ca8b9SKrzysztof Kosiński bool EnsemblePatchReader::Initialize(BufferSource* source) {
337*a03ca8b9SKrzysztof Kosiński   if (!source->GetValue(&header_)) {
338*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Impossible to read header from source.";
339*a03ca8b9SKrzysztof Kosiński     return false;
340*a03ca8b9SKrzysztof Kosiński   }
341*a03ca8b9SKrzysztof Kosiński   if (header_.magic != PatchHeader::kMagic) {
342*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Patch contains invalid magic.";
343*a03ca8b9SKrzysztof Kosiński     return false;
344*a03ca8b9SKrzysztof Kosiński   }
345*a03ca8b9SKrzysztof Kosiński   if (header_.major_version != kMajorVersion) {
346*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Patch major version doesn't match. Expected: "
347*a03ca8b9SKrzysztof Kosiński                << kMajorVersion << ", Actual:" << header_.major_version;
348*a03ca8b9SKrzysztof Kosiński     return false;
349*a03ca8b9SKrzysztof Kosiński   }
350*a03ca8b9SKrzysztof Kosiński   // |header_| is assumed to be safe from this point forward.
351*a03ca8b9SKrzysztof Kosiński 
352*a03ca8b9SKrzysztof Kosiński   uint32_t element_count = 0;
353*a03ca8b9SKrzysztof Kosiński   if (!source->GetValue(&element_count)) {
354*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Impossible to read element_count from source.";
355*a03ca8b9SKrzysztof Kosiński     return false;
356*a03ca8b9SKrzysztof Kosiński   }
357*a03ca8b9SKrzysztof Kosiński 
358*a03ca8b9SKrzysztof Kosiński   offset_t current_dst_offset = 0;
359*a03ca8b9SKrzysztof Kosiński   for (uint32_t i = 0; i < element_count; ++i) {
360*a03ca8b9SKrzysztof Kosiński     PatchElementReader element_patch;
361*a03ca8b9SKrzysztof Kosiński     if (!element_patch.Initialize(source))
362*a03ca8b9SKrzysztof Kosiński       return false;
363*a03ca8b9SKrzysztof Kosiński 
364*a03ca8b9SKrzysztof Kosiński     if (!element_patch.old_element().FitsIn(header_.old_size) ||
365*a03ca8b9SKrzysztof Kosiński         !element_patch.new_element().FitsIn(header_.new_size)) {
366*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Invalid element encountered.";
367*a03ca8b9SKrzysztof Kosiński       return false;
368*a03ca8b9SKrzysztof Kosiński     }
369*a03ca8b9SKrzysztof Kosiński 
370*a03ca8b9SKrzysztof Kosiński     if (element_patch.new_element().offset != current_dst_offset) {
371*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Invalid element encountered.";
372*a03ca8b9SKrzysztof Kosiński       return false;
373*a03ca8b9SKrzysztof Kosiński     }
374*a03ca8b9SKrzysztof Kosiński     current_dst_offset = element_patch.new_element().EndOffset();
375*a03ca8b9SKrzysztof Kosiński 
376*a03ca8b9SKrzysztof Kosiński     elements_.push_back(std::move(element_patch));
377*a03ca8b9SKrzysztof Kosiński   }
378*a03ca8b9SKrzysztof Kosiński   if (current_dst_offset != header_.new_size) {
379*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Patch elements don't fully cover new image file.";
380*a03ca8b9SKrzysztof Kosiński     return false;
381*a03ca8b9SKrzysztof Kosiński   }
382*a03ca8b9SKrzysztof Kosiński 
383*a03ca8b9SKrzysztof Kosiński   if (!source->empty()) {
384*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Patch was not fully consumed.";
385*a03ca8b9SKrzysztof Kosiński     return false;
386*a03ca8b9SKrzysztof Kosiński   }
387*a03ca8b9SKrzysztof Kosiński 
388*a03ca8b9SKrzysztof Kosiński   return true;
389*a03ca8b9SKrzysztof Kosiński }
390*a03ca8b9SKrzysztof Kosiński 
CheckOldFile(ConstBufferView old_image) const391*a03ca8b9SKrzysztof Kosiński bool EnsemblePatchReader::CheckOldFile(ConstBufferView old_image) const {
392*a03ca8b9SKrzysztof Kosiński   return old_image.size() == header_.old_size &&
393*a03ca8b9SKrzysztof Kosiński          CalculateCrc32(old_image.begin(), old_image.end()) == header_.old_crc;
394*a03ca8b9SKrzysztof Kosiński }
395*a03ca8b9SKrzysztof Kosiński 
CheckNewFile(ConstBufferView new_image) const396*a03ca8b9SKrzysztof Kosiński bool EnsemblePatchReader::CheckNewFile(ConstBufferView new_image) const {
397*a03ca8b9SKrzysztof Kosiński   return new_image.size() == header_.new_size &&
398*a03ca8b9SKrzysztof Kosiński          CalculateCrc32(new_image.begin(), new_image.end()) == header_.new_crc;
399*a03ca8b9SKrzysztof Kosiński }
400*a03ca8b9SKrzysztof Kosiński 
401*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
402