From 5a1dee01df3af346729b5791606b72d59b8e9815 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 21 Jul 2017 15:15:31 -0700 Subject: [PATCH] update_verifier: Handle legacy care_map.txt gracefully. update_verifier should be backward compatible to not reject legacy care_map.txt from old releases, which could otherwise fail to boot into the new release. For example, we've changed the care_map format between N and O. An O update_verifier would fail to work with an N care_map.txt - a) we have switched update_verifier to read from device mapper in O; b) the last few blocks that contain metadata can't be read via device mapper. This could be a result of sideloading an O OTA while the device having a pending N update. Bug: 63544345 Test: As follows on sailfish: 1. Flash the device with this CL; 2. Put a copy of N care_map.txt at /data/ota_package/. Restore the permissions properly ('cache' group); 3. `adb reboot bootloader`; 4. `fastboot set_active ` 5. Device boots up into home screen, with a warning in logcat that says it has skipped legacy care_map.txt. Change-Id: I6acc88c9e655a9245e6531f176fef7953953935f --- update_verifier/update_verifier.cpp | 77 +++++++++++++++++------------ 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp index d3a5185b..b49011a1 100644 --- a/update_verifier/update_verifier.cpp +++ b/update_verifier/update_verifier.cpp @@ -175,40 +175,53 @@ static bool read_blocks(const std::string& partition, const std::string& range_s return true; } +// Returns true to indicate a passing verification (or the error should be ignored); Otherwise +// returns false on fatal errors, where we should reject the current boot and trigger a fallback. +// Note that update_verifier should be backward compatible to not reject care_map.txt from old +// releases, which could otherwise fail to boot into the new release. For example, we've changed +// the care_map format between N and O. An O update_verifier would fail to work with N +// care_map.txt. This could be a result of sideloading an O OTA while the device having a pending N +// update. bool verify_image(const std::string& care_map_name) { - android::base::unique_fd care_map_fd(TEMP_FAILURE_RETRY(open(care_map_name.c_str(), O_RDONLY))); - // If the device is flashed before the current boot, it may not have care_map.txt - // in /data/ota_package. To allow the device to continue booting in this situation, - // we should print a warning and skip the block verification. - if (care_map_fd.get() == -1) { - PLOG(WARNING) << "Failed to open " << care_map_name; - return true; - } - // Care map file has four lines (two lines if vendor partition is not present): - // First line has the block partition name (system/vendor). - // Second line holds all ranges of blocks to verify. - // The next two lines have the same format but for vendor partition. - std::string file_content; - if (!android::base::ReadFdToString(care_map_fd.get(), &file_content)) { - LOG(ERROR) << "Error reading care map contents to string."; - return false; - } - - std::vector lines; - lines = android::base::Split(android::base::Trim(file_content), "\n"); - if (lines.size() != 2 && lines.size() != 4) { - LOG(ERROR) << "Invalid lines in care_map: found " << lines.size() - << " lines, expecting 2 or 4 lines."; - return false; - } - - for (size_t i = 0; i < lines.size(); i += 2) { - if (!read_blocks(lines[i], lines[i+1])) { - return false; - } - } - + android::base::unique_fd care_map_fd(TEMP_FAILURE_RETRY(open(care_map_name.c_str(), O_RDONLY))); + // If the device is flashed before the current boot, it may not have care_map.txt + // in /data/ota_package. To allow the device to continue booting in this situation, + // we should print a warning and skip the block verification. + if (care_map_fd.get() == -1) { + PLOG(WARNING) << "Failed to open " << care_map_name; return true; + } + // Care map file has four lines (two lines if vendor partition is not present): + // First line has the block partition name (system/vendor). + // Second line holds all ranges of blocks to verify. + // The next two lines have the same format but for vendor partition. + std::string file_content; + if (!android::base::ReadFdToString(care_map_fd.get(), &file_content)) { + LOG(ERROR) << "Error reading care map contents to string."; + return false; + } + + std::vector lines; + lines = android::base::Split(android::base::Trim(file_content), "\n"); + if (lines.size() != 2 && lines.size() != 4) { + LOG(ERROR) << "Invalid lines in care_map: found " << lines.size() + << " lines, expecting 2 or 4 lines."; + return false; + } + + for (size_t i = 0; i < lines.size(); i += 2) { + // We're seeing an N care_map.txt. Skip the verification since it's not compatible with O + // update_verifier (the last few metadata blocks can't be read via device mapper). + if (android::base::StartsWith(lines[i], "/dev/block/")) { + LOG(WARNING) << "Found legacy care_map.txt; skipped."; + return true; + } + if (!read_blocks(lines[i], lines[i+1])) { + return false; + } + } + + return true; } static int reboot_device() {