From 6faf0265c9b58db2c15b53f6d29025629d52f882 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Thu, 9 Jun 2016 14:09:39 -0700 Subject: Verify wipe package when wiping A/B device in recovery. To increase the security of wiping A/B devices, let uncrypt write wipe package in misc partition. Then recovery verifies the wipe package before wiping the device. Bug: 29159185 Change-Id: I186691bab1928d3dc036bc5542abd64a81bc2168 --- recovery.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 65e1a7bba..6df9b6fae 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -61,6 +61,7 @@ #include "install.h" #include "minui/minui.h" #include "minzip/DirUtil.h" +#include "minzip/Zip.h" #include "roots.h" #include "ui.h" #include "unique_fd.h" @@ -84,6 +85,7 @@ static const struct option OPTIONS[] = { { "reason", required_argument, NULL, 'r' }, { "security", no_argument, NULL, 'e'}, { "wipe_ab", no_argument, NULL, 0 }, + { "wipe_package_size", required_argument, NULL, 0 }, { NULL, 0, NULL, 0 }, }; @@ -904,12 +906,75 @@ static bool secure_wipe_partition(const std::string& partition) { return true; } +// Check if the wipe package matches expectation: +// 1. verify the package. +// 2. check metadata (ota-type, pre-device and serial number if having one). +static bool check_wipe_package(size_t wipe_package_size) { + if (wipe_package_size == 0) { + LOGE("wipe_package_size is zero.\n"); + return false; + } + std::string wipe_package; + if (!read_wipe_package(wipe_package_size, &wipe_package)) { + LOGE("Failed to read wipe package.\n"); + return false; + } + if (!verify_package(reinterpret_cast(wipe_package.data()), + wipe_package.size())) { + LOGE("Failed to verify package.\n"); + return false; + } + + // Extract metadata + ZipArchive zip; + int err = mzOpenZipArchive(reinterpret_cast(&wipe_package[0]), + wipe_package.size(), &zip); + if (err != 0) { + LOGE("Can't open wipe package: %s\n", err != -1 ? strerror(err) : "bad"); + return false; + } + std::string metadata; + if (!read_metadata_from_package(&zip, &metadata)) { + mzCloseZipArchive(&zip); + return false; + } + mzCloseZipArchive(&zip); + + // Check metadata + std::vector lines = android::base::Split(metadata, "\n"); + bool ota_type_matched = false; + bool device_type_matched = false; + bool has_serial_number = false; + bool serial_number_matched = false; + for (const auto& line : lines) { + if (line == "ota-type=BRICK") { + ota_type_matched = true; + } else if (android::base::StartsWith(line, "pre-device=")) { + std::string device_type = line.substr(strlen("pre-device=")); + char real_device_type[PROPERTY_VALUE_MAX]; + property_get("ro.build.product", real_device_type, ""); + device_type_matched = (device_type == real_device_type); + } else if (android::base::StartsWith(line, "serialno=")) { + std::string serial_no = line.substr(strlen("serialno=")); + char real_serial_no[PROPERTY_VALUE_MAX]; + property_get("ro.serialno", real_serial_no, ""); + has_serial_number = true; + serial_number_matched = (serial_no == real_serial_no); + } + } + return ota_type_matched && device_type_matched && (!has_serial_number || serial_number_matched); +} + // Wipe the current A/B device, with a secure wipe of all the partitions in // RECOVERY_WIPE. -static bool wipe_ab_device() { +static bool wipe_ab_device(size_t wipe_package_size) { ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); + if (!check_wipe_package(wipe_package_size)) { + LOGE("Failed to verify wipe package\n"); + return false; + } std::string partition_list; if (!android::base::ReadFileToString(RECOVERY_WIPE, &partition_list)) { LOGE("failed to read \"%s\".\n", RECOVERY_WIPE); @@ -1418,6 +1483,7 @@ int main(int argc, char **argv) { bool should_wipe_data = false; bool should_wipe_cache = false; bool should_wipe_ab = false; + size_t wipe_package_size = 0; bool show_text = false; bool sideload = false; bool sideload_auto_reboot = false; @@ -1455,6 +1521,9 @@ int main(int argc, char **argv) { if (strcmp(OPTIONS[option_index].name, "wipe_ab") == 0) { should_wipe_ab = true; break; + } else if (strcmp(OPTIONS[option_index].name, "wipe_package_size") == 0) { + android::base::ParseUint(optarg, &wipe_package_size); + break; } break; } @@ -1597,7 +1666,7 @@ int main(int argc, char **argv) { status = INSTALL_ERROR; } } else if (should_wipe_ab) { - if (!wipe_ab_device()) { + if (!wipe_ab_device(wipe_package_size)) { status = INSTALL_ERROR; } } else if (sideload) { -- cgit v1.2.3