1 /*
2  * Copyright (C) 2018 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  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <stdint.h>
20 
21 #include <functional>
22 #include <ostream>
23 #include <string>
24 #include <vector>
25 
26 #include <gtest/gtest_prod.h>  // FRIEND_TEST
27 
28 #include "otautil/rangeset.h"
29 
30 // Represents the target info used in a Command. TargetInfo contains the ranges of the blocks and
31 // the expected hash.
32 class TargetInfo {
33  public:
34   TargetInfo() = default;
35 
TargetInfo(std::string hash,RangeSet ranges)36   TargetInfo(std::string hash, RangeSet ranges)
37       : hash_(std::move(hash)), ranges_(std::move(ranges)) {}
38 
hash()39   const std::string& hash() const {
40     return hash_;
41   }
42 
ranges()43   const RangeSet& ranges() const {
44     return ranges_;
45   }
46 
blocks()47   size_t blocks() const {
48     return ranges_.blocks();
49   }
50 
51   bool operator==(const TargetInfo& other) const {
52     return hash_ == other.hash_ && ranges_ == other.ranges_;
53   }
54 
55  private:
56   friend std::ostream& operator<<(std::ostream& os, const TargetInfo& source);
57 
58   // The hash of the data represented by the object.
59   std::string hash_;
60   // The block ranges that the data should be written to.
61   RangeSet ranges_;
62 };
63 
64 std::ostream& operator<<(std::ostream& os, const TargetInfo& source);
65 
66 // Represents the stash info used in a Command.
67 class StashInfo {
68  public:
69   StashInfo() = default;
70 
StashInfo(std::string id,RangeSet ranges)71   StashInfo(std::string id, RangeSet ranges) : id_(std::move(id)), ranges_(std::move(ranges)) {}
72 
blocks()73   size_t blocks() const {
74     return ranges_.blocks();
75   }
76 
id()77   const std::string& id() const {
78     return id_;
79   }
80 
ranges()81   const RangeSet& ranges() const {
82     return ranges_;
83   }
84 
85   bool operator==(const StashInfo& other) const {
86     return id_ == other.id_ && ranges_ == other.ranges_;
87   }
88 
89  private:
90   friend std::ostream& operator<<(std::ostream& os, const StashInfo& stash);
91 
92   // The id (i.e. hash) of the stash.
93   std::string id_;
94   // The matching location of the stash.
95   RangeSet ranges_;
96 };
97 
98 std::ostream& operator<<(std::ostream& os, const StashInfo& stash);
99 
100 // Represents the source info in a Command, whose data could come from source image, stashed blocks,
101 // or both.
102 class SourceInfo {
103  public:
104   SourceInfo() = default;
105 
SourceInfo(std::string hash,RangeSet ranges,RangeSet location,std::vector<StashInfo> stashes)106   SourceInfo(std::string hash, RangeSet ranges, RangeSet location, std::vector<StashInfo> stashes)
107       : hash_(std::move(hash)),
108         ranges_(std::move(ranges)),
109         location_(std::move(location)),
110         stashes_(std::move(stashes)) {
111     blocks_ = ranges_.blocks();
112     for (const auto& stash : stashes_) {
113       blocks_ += stash.ranges().blocks();
114     }
115   }
116 
117   // Reads all the data specified by this SourceInfo object into the given 'buffer', by calling the
118   // given readers. Caller needs to specify the block size for the represented blocks. The given
119   // buffer needs to be sufficiently large. Otherwise it returns false. 'block_reader' and
120   // 'stash_reader' read the specified data into the given buffer (guaranteed to be large enough)
121   // respectively. The readers should return 0 on success, or -1 on error.
122   bool ReadAll(
123       std::vector<uint8_t>* buffer, size_t block_size,
124       const std::function<int(const RangeSet&, std::vector<uint8_t>*)>& block_reader,
125       const std::function<int(const std::string&, std::vector<uint8_t>*)>& stash_reader) const;
126 
127   // Whether this SourceInfo overlaps with the given TargetInfo object.
128   bool Overlaps(const TargetInfo& target) const;
129 
130   // Dumps the hashes in hex for the given buffer that's loaded from this SourceInfo object
131   // (excluding the stashed blocks which are handled separately).
132   void DumpBuffer(const std::vector<uint8_t>& buffer, size_t block_size) const;
133 
hash()134   const std::string& hash() const {
135     return hash_;
136   }
137 
blocks()138   size_t blocks() const {
139     return blocks_;
140   }
141 
142   bool operator==(const SourceInfo& other) const {
143     return hash_ == other.hash_ && ranges_ == other.ranges_ && location_ == other.location_ &&
144            stashes_ == other.stashes_;
145   }
146 
147  private:
148   friend std::ostream& operator<<(std::ostream& os, const SourceInfo& source);
149 
150   // The hash of the data represented by the object.
151   std::string hash_;
152   // The block ranges from the source image to read data from. This could be a subset of all the
153   // blocks represented by the object, or empty if all the data should be loaded from stash.
154   RangeSet ranges_;
155   // The location in the buffer to load ranges_ into. Empty if ranges_ alone covers all the blocks
156   // (i.e. nothing needs to be loaded from stash).
157   RangeSet location_;
158   // The info for the stashed blocks that are part of the source. Empty if there's none.
159   std::vector<StashInfo> stashes_;
160   // Total number of blocks represented by the object.
161   size_t blocks_{ 0 };
162 };
163 
164 std::ostream& operator<<(std::ostream& os, const SourceInfo& source);
165 
166 class PatchInfo {
167  public:
168   PatchInfo() = default;
169 
PatchInfo(size_t offset,size_t length)170   PatchInfo(size_t offset, size_t length) : offset_(offset), length_(length) {}
171 
offset()172   size_t offset() const {
173     return offset_;
174   }
175 
length()176   size_t length() const {
177     return length_;
178   }
179 
180   bool operator==(const PatchInfo& other) const {
181     return offset_ == other.offset_ && length_ == other.length_;
182   }
183 
184  private:
185   size_t offset_{ 0 };
186   size_t length_{ 0 };
187 };
188 
189 // The arguments to build a hash tree from blocks on the block device.
190 class HashTreeInfo {
191  public:
192   HashTreeInfo() = default;
193 
HashTreeInfo(RangeSet hash_tree_ranges,RangeSet source_ranges,std::string hash_algorithm,std::string salt_hex,std::string root_hash)194   HashTreeInfo(RangeSet hash_tree_ranges, RangeSet source_ranges, std::string hash_algorithm,
195                std::string salt_hex, std::string root_hash)
196       : hash_tree_ranges_(std::move(hash_tree_ranges)),
197         source_ranges_(std::move(source_ranges)),
198         hash_algorithm_(std::move(hash_algorithm)),
199         salt_hex_(std::move(salt_hex)),
200         root_hash_(std::move(root_hash)) {}
201 
hash_tree_ranges()202   const RangeSet& hash_tree_ranges() const {
203     return hash_tree_ranges_;
204   }
source_ranges()205   const RangeSet& source_ranges() const {
206     return source_ranges_;
207   }
208 
hash_algorithm()209   const std::string& hash_algorithm() const {
210     return hash_algorithm_;
211   }
salt_hex()212   const std::string& salt_hex() const {
213     return salt_hex_;
214   }
root_hash()215   const std::string& root_hash() const {
216     return root_hash_;
217   }
218 
219   bool operator==(const HashTreeInfo& other) const {
220     return hash_tree_ranges_ == other.hash_tree_ranges_ && source_ranges_ == other.source_ranges_ &&
221            hash_algorithm_ == other.hash_algorithm_ && salt_hex_ == other.salt_hex_ &&
222            root_hash_ == other.root_hash_;
223   }
224 
225  private:
226   RangeSet hash_tree_ranges_;
227   RangeSet source_ranges_;
228   std::string hash_algorithm_;
229   std::string salt_hex_;
230   std::string root_hash_;
231 };
232 
233 // Command class holds the info for an update command that performs block-based OTA (BBOTA). Each
234 // command consists of one or several args, namely TargetInfo, SourceInfo, StashInfo and PatchInfo.
235 // The currently used BBOTA version is v4.
236 //
237 //    zero <tgt_ranges>
238 //      - Fill the indicated blocks with zeros.
239 //      - Meaningful args: TargetInfo
240 //
241 //    new <tgt_ranges>
242 //      - Fill the blocks with data read from the new_data file.
243 //      - Meaningful args: TargetInfo
244 //
245 //    erase <tgt_ranges>
246 //      - Mark the given blocks as empty.
247 //      - Meaningful args: TargetInfo
248 //
249 //    move <hash> <...>
250 //      - Read the source blocks, write result to target blocks.
251 //      - Meaningful args: TargetInfo, SourceInfo
252 //
253 //      See the note below for <...>.
254 //
255 //    bsdiff <patchstart> <patchlen> <srchash> <dsthash> <...>
256 //    imgdiff <patchstart> <patchlen> <srchash> <dsthash> <...>
257 //      - Read the source blocks, apply a patch, and write result to target blocks.
258 //      - Meaningful args: PatchInfo, TargetInfo, SourceInfo
259 //
260 //      It expects <...> in one of the following formats:
261 //
262 //        <tgt_ranges> <src_block_count> - <[stash_id:stash_location] ...>
263 //          (loads data from stashes only)
264 //
265 //        <tgt_ranges> <src_block_count> <src_ranges>
266 //          (loads data from source image only)
267 //
268 //        <tgt_ranges> <src_block_count> <src_ranges> <src_ranges_location>
269 //                                       <[stash_id:stash_location] ...>
270 //          (loads data from both of source image and stashes)
271 //
272 //    stash <stash_id> <src_ranges>
273 //      - Load the given source blocks and stash the data in the given slot of the stash table.
274 //      - Meaningful args: StashInfo
275 //
276 //    free <stash_id>
277 //      - Free the given stash data.
278 //      - Meaningful args: StashInfo
279 //
280 //    compute_hash_tree <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash>
281 //      - Computes the hash_tree bytes and writes the result to the specified range on the
282 //        block_device.
283 //
284 //    abort
285 //      - Abort the current update. Allowed for testing code only.
286 //
287 class Command {
288  public:
289   enum class Type {
290     ABORT,
291     BSDIFF,
292     COMPUTE_HASH_TREE,
293     ERASE,
294     FREE,
295     IMGDIFF,
296     MOVE,
297     NEW,
298     STASH,
299     ZERO,
300     LAST,  // Not a valid type.
301   };
302 
303   Command() = default;
304 
Command(Type type,size_t index,std::string cmdline,PatchInfo patch,TargetInfo target,SourceInfo source,StashInfo stash)305   Command(Type type, size_t index, std::string cmdline, PatchInfo patch, TargetInfo target,
306           SourceInfo source, StashInfo stash)
307       : type_(type),
308         index_(index),
309         cmdline_(std::move(cmdline)),
310         patch_(std::move(patch)),
311         target_(std::move(target)),
312         source_(std::move(source)),
313         stash_(std::move(stash)) {}
314 
315   Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info);
316 
317   // Parses the given command 'line' into a Command object and returns it. The 'index' is specified
318   // by the caller to index the object. On parsing error, it returns an empty Command object that
319   // evaluates to false, and the specific error message will be set in 'err'.
320   static Command Parse(const std::string& line, size_t index, std::string* err);
321 
322   // Parses the command type from the given string.
323   static Type ParseType(const std::string& type_str);
324 
type()325   Type type() const {
326     return type_;
327   }
328 
index()329   size_t index() const {
330     return index_;
331   }
332 
cmdline()333   const std::string& cmdline() const {
334     return cmdline_;
335   }
336 
patch()337   const PatchInfo& patch() const {
338     return patch_;
339   }
340 
target()341   const TargetInfo& target() const {
342     return target_;
343   }
344 
source()345   const SourceInfo& source() const {
346     return source_;
347   }
348 
stash()349   const StashInfo& stash() const {
350     return stash_;
351   }
352 
hash_tree_info()353   const HashTreeInfo& hash_tree_info() const {
354     return hash_tree_info_;
355   }
356 
block_size()357   size_t block_size() const {
358     return block_size_;
359   }
360 
361   constexpr explicit operator bool() const {
362     return type_ != Type::LAST;
363   }
364 
365  private:
366   friend class ResumableUpdaterTest;
367   friend class UpdaterTest;
368 
369   FRIEND_TEST(CommandsTest, Parse_ABORT_Allowed);
370   FRIEND_TEST(CommandsTest, Parse_InvalidNumberOfArgs);
371   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_InvalidInput);
372   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_StashesOnly);
373   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksAndStashes);
374   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksOnly);
375 
376   // Parses the target and source info from the given 'tokens' vector. Saves the parsed info into
377   // 'target' and 'source' objects. Returns the parsing result. Error message will be set in 'err'
378   // on parsing error, and the contents in 'target' and 'source' will be undefined.
379   static bool ParseTargetInfoAndSourceInfo(const std::vector<std::string>& tokens,
380                                            const std::string& tgt_hash, TargetInfo* target,
381                                            const std::string& src_hash, SourceInfo* source,
382                                            std::string* err);
383 
384   // Allows parsing ABORT command, which should be used for testing purpose only.
385   static bool abort_allowed_;
386 
387   // The type of the command.
388   Type type_{ Type::LAST };
389   // The index of the Command object, which is specified by the caller.
390   size_t index_{ 0 };
391   // The input string that the Command object is parsed from.
392   std::string cmdline_;
393   // The patch info. Only meaningful for BSDIFF and IMGDIFF commands.
394   PatchInfo patch_;
395   // The target info, where the command should be written to.
396   TargetInfo target_;
397   // The source info to load the source blocks for the command.
398   SourceInfo source_;
399   // The stash info. Only meaningful for STASH and FREE commands. Note that although SourceInfo may
400   // also load data from stash, such info will be owned and managed by SourceInfo (i.e. in source_).
401   StashInfo stash_;
402   // The hash_tree info. Only meaningful for COMPUTE_HASH_TREE.
403   HashTreeInfo hash_tree_info_;
404   // The unit size of each block to be used in this command.
405   size_t block_size_{ 4096 };
406 };
407 
408 std::ostream& operator<<(std::ostream& os, const Command& command);
409 
410 // TransferList represents the info for a transfer list, which is parsed from input text lines
411 // containing commands to transfer data from one place to another on the target partition.
412 //
413 // The creator of the transfer list will guarantee that no block is read (i.e., used as the source
414 // for a patch or move) after it has been written.
415 //
416 // The creator will guarantee that a given stash is loaded (with a stash command) before it's used
417 // in a move/bsdiff/imgdiff command.
418 //
419 // Within one command the source and target ranges may overlap so in general we need to read the
420 // entire source into memory before writing anything to the target blocks.
421 //
422 // All the patch data is concatenated into one patch_data file in the update package. It must be
423 // stored uncompressed because we memory-map it in directly from the archive. (Since patches are
424 // already compressed, we lose very little by not compressing their concatenation.)
425 //
426 // Commands that read data from the partition (i.e. move/bsdiff/imgdiff/stash) have one or more
427 // additional hashes before the range parameters, which are used to check if the command has
428 // already been completed and verify the integrity of the source data.
429 class TransferList {
430  public:
431   // Number of header lines.
432   static constexpr size_t kTransferListHeaderLines = 4;
433 
434   TransferList() = default;
435 
436   // Parses the given input string and returns a TransferList object. Sets error message if any.
437   static TransferList Parse(const std::string& transfer_list_str, std::string* err);
438 
version()439   int version() const {
440     return version_;
441   }
442 
total_blocks()443   size_t total_blocks() const {
444     return total_blocks_;
445   }
446 
stash_max_entries()447   size_t stash_max_entries() const {
448     return stash_max_entries_;
449   }
450 
stash_max_blocks()451   size_t stash_max_blocks() const {
452     return stash_max_blocks_;
453   }
454 
commands()455   const std::vector<Command>& commands() const {
456     return commands_;
457   }
458 
459   // Returns whether the TransferList is valid.
460   constexpr explicit operator bool() const {
461     return version_ != 0;
462   }
463 
464  private:
465   // BBOTA version.
466   int version_{ 0 };
467   // Total number of blocks to be written in this transfer.
468   size_t total_blocks_;
469   // Maximum number of stashes that exist at the same time.
470   size_t stash_max_entries_;
471   // Maximum number of blocks to be stashed.
472   size_t stash_max_blocks_;
473   // Commands in this transfer.
474   std::vector<Command> commands_;
475 };
476