From 4d9e62d8a07b233da4d82a42eb30de64cf2b45bd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 11 May 2018 10:41:44 -0700 Subject: Add proto3 support for care_map Switching to the protobuf format helps to make the care_map more extensible. As we have such plans in the future, add the support to parse the protobuf message in the update_verifier. Bug: 77867897 Test: unit tests pass, update_verifier successfully verifies a care_map.pb Change-Id: I9fe83cb4dd3cc8d6fd0260f2a47338fe142d3938 --- update_verifier/Android.bp | 7 +++ update_verifier/care_map.proto | 31 ++++++++++ .../include/update_verifier/update_verifier.h | 10 ++- update_verifier/update_verifier.cpp | 72 ++++++++++++++-------- 4 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 update_verifier/care_map.proto (limited to 'update_verifier') diff --git a/update_verifier/Android.bp b/update_verifier/Android.bp index f6c7056d9..f4dc1f498 100644 --- a/update_verifier/Android.bp +++ b/update_verifier/Android.bp @@ -33,6 +33,7 @@ cc_library_static { ], srcs: [ + "care_map.proto", "update_verifier.cpp", ], @@ -49,6 +50,11 @@ cc_library_static { "libbase", "libcutils", ], + + proto: { + type: "lite", + export_proto_headers: true, + } } cc_binary { @@ -74,6 +80,7 @@ cc_binary { "libhardware", "libhidlbase", "liblog", + "libprotobuf-cpp-lite", "libutils", ], diff --git a/update_verifier/care_map.proto b/update_verifier/care_map.proto new file mode 100644 index 000000000..442ddd4a9 --- /dev/null +++ b/update_verifier/care_map.proto @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package UpdateVerifier; +option optimize_for = LITE_RUNTIME; + +message CareMap { + message PartitionInfo { + string name = 1; + string ranges = 2; + string id = 3; + string fingerprint = 4; + } + + repeated PartitionInfo partitions = 1; +} diff --git a/update_verifier/include/update_verifier/update_verifier.h b/update_verifier/include/update_verifier/update_verifier.h index 16b394e98..534384e1d 100644 --- a/update_verifier/include/update_verifier/update_verifier.h +++ b/update_verifier/include/update_verifier/update_verifier.h @@ -20,5 +20,13 @@ int update_verifier(int argc, char** argv); -// Exposed for testing purpose. +// 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. +// This function tries to process the care_map.txt as protobuf message; and falls back to use the +// plain text format if the parse failed. +// +// 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); diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp index dc7276326..5e5aa1819 100644 --- a/update_verifier/update_verifier.cpp +++ b/update_verifier/update_verifier.cpp @@ -60,6 +60,7 @@ #include #include +#include "care_map.pb.h" #include "otautil/rangeset.h" using android::sp; @@ -189,33 +190,12 @@ static bool read_blocks(const std::string& partition, const std::string& range_s return ret; } -// 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; - } +static bool process_care_map_plain_text(const std::string& care_map_contents) { // care_map file has up to six lines, where every two lines make a pair. Within each pair, the // first line has the partition name (e.g. "system"), while the second line holds the ranges of // all the blocks to verify. - 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"); + std::vector lines = + android::base::Split(android::base::Trim(care_map_contents), "\n"); if (lines.size() != 2 && lines.size() != 4 && lines.size() != 6) { LOG(ERROR) << "Invalid lines in care_map: found " << lines.size() << " lines, expecting 2 or 4 or 6 lines."; @@ -237,6 +217,50 @@ bool verify_image(const std::string& care_map_name) { return true; } +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; + } + + std::string file_content; + if (!android::base::ReadFdToString(care_map_fd.get(), &file_content)) { + PLOG(ERROR) << "Failed to read " << care_map_name; + return false; + } + + if (file_content.empty()) { + LOG(ERROR) << "Unexpected empty care map"; + return false; + } + + UpdateVerifier::CareMap care_map; + // Falls back to use the plain text version if we cannot parse the file as protobuf message. + if (!care_map.ParseFromString(file_content)) { + return process_care_map_plain_text(file_content); + } + + for (const auto& partition : care_map.partitions()) { + if (partition.name().empty()) { + LOG(ERROR) << "Unexpected empty partition name."; + return false; + } + if (partition.ranges().empty()) { + LOG(ERROR) << "Unexpected block ranges for partition " << partition.name(); + return false; + } + if (!read_blocks(partition.name(), partition.ranges())) { + return false; + } + } + + return true; +} + static int reboot_device() { if (android_reboot(ANDROID_RB_RESTART2, 0, nullptr) == -1) { LOG(ERROR) << "Failed to reboot."; -- cgit v1.2.3