update_verifier.cpp revision d007cf2da29f05eee002dd33e6c04262f709b274
17197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao/* 27197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * Copyright (C) 2015 The Android Open Source Project 37197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * 47197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * Licensed under the Apache License, Version 2.0 (the "License"); 57197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * you may not use this file except in compliance with the License. 67197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * You may obtain a copy of the License at 77197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * 87197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * http://www.apache.org/licenses/LICENSE-2.0 97197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * 107197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * Unless required by applicable law or agreed to in writing, software 117197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * distributed under the License is distributed on an "AS IS" BASIS, 127197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * See the License for the specific language governing permissions and 147197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * limitations under the License. 157197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao */ 167197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 177197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao/* 187197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * This program verifies the integrity of the partitions after an A/B OTA 197197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * update. It gets invoked by init, and will only perform the verification if 207197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * it's the first boot post an A/B OTA update. 217197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * 227197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * It relies on dm-verity to capture any corruption on the partitions being 237197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * verified. dm-verity must be in enforcing mode, so that it will reboot the 247197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * device on dm-verity failures. When that happens, the bootloader should 25d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu * mark the slot as unbootable and stops trying. Other dm-verity modes ( 26d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu * for example, veritymode=EIO) are not accepted and simply lead to a 27d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu * verification failure. 287197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * 297197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * The current slot will be marked as having booted successfully if the 307197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * verifier reaches the end after the verification. 317197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao * 327197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao */ 337197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 34d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <errno.h> 35d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <fcntl.h> 36d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <stdio.h> 377197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao#include <string.h> 387197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 39d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <string> 40d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <vector> 41d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 42d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <android-base/file.h> 437b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu#include <android-base/logging.h> 44d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <android-base/parseint.h> 45d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <android-base/strings.h> 46d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <android-base/unique_fd.h> 47d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu#include <cutils/properties.h> 487197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao#include <hardware/boot_control.h> 497197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 50d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xuconstexpr auto CARE_MAP_FILE = "/data/ota_package/care_map.txt"; 51d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xuconstexpr int BLOCKSIZE = 4096; 52d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 53d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xustatic bool read_blocks(const std::string& blk_device_prefix, const std::string& range_str) { 54d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu char slot_suffix[PROPERTY_VALUE_MAX]; 55d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu property_get("ro.boot.slot_suffix", slot_suffix, ""); 56d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu std::string blk_device = blk_device_prefix + std::string(slot_suffix); 57d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY))); 58d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (fd.get() == -1) { 59d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu PLOG(ERROR) << "Error reading partition " << blk_device; 60d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 61d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 62d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 63d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // For block range string, first integer 'count' equals 2 * total number of valid ranges, 64d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // followed by 'count' number comma separated integers. Every two integers reprensent a 65d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // block range with the first number included in range but second number not included. 66d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // For example '4,64536,65343,74149,74150' represents: [64536,65343) and [74149,74150). 67d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu std::vector<std::string> ranges = android::base::Split(range_str, ","); 68d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu size_t range_count; 69d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu bool status = android::base::ParseUint(ranges[0].c_str(), &range_count); 70d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (!status || (range_count == 0) || (range_count % 2 != 0) || 71d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu (range_count != ranges.size()-1)) { 72d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Error in parsing range string."; 73d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 74d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 75d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 76d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu size_t blk_count = 0; 77d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu for (size_t i = 1; i < ranges.size(); i += 2) { 78d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu unsigned int range_start, range_end; 79d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu bool parse_status = android::base::ParseUint(ranges[i].c_str(), &range_start); 80d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu parse_status = parse_status && android::base::ParseUint(ranges[i+1].c_str(), &range_end); 81d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (!parse_status || range_start >= range_end) { 82d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Invalid range pair " << ranges[i] << ", " << ranges[i+1]; 83d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 84d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 85d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 86d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (lseek64(fd.get(), static_cast<off64_t>(range_start) * BLOCKSIZE, SEEK_SET) == -1) { 87d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu PLOG(ERROR) << "lseek to " << range_start << " failed"; 88d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 89d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 90d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 91d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu size_t size = (range_end - range_start) * BLOCKSIZE; 92d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu std::vector<uint8_t> buf(size); 93d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (!android::base::ReadFully(fd.get(), buf.data(), size)) { 94d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu PLOG(ERROR) << "Failed to read blocks " << range_start << " to " << range_end; 95d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 96d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 97d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu blk_count += (range_end - range_start); 98d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 99d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 100d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(INFO) << "Finished reading " << blk_count << " blocks on " << blk_device; 101d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return true; 102d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu} 103d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 104d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xustatic bool verify_image(const std::string& care_map_name) { 105d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu android::base::unique_fd care_map_fd(TEMP_FAILURE_RETRY(open(care_map_name.c_str(), O_RDONLY))); 106d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // If the device is flashed before the current boot, it may not have care_map.txt 107d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // in /data/ota_package. To allow the device to continue booting in this situation, 108d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // we should print a warning and skip the block verification. 109d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (care_map_fd.get() == -1) { 110d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(WARNING) << "Warning: care map " << care_map_name << " not found."; 111d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return true; 112d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 113d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // Care map file has four lines (two lines if vendor partition is not present): 114d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // First line has the block device name, e.g./dev/block/.../by-name/system. 115d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // Second line holds all ranges of blocks to verify. 116d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // The next two lines have the same format but for vendor partition. 117d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu std::string file_content; 118d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (!android::base::ReadFdToString(care_map_fd.get(), &file_content)) { 119d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Error reading care map contents to string."; 120d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 121d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 122d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 123d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu std::vector<std::string> lines; 124d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu lines = android::base::Split(android::base::Trim(file_content), "\n"); 125d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (lines.size() != 2 && lines.size() != 4) { 126d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Invalid lines in care_map: found " << lines.size() 127d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu << " lines, expecting 2 or 4 lines."; 128d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 129d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 130d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 131d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu for (size_t i = 0; i < lines.size(); i += 2) { 132d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (!read_blocks(lines[i], lines[i+1])) { 133d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return false; 134d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 135d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 136d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 137d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return true; 138d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu} 139d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu 1407197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Baoint main(int argc, char** argv) { 1417197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao for (int i = 1; i < argc; i++) { 1427b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu LOG(INFO) << "Started with arg " << i << ": " << argv[i]; 1437197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao } 1447197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 1457197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao const hw_module_t* hw_module; 1467197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao if (hw_get_module("bootctrl", &hw_module) != 0) { 1477b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu LOG(ERROR) << "Error getting bootctrl module."; 1487197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao return -1; 1497197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao } 1507197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 1517197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao boot_control_module_t* module = reinterpret_cast<boot_control_module_t*>( 1527197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao const_cast<hw_module_t*>(hw_module)); 1537197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao module->init(module); 1547197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 1557197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao unsigned current_slot = module->getCurrentSlot(module); 156612161ef1c9e36add87ba40c30bc4092786cddb6Tao Bao int is_successful= module->isSlotMarkedSuccessful(module, current_slot); 1577b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu LOG(INFO) << "Booting slot " << current_slot << ": isSlotMarkedSuccessful=" << is_successful; 1587197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 159612161ef1c9e36add87ba40c30bc4092786cddb6Tao Bao if (is_successful == 0) { 1607197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao // The current slot has not booted successfully. 161d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu char verity_mode[PROPERTY_VALUE_MAX]; 162d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu if (property_get("ro.boot.veritymode", verity_mode, "") == -1) { 163d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Failed to get dm-verity mode."; 164d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return -1; 165d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } else if (strcasecmp(verity_mode, "eio") == 0) { 166d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // We shouldn't see verity in EIO mode if the current slot hasn't booted 167d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu // successfully before. Therefore, fail the verification when veritymode=eio. 168d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Found dm-verity in EIO mode, skip verification."; 169d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return -1; 170d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } else if (strcmp(verity_mode, "enforcing") != 0) { 171d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Unexpected dm-verity mode : " << verity_mode << ", expecting enforcing."; 172d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return -1; 173d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } else if (!verify_image(CARE_MAP_FILE)) { 174d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu LOG(ERROR) << "Failed to verify all blocks in care map file."; 175d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu return -1; 176d007cf2da29f05eee002dd33e6c04262f709b274Tianjie Xu } 1777197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 1787197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao int ret = module->markBootSuccessful(module); 1797197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao if (ret != 0) { 1807b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu LOG(ERROR) << "Error marking booted successfully: " << strerror(-ret); 1817197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao return -1; 1827197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao } 1837b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu LOG(INFO) << "Marked slot " << current_slot << " as booted successfully."; 1847197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao } 1857197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao 1867b0ad9c638176dc364dabb65b363536055a0ea9cTianjie Xu LOG(INFO) << "Leaving update_verifier."; 1877197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao return 0; 1887197ee0e39bebea3a1bbe5d980f4dbf1cfe58136Tao Bao} 189