From 93b5bf261ca984dcebdb538b7691fe47576069eb Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 25 Oct 2018 10:39:01 -0700 Subject: Refactor the code to check the metadata The two functions check_wipe_package() and check_newer_ab_build() were using the same flow; and checked the same device properties against the metadata file in the package. These properties include: ota_type, pre-device, and serial number. Therefore, we can consolidate the checks to a single function; and continue to check the fingerprint and timestamp only for AB updates. This change also addresses the need to accept multiple serial number in the wipe package. Bug: 118401208 Test: unit tests pass Change-Id: Ia6bc48fb6effcae059a2ff2cf71764b4136b4c00 --- install.cpp | 226 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 123 insertions(+), 103 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index 42d264157..e1e8ee879 100644 --- a/install.cpp +++ b/install.cpp @@ -32,9 +32,7 @@ #include #include #include -#include #include -#include #include #include @@ -47,7 +45,6 @@ #include #include #include -#include #include "common.h" #include "otautil/error_code.h" @@ -67,18 +64,7 @@ static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25; static std::condition_variable finish_log_temperature; -// This function parses and returns the build.version.incremental -static std::string parse_build_number(const std::string& str) { - size_t pos = str.find('='); - if (pos != std::string::npos) { - return android::base::Trim(str.substr(pos+1)); - } - - LOG(ERROR) << "Failed to parse build number in " << str; - return ""; -} - -bool read_metadata_from_package(ZipArchiveHandle zip, std::string* metadata) { +bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map* metadata) { CHECK(metadata != nullptr); static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata"; @@ -90,101 +76,79 @@ bool read_metadata_from_package(ZipArchiveHandle zip, std::string* metadata) { } uint32_t length = entry.uncompressed_length; - metadata->resize(length, '\0'); - int32_t err = ExtractToMemory(zip, &entry, reinterpret_cast(&(*metadata)[0]), length); + std::string metadata_string(length, '\0'); + int32_t err = + ExtractToMemory(zip, &entry, reinterpret_cast(&metadata_string[0]), length); if (err != 0) { LOG(ERROR) << "Failed to extract " << METADATA_PATH << ": " << ErrorCodeString(err); return false; } - return true; -} -// Read the build.version.incremental of src/tgt from the metadata and log it to last_install. -static void read_source_target_build(ZipArchiveHandle zip, std::vector* log_buffer) { - std::string metadata; - if (!read_metadata_from_package(zip, &metadata)) { - return; - } - // Examples of the pre-build and post-build strings in metadata: - // pre-build-incremental=2943039 - // post-build-incremental=2951741 - std::vector lines = android::base::Split(metadata, "\n"); - for (const std::string& line : lines) { - std::string str = android::base::Trim(line); - if (android::base::StartsWith(str, "pre-build-incremental")) { - std::string source_build = parse_build_number(str); - if (!source_build.empty()) { - log_buffer->push_back("source_build: " + source_build); - } - } else if (android::base::StartsWith(str, "post-build-incremental")) { - std::string target_build = parse_build_number(str); - if (!target_build.empty()) { - log_buffer->push_back("target_build: " + target_build); - } - } - } -} - -// Parses the metadata of the OTA package in |zip| and checks whether we are allowed to accept this -// A/B package. Downgrading is not allowed unless explicitly enabled in the package and only for -// incremental packages. -static int check_newer_ab_build(ZipArchiveHandle zip) { - std::string metadata_str; - if (!read_metadata_from_package(zip, &metadata_str)) { - return INSTALL_CORRUPT; - } - std::map metadata; - for (const std::string& line : android::base::Split(metadata_str, "\n")) { + for (const std::string& line : android::base::Split(metadata_string, "\n")) { size_t eq = line.find('='); if (eq != std::string::npos) { - metadata[line.substr(0, eq)] = line.substr(eq + 1); + metadata->emplace(android::base::Trim(line.substr(0, eq)), + android::base::Trim(line.substr(eq + 1))); } } - std::string value = android::base::GetProperty("ro.product.device", ""); - const std::string& pkg_device = metadata["pre-device"]; - if (pkg_device != value || pkg_device.empty()) { - LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << value; - return INSTALL_ERROR; + return true; +} + +// Gets the value for the given key in |metadata|. Returns an emtpy string if the key isn't +// present. +static std::string get_value(const std::map& metadata, + const std::string& key) { + const auto& it = metadata.find(key); + return (it == metadata.end()) ? "" : it->second; +} + +static std::string OtaTypeToString(OtaType type) { + switch (type) { + case OtaType::AB: + return "AB"; + case OtaType::BLOCK: + return "BLOCK"; + case OtaType::BRICK: + return "BRICK"; } +} - // We allow the package to not have any serialno; and we also allow it to carry multiple serial - // numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the - // verification if the device's serialno doesn't match any of these carried numbers. - value = android::base::GetProperty("ro.serialno", ""); - const std::string& pkg_serial_no = metadata["serialno"]; - if (!pkg_serial_no.empty()) { - bool match = false; - for (const std::string& number : android::base::Split(pkg_serial_no, "|")) { - if (value == android::base::Trim(number)) { - match = true; - break; - } - } - if (!match) { - LOG(ERROR) << "Package is for serial " << pkg_serial_no; - return INSTALL_ERROR; - } +// Read the build.version.incremental of src/tgt from the metadata and log it to last_install. +static void ReadSourceTargetBuild(const std::map& metadata, + std::vector* log_buffer) { + // Examples of the pre-build and post-build strings in metadata: + // pre-build-incremental=2943039 + // post-build-incremental=2951741 + auto source_build = get_value(metadata, "pre-build-incremental"); + if (!source_build.empty()) { + log_buffer->push_back("source_build: " + source_build); } - if (metadata["ota-type"] != "AB") { - LOG(ERROR) << "Package is not A/B"; - return INSTALL_ERROR; + auto target_build = get_value(metadata, "post-build-incremental"); + if (!target_build.empty()) { + log_buffer->push_back("target_build: " + target_build); } +} +// Checks the build version, fingerprint and timestamp in the metadata of the A/B package. +// Downgrading is not allowed unless explicitly enabled in the package and only for +// incremental packages. +static int CheckAbSpecificMetadata(const std::map& metadata) { // Incremental updates should match the current build. - value = android::base::GetProperty("ro.build.version.incremental", ""); - const std::string& pkg_pre_build = metadata["pre-build-incremental"]; - if (!pkg_pre_build.empty() && pkg_pre_build != value) { - LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected " << value; + auto device_pre_build = android::base::GetProperty("ro.build.version.incremental", ""); + auto pkg_pre_build = get_value(metadata, "pre-build-incremental"); + if (!pkg_pre_build.empty() && pkg_pre_build != device_pre_build) { + LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected " + << device_pre_build; return INSTALL_ERROR; } - value = android::base::GetProperty("ro.build.fingerprint", ""); - const std::string& pkg_pre_build_fingerprint = metadata["pre-build"]; - if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != value) { + auto device_fingerprint = android::base::GetProperty("ro.build.fingerprint", ""); + auto pkg_pre_build_fingerprint = get_value(metadata, "pre-build"); + if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != device_fingerprint) { LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint << " but expected " - << value; + << device_fingerprint; return INSTALL_ERROR; } @@ -194,10 +158,11 @@ static int check_newer_ab_build(ZipArchiveHandle zip) { int64_t pkg_post_timestamp = 0; // We allow to full update to the same version we are running, in case there // is a problem with the current copy of that version. - if (metadata["post-timestamp"].empty() || - !android::base::ParseInt(metadata["post-timestamp"].c_str(), &pkg_post_timestamp) || + auto pkg_post_timestamp_string = get_value(metadata, "post-timestamp"); + if (pkg_post_timestamp_string.empty() || + !android::base::ParseInt(pkg_post_timestamp_string, &pkg_post_timestamp) || pkg_post_timestamp < build_timestamp) { - if (metadata["ota-downgrade"] != "yes") { + if (get_value(metadata, "ota-downgrade") != "yes") { LOG(ERROR) << "Update package is older than the current build, expected a build " "newer than timestamp " << build_timestamp << " but package has timestamp " << pkg_post_timestamp @@ -213,13 +178,55 @@ static int check_newer_ab_build(ZipArchiveHandle zip) { return 0; } +int CheckPackageMetadata(const std::map& metadata, OtaType ota_type) { + auto package_ota_type = get_value(metadata, "ota-type"); + auto expected_ota_type = OtaTypeToString(ota_type); + if (ota_type != OtaType::AB && ota_type != OtaType::BRICK) { + LOG(INFO) << "Skip package metadata check for ota type " << expected_ota_type; + return 0; + } + + if (package_ota_type != expected_ota_type) { + LOG(ERROR) << "Unexpected ota package type, expects " << expected_ota_type << ", actual " + << package_ota_type; + return INSTALL_ERROR; + } + + auto device = android::base::GetProperty("ro.product.device", ""); + auto pkg_device = get_value(metadata, "pre-device"); + if (pkg_device != device || pkg_device.empty()) { + LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << device; + return INSTALL_ERROR; + } + + // We allow the package to not have any serialno; and we also allow it to carry multiple serial + // numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the + // verification if the device's serialno doesn't match any of these carried numbers. + auto pkg_serial_no = get_value(metadata, "serialno"); + if (!pkg_serial_no.empty()) { + auto device_serial_no = android::base::GetProperty("ro.serialno", ""); + bool serial_number_match = false; + for (const auto& number : android::base::Split(pkg_serial_no, "|")) { + if (device_serial_no == android::base::Trim(number)) { + serial_number_match = true; + } + } + if (!serial_number_match) { + LOG(ERROR) << "Package is for serial " << pkg_serial_no; + return INSTALL_ERROR; + } + } + + if (ota_type == OtaType::AB) { + return CheckAbSpecificMetadata(metadata); + } + + return 0; +} + int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd, std::vector* cmd) { CHECK(cmd != nullptr); - int ret = check_newer_ab_build(zip); - if (ret != 0) { - return ret; - } // For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset // in the zip file. @@ -311,20 +318,33 @@ static void log_max_temperature(int* max_temperature, const std::atomic& l static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache, std::vector* log_buffer, int retry_count, int* max_temperature) { - read_source_target_build(zip, log_buffer); + std::map metadata; + if (!ReadMetadataFromPackage(zip, &metadata)) { + LOG(ERROR) << "Failed to parse metadata in the zip file"; + return INSTALL_CORRUPT; + } + + bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false); + // Verifies against the metadata in the package first. + if (int check_status = is_ab ? CheckPackageMetadata(metadata, OtaType::AB) : 0; + check_status != 0) { + log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure)); + return check_status; + } + + ReadSourceTargetBuild(metadata, log_buffer); int pipefd[2]; pipe(pipefd); - - bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false); std::vector args; - int ret = is_ab ? SetUpAbUpdateCommands(package, zip, pipefd[1], &args) - : SetUpNonAbUpdateCommands(package, zip, retry_count, pipefd[1], &args); - if (ret) { + if (int update_status = + is_ab ? SetUpAbUpdateCommands(package, zip, pipefd[1], &args) + : SetUpNonAbUpdateCommands(package, zip, retry_count, pipefd[1], &args); + update_status != 0) { close(pipefd[0]); close(pipefd[1]); log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure)); - return ret; + return update_status; } // When executing the update binary contained in the package, the -- cgit v1.2.3