diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2016-10-19 21:15:06 +0200 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2016-10-19 21:15:06 +0200 |
commit | fd796317c309a9c2423d6de1b0c87d1004efbec4 (patch) | |
tree | 53388e66db91793598030067dea27790a7f2c0de | |
parent | Merge "Add a unit test for applypatch_check" (diff) | |
parent | Verify wipe package when wiping A/B device in recovery. (diff) | |
download | android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.tar android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.tar.gz android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.tar.bz2 android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.tar.lz android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.tar.xz android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.tar.zst android_bootable_recovery-fd796317c309a9c2423d6de1b0c87d1004efbec4.zip |
-rw-r--r-- | bootloader.cpp | 134 | ||||
-rw-r--r-- | install.cpp | 66 | ||||
-rw-r--r-- | install.h | 17 | ||||
-rw-r--r-- | recovery.cpp | 73 | ||||
-rw-r--r-- | uncrypt/include/bootloader_message_writer.h | 35 | ||||
-rw-r--r-- | uncrypt/uncrypt.cpp | 19 |
6 files changed, 140 insertions, 204 deletions
diff --git a/bootloader.cpp b/bootloader.cpp deleted file mode 100644 index dad0bab30..000000000 --- a/bootloader.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <fs_mgr.h> - -#include <android-base/logging.h> -#include <android-base/unique_fd.h> - -#include "bootloader.h" -#include "roots.h" - -static int get_bootloader_message_block(bootloader_message* out, const Volume* v); -static int set_bootloader_message_block(const bootloader_message* in, const Volume* v); - -int get_bootloader_message(bootloader_message* out) { - Volume* v = volume_for_path("/misc"); - if (v == nullptr) { - LOG(ERROR) << "Cannot load volume /misc!"; - return -1; - } - if (strcmp(v->fs_type, "emmc") == 0) { - return get_bootloader_message_block(out, v); - } - LOG(ERROR) << "unknown misc partition fs_type \"" << v->fs_type << "\""; - return -1; -} - -int set_bootloader_message(const bootloader_message* in) { - Volume* v = volume_for_path("/misc"); - if (v == nullptr) { - LOG(ERROR) << "Cannot load volume /misc!"; - return -1; - } - if (strcmp(v->fs_type, "emmc") == 0) { - return set_bootloader_message_block(in, v); - } - LOG(ERROR) << "unknown misc partition fs_type \"" << v->fs_type << "\""; - return -1; -} - -// ------------------------------------ -// for misc partitions on block devices -// ------------------------------------ - -static void wait_for_device(const char* fn) { - int tries = 0; - int ret; - do { - ++tries; - struct stat buf; - ret = stat(fn, &buf); - if (ret == -1) { - printf("failed to stat \"%s\" try %d: %s\n", fn, tries, strerror(errno)); - sleep(1); - } - } while (ret && tries < 10); - - if (ret) { - printf("failed to stat \"%s\"\n", fn); - } -} - -static int get_bootloader_message_block(bootloader_message* out, - const Volume* v) { - wait_for_device(v->blk_device); - FILE* f = fopen(v->blk_device, "rb"); - if (f == nullptr) { - PLOG(ERROR) << "failed to open \"" << v->blk_device << "\""; - return -1; - } - bootloader_message temp; - int count = fread(&temp, sizeof(temp), 1, f); - if (count != 1) { - PLOG(ERROR) << "failed to read \"" << v->blk_device << "\""; - return -1; - } - if (fclose(f) != 0) { - PLOG(ERROR) << "failed to close \"" << v->blk_device << "\""; - return -1; - } - memcpy(out, &temp, sizeof(temp)); - return 0; -} - -static int set_bootloader_message_block(const bootloader_message* in, - const Volume* v) { - wait_for_device(v->blk_device); - android::base::unique_fd fd(open(v->blk_device, O_WRONLY | O_SYNC)); - if (fd == -1) { - PLOG(ERROR) << "failed to open \"" << v->blk_device << "\""; - return -1; - } - - size_t written = 0; - const uint8_t* start = reinterpret_cast<const uint8_t*>(in); - size_t total = sizeof(*in); - while (written < total) { - ssize_t wrote = TEMP_FAILURE_RETRY(write(fd, start + written, total - written)); - if (wrote == -1) { - PLOG(ERROR) << "failed to write " << total << " bytes, " << written - << " bytes written"; - return -1; - } - written += wrote; - } - - if (fsync(fd) == -1) { - PLOG(ERROR) << "failed to fsync \"" << v->blk_device << "\""; - return -1; - } - return 0; -} diff --git a/install.cpp b/install.cpp index c98715231..0f9088a7a 100644 --- a/install.cpp +++ b/install.cpp @@ -71,22 +71,33 @@ static int parse_build_number(const std::string& str) { return -1; } -// 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<std::string>& log_buffer) { +bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data) { ZipString metadata_path(METADATA_PATH); ZipEntry meta_entry; + if (meta_data == nullptr) { + LOG(ERROR) << "string* meta_data can't be nullptr"; + return false; + } if (FindEntry(zip, metadata_path, &meta_entry) != 0) { LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package"; - return; + return false; } - std::string meta_data(meta_entry.uncompressed_length, '\0'); - if (ExtractToMemory(zip, &meta_entry, reinterpret_cast<uint8_t*>(&meta_data[0]), + meta_data->resize(meta_entry.uncompressed_length, '\0'); + if (ExtractToMemory(zip, &meta_entry, reinterpret_cast<uint8_t*>(&(*meta_data)[0]), meta_entry.uncompressed_length) != 0) { LOG(ERROR) << "Failed to read metadata in update package"; - return; + 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<std::string>& log_buffer) { + std::string meta_data; + if (!read_metadata_from_package(zip, &meta_data)) { + return; + } // Examples of the pre-build and post-build strings in metadata: // pre-build-incremental=2943039 // post-build-incremental=2951741 @@ -301,33 +312,16 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, return INSTALL_CORRUPT; } - // Load keys. - std::vector<Certificate> loadedKeys; - if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) { - LOG(ERROR) << "Failed to load keys"; - sysReleaseMap(&map); - return INSTALL_CORRUPT; - } - LOG(INFO) << loadedKeys.size() << " key(s) loaded from " << PUBLIC_KEYS_FILE; - // Verify package. - ui->Print("Verifying update package...\n"); - - auto t0 = std::chrono::system_clock::now(); - int err = verify_file(map.addr, map.length, loadedKeys); - std::chrono::duration<double> duration = std::chrono::system_clock::now() - t0; - ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err); - if (err != VERIFY_SUCCESS) { - LOG(ERROR) << "signature verification failed"; + if (!verify_package(map.addr, map.length)) { log_buffer.push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure)); - sysReleaseMap(&map); return INSTALL_CORRUPT; } // Try to open the package. ZipArchiveHandle zip; - err = OpenArchiveFromMemory(map.addr, map.length, path, &zip); + int err = OpenArchiveFromMemory(map.addr, map.length, path, &zip); if (err != 0) { LOG(ERROR) << "Can't open " << path << " : " << ErrorCodeString(err); log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure)); @@ -403,3 +397,25 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, return result; } + +bool verify_package(const unsigned char* package_data, size_t package_size) { + std::vector<Certificate> loadedKeys; + if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) { + LOG(ERROR) << "Failed to load keys"; + return false; + } + LOG(INFO) << loadedKeys.size() << " key(s) loaded from " << PUBLIC_KEYS_FILE; + + // Verify package. + ui->Print("Verifying update package...\n"); + auto t0 = std::chrono::system_clock::now(); + int err = verify_file(const_cast<unsigned char*>(package_data), package_size, loadedKeys); + std::chrono::duration<double> duration = std::chrono::system_clock::now() - t0; + ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err); + if (err != VERIFY_SUCCESS) { + LOG(ERROR) << "Signature verification failed"; + LOG(ERROR) << "error: " << kZipVerificationFailure; + return false; + } + return true; +} @@ -17,11 +17,10 @@ #ifndef RECOVERY_INSTALL_H_ #define RECOVERY_INSTALL_H_ -#include "common.h" +#include <string> +#include <ziparchive/zip_archive.h> -#ifdef __cplusplus -extern "C" { -#endif +#include "common.h" enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED, INSTALL_RETRY }; @@ -31,8 +30,12 @@ enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SK int install_package(const char* root_path, bool* wipe_cache, const char* install_file, bool needs_mount, int retry_count); -#ifdef __cplusplus -} -#endif +// Verify the package by ota keys. Return true if the package is verified successfully, +// otherwise return false. +bool verify_package(const unsigned char* package_data, size_t package_size); + +// Read meta data file of the package, write its content in the string pointed by meta_data. +// Return true if succeed, otherwise return false. +bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data); #endif // RECOVERY_INSTALL_H_ diff --git a/recovery.cpp b/recovery.cpp index dc17c9527..683d101f5 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -86,6 +86,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 }, }; @@ -902,12 +903,76 @@ 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) { + LOG(ERROR) << "wipe_package_size is zero"; + return false; + } + std::string wipe_package; + std::string err_str; + if (!read_wipe_package(&wipe_package, wipe_package_size, &err_str)) { + PLOG(ERROR) << "Failed to read wipe package"; + return false; + } + if (!verify_package(reinterpret_cast<const unsigned char*>(wipe_package.data()), + wipe_package.size())) { + LOG(ERROR) << "Failed to verify package"; + return false; + } + + // Extract metadata + ZipArchiveHandle zip; + int err = OpenArchiveFromMemory(reinterpret_cast<void*>(&wipe_package[0]), + wipe_package.size(), "wipe_package", &zip); + if (err != 0) { + LOG(ERROR) << "Can't open wipe package : " << ErrorCodeString(err); + return false; + } + std::string metadata; + if (!read_metadata_from_package(&zip, &metadata)) { + CloseArchive(zip); + return false; + } + CloseArchive(zip); + + // Check metadata + std::vector<std::string> 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)) { + LOG(ERROR) << "Failed to verify wipe package"; + return false; + } std::string partition_list; if (!android::base::ReadFileToString(RECOVERY_WIPE, &partition_list)) { LOG(ERROR) << "failed to read \"" << RECOVERY_WIPE << "\""; @@ -1426,6 +1491,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; @@ -1462,6 +1528,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; } @@ -1607,7 +1676,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) { diff --git a/uncrypt/include/bootloader_message_writer.h b/uncrypt/include/bootloader_message_writer.h deleted file mode 100644 index e0ca3f44a..000000000 --- a/uncrypt/include/bootloader_message_writer.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#ifndef BOOTLOADER_MESSAGE_WRITER_H -#define BOOTLOADER_MESSAGE_WRITER_H - -#ifdef __cplusplus -#include <string> -#include <vector> - -bool clear_bootloader_message(std::string* err); - -bool write_bootloader_message(const std::vector<std::string>& options, std::string* err); - -#else -#include <stdbool.h> - -// C Interface. -bool write_bootloader_message(const char* options); -#endif - -#endif // BOOTLOADER_MESSAGE_WRITER_H diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp index 8b4d8ef8c..a5d692bbb 100644 --- a/uncrypt/uncrypt.cpp +++ b/uncrypt/uncrypt.cpp @@ -528,14 +528,31 @@ static bool setup_bcb(const int socket) { return false; } LOG(INFO) << " received command: [" << content << "] (" << content.size() << ")"; + std::vector<std::string> options = android::base::Split(content, "\n"); + std::string wipe_package; + for (auto& option : options) { + if (android::base::StartsWith(option, "--wipe_package=")) { + std::string path = option.substr(strlen("--wipe_package=")); + if (!android::base::ReadFileToString(path, &wipe_package)) { + PLOG(ERROR) << "failed to read " << path; + return false; + } + option = android::base::StringPrintf("--wipe_package_size=%zu", wipe_package.size()); + } + } // c8. setup the bcb command std::string err; - if (!write_bootloader_message({content}, &err)) { + if (!write_bootloader_message(options, &err)) { LOG(ERROR) << "failed to set bootloader message: " << err; write_status_to_socket(-1, socket); return false; } + if (!wipe_package.empty() && !write_wipe_package(wipe_package, &err)) { + PLOG(ERROR) << "failed to set wipe package: " << err; + write_status_to_socket(-1, socket); + return false; + } // c10. send "100" status write_status_to_socket(100, socket); return true; |