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 #include "private/commands.h" 18 19 #include <stdint.h> 20 #include <string.h> 21 22 #include <functional> 23 #include <ostream> 24 #include <string> 25 #include <vector> 26 27 #include <android-base/logging.h> 28 #include <android-base/parseint.h> 29 #include <android-base/stringprintf.h> 30 #include <android-base/strings.h> 31 #include <openssl/sha.h> 32 33 #include "otautil/print_sha1.h" 34 #include "otautil/rangeset.h" 35 36 using namespace std::string_literals; 37 38 bool Command::abort_allowed_ = false; 39 40 Command::Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info) 41 : type_(type), 42 index_(index), 43 cmdline_(std::move(cmdline)), 44 hash_tree_info_(std::move(hash_tree_info)) { 45 CHECK(type == Type::COMPUTE_HASH_TREE); 46 } 47 48 Command::Type Command::ParseType(const std::string& type_str) { 49 if (type_str == "abort") { 50 if (!abort_allowed_) { 51 LOG(ERROR) << "ABORT disallowed"; 52 return Type::LAST; 53 } 54 return Type::ABORT; 55 } else if (type_str == "bsdiff") { 56 return Type::BSDIFF; 57 } else if (type_str == "compute_hash_tree") { 58 return Type::COMPUTE_HASH_TREE; 59 } else if (type_str == "erase") { 60 return Type::ERASE; 61 } else if (type_str == "free") { 62 return Type::FREE; 63 } else if (type_str == "imgdiff") { 64 return Type::IMGDIFF; 65 } else if (type_str == "move") { 66 return Type::MOVE; 67 } else if (type_str == "new") { 68 return Type::NEW; 69 } else if (type_str == "stash") { 70 return Type::STASH; 71 } else if (type_str == "zero") { 72 return Type::ZERO; 73 } 74 return Type::LAST; 75 }; 76 77 bool Command::ParseTargetInfoAndSourceInfo(const std::vector<std::string>& tokens, 78 const std::string& tgt_hash, TargetInfo* target, 79 const std::string& src_hash, SourceInfo* source, 80 std::string* err) { 81 // We expect the given args (in 'tokens' vector) in one of the following formats. 82 // 83 // <tgt_ranges> <src_block_count> - <[stash_id:location] ...> 84 // (loads data from stashes only) 85 // 86 // <tgt_ranges> <src_block_count> <src_ranges> 87 // (loads data from source image only) 88 // 89 // <tgt_ranges> <src_block_count> <src_ranges> <src_ranges_location> <[stash_id:location] ...> 90 // (loads data from both of source image and stashes) 91 92 // At least it needs to provide three args: <tgt_ranges>, <src_block_count> and "-"/<src_ranges>. 93 if (tokens.size() < 3) { 94 *err = "invalid number of args"; 95 return false; 96 } 97 98 size_t pos = 0; 99 RangeSet tgt_ranges = RangeSet::Parse(tokens[pos++]); 100 if (!tgt_ranges) { 101 *err = "invalid target ranges"; 102 return false; 103 } 104 *target = TargetInfo(tgt_hash, tgt_ranges); 105 106 // <src_block_count> 107 const std::string& token = tokens[pos++]; 108 size_t src_blocks; 109 if (!android::base::ParseUint(token, &src_blocks)) { 110 *err = "invalid src_block_count \""s + token + "\""; 111 return false; 112 } 113 114 RangeSet src_ranges; 115 RangeSet src_ranges_location; 116 // "-" or <src_ranges> [<src_ranges_location>] 117 if (tokens[pos] == "-") { 118 // no source ranges, only stashes 119 pos++; 120 } else { 121 src_ranges = RangeSet::Parse(tokens[pos++]); 122 if (!src_ranges) { 123 *err = "invalid source ranges"; 124 return false; 125 } 126 127 if (pos >= tokens.size()) { 128 // No stashes, only source ranges. 129 SourceInfo result(src_hash, src_ranges, {}, {}); 130 131 // Sanity check the block count. 132 if (result.blocks() != src_blocks) { 133 *err = 134 android::base::StringPrintf("mismatching block count: %zu (%s) vs %zu", result.blocks(), 135 src_ranges.ToString().c_str(), src_blocks); 136 return false; 137 } 138 139 *source = result; 140 return true; 141 } 142 143 src_ranges_location = RangeSet::Parse(tokens[pos++]); 144 if (!src_ranges_location) { 145 *err = "invalid source ranges location"; 146 return false; 147 } 148 } 149 150 // <[stash_id:stash_location]> 151 std::vector<StashInfo> stashes; 152 while (pos < tokens.size()) { 153 // Each word is a an index into the stash table, a colon, and then a RangeSet describing where 154 // in the source block that stashed data should go. 155 std::vector<std::string> pairs = android::base::Split(tokens[pos++], ":"); 156 if (pairs.size() != 2) { 157 *err = "invalid stash info"; 158 return false; 159 } 160 RangeSet stash_location = RangeSet::Parse(pairs[1]); 161 if (!stash_location) { 162 *err = "invalid stash location"; 163 return false; 164 } 165 stashes.emplace_back(pairs[0], stash_location); 166 } 167 168 SourceInfo result(src_hash, src_ranges, src_ranges_location, stashes); 169 if (src_blocks != result.blocks()) { 170 *err = android::base::StringPrintf("mismatching block count: %zu (%s) vs %zu", result.blocks(), 171 src_ranges.ToString().c_str(), src_blocks); 172 return false; 173 } 174 175 *source = result; 176 return true; 177 } 178 179 Command Command::Parse(const std::string& line, size_t index, std::string* err) { 180 std::vector<std::string> tokens = android::base::Split(line, " "); 181 size_t pos = 0; 182 // tokens.size() will be 1 at least. 183 Type op = ParseType(tokens[pos++]); 184 if (op == Type::LAST) { 185 *err = "invalid type"; 186 return {}; 187 } 188 189 PatchInfo patch_info; 190 TargetInfo target_info; 191 SourceInfo source_info; 192 StashInfo stash_info; 193 194 if (op == Type::ZERO || op == Type::NEW || op == Type::ERASE) { 195 // zero/new/erase <rangeset> 196 if (pos + 1 != tokens.size()) { 197 *err = android::base::StringPrintf("invalid number of args: %zu (expected 1)", 198 tokens.size() - pos); 199 return {}; 200 } 201 RangeSet tgt_ranges = RangeSet::Parse(tokens[pos++]); 202 if (!tgt_ranges) { 203 return {}; 204 } 205 static const std::string kUnknownHash{ "unknown-hash" }; 206 target_info = TargetInfo(kUnknownHash, tgt_ranges); 207 } else if (op == Type::STASH) { 208 // stash <stash_id> <src_ranges> 209 if (pos + 2 != tokens.size()) { 210 *err = android::base::StringPrintf("invalid number of args: %zu (expected 2)", 211 tokens.size() - pos); 212 return {}; 213 } 214 const std::string& id = tokens[pos++]; 215 RangeSet src_ranges = RangeSet::Parse(tokens[pos++]); 216 if (!src_ranges) { 217 *err = "invalid token"; 218 return {}; 219 } 220 stash_info = StashInfo(id, src_ranges); 221 } else if (op == Type::FREE) { 222 // free <stash_id> 223 if (pos + 1 != tokens.size()) { 224 *err = android::base::StringPrintf("invalid number of args: %zu (expected 1)", 225 tokens.size() - pos); 226 return {}; 227 } 228 stash_info = StashInfo(tokens[pos++], {}); 229 } else if (op == Type::MOVE) { 230 // <hash> 231 if (pos + 1 > tokens.size()) { 232 *err = "missing hash"; 233 return {}; 234 } 235 std::string hash = tokens[pos++]; 236 if (!ParseTargetInfoAndSourceInfo( 237 std::vector<std::string>(tokens.cbegin() + pos, tokens.cend()), hash, &target_info, 238 hash, &source_info, err)) { 239 return {}; 240 } 241 } else if (op == Type::BSDIFF || op == Type::IMGDIFF) { 242 // <offset> <length> <srchash> <dsthash> 243 if (pos + 4 > tokens.size()) { 244 *err = android::base::StringPrintf("invalid number of args: %zu (expected 4+)", 245 tokens.size() - pos); 246 return {}; 247 } 248 size_t offset; 249 size_t length; 250 if (!android::base::ParseUint(tokens[pos++], &offset) || 251 !android::base::ParseUint(tokens[pos++], &length)) { 252 *err = "invalid patch offset/length"; 253 return {}; 254 } 255 patch_info = PatchInfo(offset, length); 256 257 std::string src_hash = tokens[pos++]; 258 std::string dst_hash = tokens[pos++]; 259 if (!ParseTargetInfoAndSourceInfo( 260 std::vector<std::string>(tokens.cbegin() + pos, tokens.cend()), dst_hash, &target_info, 261 src_hash, &source_info, err)) { 262 return {}; 263 } 264 } else if (op == Type::ABORT) { 265 // No-op, other than sanity checking the input args. 266 if (pos != tokens.size()) { 267 *err = android::base::StringPrintf("invalid number of args: %zu (expected 0)", 268 tokens.size() - pos); 269 return {}; 270 } 271 } else if (op == Type::COMPUTE_HASH_TREE) { 272 // <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash> 273 if (pos + 5 != tokens.size()) { 274 *err = android::base::StringPrintf("invalid number of args: %zu (expected 5)", 275 tokens.size() - pos); 276 return {}; 277 } 278 279 // Expects the hash_tree data to be contiguous. 280 RangeSet hash_tree_ranges = RangeSet::Parse(tokens[pos++]); 281 if (!hash_tree_ranges || hash_tree_ranges.size() != 1) { 282 *err = "invalid hash tree ranges in: " + line; 283 return {}; 284 } 285 286 RangeSet source_ranges = RangeSet::Parse(tokens[pos++]); 287 if (!source_ranges) { 288 *err = "invalid source ranges in: " + line; 289 return {}; 290 } 291 292 std::string hash_algorithm = tokens[pos++]; 293 std::string salt_hex = tokens[pos++]; 294 std::string root_hash = tokens[pos++]; 295 if (hash_algorithm.empty() || salt_hex.empty() || root_hash.empty()) { 296 *err = "invalid hash tree arguments in " + line; 297 return {}; 298 } 299 300 HashTreeInfo hash_tree_info(std::move(hash_tree_ranges), std::move(source_ranges), 301 std::move(hash_algorithm), std::move(salt_hex), 302 std::move(root_hash)); 303 return Command(op, index, line, std::move(hash_tree_info)); 304 } else { 305 *err = "invalid op"; 306 return {}; 307 } 308 309 return Command(op, index, line, patch_info, target_info, source_info, stash_info); 310 } 311 312 bool SourceInfo::Overlaps(const TargetInfo& target) const { 313 return ranges_.Overlaps(target.ranges()); 314 } 315 316 // Moves blocks in the 'source' vector to the specified locations (as in 'locs') in the 'dest' 317 // vector. Note that source and dest may be the same buffer. 318 static void MoveRange(std::vector<uint8_t>* dest, const RangeSet& locs, 319 const std::vector<uint8_t>& source, size_t block_size) { 320 const uint8_t* from = source.data(); 321 uint8_t* to = dest->data(); 322 size_t start = locs.blocks(); 323 // Must do the movement backward. 324 for (auto it = locs.crbegin(); it != locs.crend(); it++) { 325 size_t blocks = it->second - it->first; 326 start -= blocks; 327 memmove(to + (it->first * block_size), from + (start * block_size), blocks * block_size); 328 } 329 } 330 331 bool SourceInfo::ReadAll( 332 std::vector<uint8_t>* buffer, size_t block_size, 333 const std::function<int(const RangeSet&, std::vector<uint8_t>*)>& block_reader, 334 const std::function<int(const std::string&, std::vector<uint8_t>*)>& stash_reader) const { 335 if (buffer->size() < blocks() * block_size) { 336 return false; 337 } 338 339 // Read in the source ranges. 340 if (ranges_) { 341 if (block_reader(ranges_, buffer) != 0) { 342 return false; 343 } 344 if (location_) { 345 MoveRange(buffer, location_, *buffer, block_size); 346 } 347 } 348 349 // Read in the stashes. 350 for (const StashInfo& stash : stashes_) { 351 std::vector<uint8_t> stash_buffer(stash.blocks() * block_size); 352 if (stash_reader(stash.id(), &stash_buffer) != 0) { 353 return false; 354 } 355 MoveRange(buffer, stash.ranges(), stash_buffer, block_size); 356 } 357 return true; 358 } 359 360 void SourceInfo::DumpBuffer(const std::vector<uint8_t>& buffer, size_t block_size) const { 361 LOG(INFO) << "Dumping hashes in hex for " << ranges_.blocks() << " source blocks"; 362 363 const RangeSet& location = location_ ? location_ : RangeSet({ Range{ 0, ranges_.blocks() } }); 364 for (size_t i = 0; i < ranges_.blocks(); i++) { 365 size_t block_num = ranges_.GetBlockNumber(i); 366 size_t buffer_index = location.GetBlockNumber(i); 367 CHECK_LE((buffer_index + 1) * block_size, buffer.size()); 368 369 uint8_t digest[SHA_DIGEST_LENGTH]; 370 SHA1(buffer.data() + buffer_index * block_size, block_size, digest); 371 std::string hexdigest = print_sha1(digest); 372 LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; 373 } 374 } 375 376 std::ostream& operator<<(std::ostream& os, const Command& command) { 377 os << command.index() << ": " << command.cmdline(); 378 return os; 379 } 380 381 std::ostream& operator<<(std::ostream& os, const TargetInfo& target) { 382 os << target.blocks() << " blocks (" << target.hash_ << "): " << target.ranges_.ToString(); 383 return os; 384 } 385 386 std::ostream& operator<<(std::ostream& os, const StashInfo& stash) { 387 os << stash.blocks() << " blocks (" << stash.id_ << "): " << stash.ranges_.ToString(); 388 return os; 389 } 390 391 std::ostream& operator<<(std::ostream& os, const SourceInfo& source) { 392 os << source.blocks_ << " blocks (" << source.hash_ << "): "; 393 if (source.ranges_) { 394 os << source.ranges_.ToString(); 395 if (source.location_) { 396 os << " (location: " << source.location_.ToString() << ")"; 397 } 398 } 399 if (!source.stashes_.empty()) { 400 os << " " << source.stashes_.size() << " stash(es)"; 401 } 402 return os; 403 } 404 405 TransferList TransferList::Parse(const std::string& transfer_list_str, std::string* err) { 406 TransferList result{}; 407 408 std::vector<std::string> lines = android::base::Split(transfer_list_str, "\n"); 409 if (lines.size() < kTransferListHeaderLines) { 410 *err = android::base::StringPrintf("too few lines in the transfer list [%zu]", lines.size()); 411 return TransferList{}; 412 } 413 414 // First line in transfer list is the version number. 415 if (!android::base::ParseInt(lines[0], &result.version_, 3, 4)) { 416 *err = "unexpected transfer list version ["s + lines[0] + "]"; 417 return TransferList{}; 418 } 419 420 // Second line in transfer list is the total number of blocks we expect to write. 421 if (!android::base::ParseUint(lines[1], &result.total_blocks_)) { 422 *err = "unexpected block count ["s + lines[1] + "]"; 423 return TransferList{}; 424 } 425 426 // Third line is how many stash entries are needed simultaneously. 427 if (!android::base::ParseUint(lines[2], &result.stash_max_entries_)) { 428 return TransferList{}; 429 } 430 431 // Fourth line is the maximum number of blocks that will be stashed simultaneously. 432 if (!android::base::ParseUint(lines[3], &result.stash_max_blocks_)) { 433 *err = "unexpected maximum stash blocks ["s + lines[3] + "]"; 434 return TransferList{}; 435 } 436 437 // Subsequent lines are all individual transfer commands. 438 for (size_t i = kTransferListHeaderLines; i < lines.size(); i++) { 439 const std::string& line = lines[i]; 440 if (line.empty()) continue; 441 442 size_t cmdindex = i - kTransferListHeaderLines; 443 std::string parsing_error; 444 Command command = Command::Parse(line, cmdindex, &parsing_error); 445 if (!command) { 446 *err = android::base::StringPrintf("Failed to parse command %zu [%s]: %s", cmdindex, 447 line.c_str(), parsing_error.c_str()); 448 return TransferList{}; 449 } 450 result.commands_.push_back(command); 451 } 452 453 return result; 454 } 455