From 3a580159499c7d3eace638882040cd6e16aa7729 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Wed, 12 Apr 2017 15:50:47 -0400 Subject: [PATCH] Move enable/disable-verity code from avbctl to libavb_user. Also build a libavb_user library and make avbctl link with it. Also add a function to get whether verity is currrently enabled and expose this through a new get-verity sub-command in avbctl. Make avbctl a bit smarter and tell the user if verity is already enabled/disabled when trying to enable/disable it. Also remind the user to reboot if we're changing the state. With this change it's possible to make adbd link with libavb_user for implementing 'adb {enable,disable}-verity' command. Also stop linking avbctl with the boot_control HAL and just access the ro.boot.slot or ro.boot.slot_suffix properties (aka "androidboot.slot" or "androidboot.slot_suffix" on the kernel cmdline). This way external/avb should be usable on N without manually having to patch in the O->N boot_control changes. Complete AvbOps in libavb_user so it can be used with avb_slot_verify() in user space. Also add more documentation explaining what this particular AvbOps implementation is intended to do. Bug: 34124301 Test: All unit tests pass. Test: Manually tested on UEFI-based bootloader. Change-Id: I0b5080ff102c29f2c4c0e92a9737590d450967a9 --- Android.mk | 99 +++++++++------- libavb_user/avb_ops_user.c | 50 ++++++++ libavb_user/avb_ops_user.h | 25 +++- libavb_user/avb_user_verity.c | 213 +++++++++++++++++++++++++++++++++ libavb_user/avb_user_verity.h | 63 ++++++++++ libavb_user/libavb_user.h | 1 + tools/avbctl/avbctl.cc | 217 +++++++++++----------------------- 7 files changed, 470 insertions(+), 198 deletions(-) create mode 100644 libavb_user/avb_user_verity.c create mode 100644 libavb_user/avb_user_verity.h diff --git a/Android.mk b/Android.mk index 901fe02..e053be6 100644 --- a/Android.mk +++ b/Android.mk @@ -44,6 +44,25 @@ avb_common_ldflags := \ -Wl,--gc-sections \ -rdynamic +# The sources that make up libavb (excluding sysdeps). +libavb_sources := \ + libavb/avb_chain_partition_descriptor.c \ + libavb/avb_crc32.c \ + libavb/avb_crypto.c \ + libavb/avb_descriptor.c \ + libavb/avb_footer.c \ + libavb/avb_hash_descriptor.c \ + libavb/avb_hashtree_descriptor.c \ + libavb/avb_kernel_cmdline_descriptor.c \ + libavb/avb_property_descriptor.c \ + libavb/avb_rsa.c \ + libavb/avb_sha256.c \ + libavb/avb_sha512.c \ + libavb/avb_slot_verify.c \ + libavb/avb_util.c \ + libavb/avb_vbmeta_image.c \ + libavb/avb_version.c + include $(CLEAR_VARS) LOCAL_SRC_FILES := avbtool LOCAL_MODULE_CLASS := EXECUTABLES @@ -52,7 +71,8 @@ LOCAL_IS_HOST_MODULE := true LOCAL_MODULE := avbtool include $(BUILD_PREBUILT) -# Build libavb for the target (for e.g. fs_mgr usage). +# Build libavb for the target - this is a static library that depends +# on only libc and doesn't drag in any other dependencies. include $(CLEAR_VARS) LOCAL_MODULE := libavb LOCAL_MODULE_HOST_OS := linux @@ -61,23 +81,30 @@ LOCAL_CLANG := true LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_ENABLE_DEBUG -DAVB_COMPILATION LOCAL_LDFLAGS := $(avb_common_ldflags) LOCAL_SRC_FILES := \ - libavb/avb_chain_partition_descriptor.c \ - libavb/avb_crc32.c \ - libavb/avb_crypto.c \ - libavb/avb_descriptor.c \ - libavb/avb_footer.c \ - libavb/avb_hash_descriptor.c \ - libavb/avb_hashtree_descriptor.c \ - libavb/avb_kernel_cmdline_descriptor.c \ - libavb/avb_property_descriptor.c \ - libavb/avb_rsa.c \ - libavb/avb_sha256.c \ - libavb/avb_sha512.c \ - libavb/avb_slot_verify.c \ + $(libavb_sources) \ + libavb/avb_sysdeps_posix.c +include $(BUILD_STATIC_LIBRARY) + +# Build libavb_user for the target - in addition to libavb, it +# includes libavb_ab, libavb_user and also depends on libbase and +# libfs_mgr. +include $(CLEAR_VARS) +LOCAL_MODULE := libavb_user +LOCAL_MODULE_HOST_OS := linux +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +LOCAL_CLANG := true +LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_ENABLE_DEBUG -DAVB_COMPILATION +LOCAL_LDFLAGS := $(avb_common_ldflags) +LOCAL_SHARED_LIBRARIES := \ + libbase +LOCAL_STATIC_LIBRARIES := \ + libfs_mgr +LOCAL_SRC_FILES := \ + $(libavb_sources) \ libavb/avb_sysdeps_posix.c \ - libavb/avb_util.c \ - libavb/avb_vbmeta_image.c \ - libavb/avb_version.c + libavb_ab/avb_ab_flow.c \ + libavb_user/avb_ops_user.c \ + libavb_user/avb_user_verity.c include $(BUILD_STATIC_LIBRARY) # Build avbctl for the target. @@ -91,18 +118,11 @@ LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_COMPILATION -DAVB_ENABLE_DEBUG LOCAL_CPPFLAGS := $(avb_common_cppflags) LOCAL_LDFLAGS := $(avb_common_ldflags) LOCAL_STATIC_LIBRARIES := \ - libavb \ + libavb_user \ libfs_mgr LOCAL_SHARED_LIBRARIES := \ - libbase \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - libutils \ - android.hardware.boot@1.0 + libbase LOCAL_SRC_FILES := \ - libavb_ab/avb_ab_flow.c \ - libavb_user/avb_ops_user.c \ tools/avbctl/avbctl.cc include $(BUILD_EXECUTABLE) @@ -116,21 +136,7 @@ LOCAL_CLANG := true LOCAL_CFLAGS := $(avb_common_cflags) -fno-stack-protector -DAVB_ENABLE_DEBUG -DAVB_COMPILATION LOCAL_LDFLAGS := $(avb_common_ldflags) LOCAL_SRC_FILES := \ - libavb/avb_chain_partition_descriptor.c \ - libavb/avb_crc32.c \ - libavb/avb_crypto.c \ - libavb/avb_descriptor.c \ - libavb/avb_footer.c \ - libavb/avb_hash_descriptor.c \ - libavb/avb_hashtree_descriptor.c \ - libavb/avb_kernel_cmdline_descriptor.c \ - libavb/avb_property_descriptor.c \ - libavb/avb_rsa.c \ - libavb/avb_sha256.c \ - libavb/avb_sha512.c \ - libavb/avb_slot_verify.c \ - libavb/avb_util.c \ - libavb/avb_vbmeta_image.c \ + $(libavb_sources) \ libavb/avb_version.c include $(BUILD_HOST_STATIC_LIBRARY) @@ -220,16 +226,17 @@ include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := bootctrl.avb LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_REQUIRED_MODULES := libavb LOCAL_SRC_FILES := \ - libavb_ab/avb_ab_flow.c \ - libavb_user/avb_ops_user.c \ boot_control/boot_control_avb.c LOCAL_CLANG := true LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_COMPILATION LOCAL_LDFLAGS := $(avb_common_ldflags) -LOCAL_SHARED_LIBRARIES := libbase libcutils -LOCAL_STATIC_LIBRARIES := libfs_mgr libavb +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils +LOCAL_STATIC_LIBRARIES := \ + libavb_user \ + libfs_mgr LOCAL_POST_INSTALL_CMD := \ $(hide) mkdir -p $(TARGET_OUT_SHARED_LIBRARIES)/hw && \ ln -sf bootctrl.avb.so $(TARGET_OUT_SHARED_LIBRARIES)/hw/bootctrl.default.so diff --git a/libavb_user/avb_ops_user.c b/libavb_user/avb_ops_user.c index a95ce4d..1611450 100644 --- a/libavb_user/avb_ops_user.c +++ b/libavb_user/avb_ops_user.c @@ -221,6 +221,51 @@ static AvbIOResult write_to_partition(AvbOps* ops, return ret; } +static AvbIOResult validate_vbmeta_public_key( + AvbOps* ops, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_is_trusted) { + if (out_is_trusted != NULL) { + *out_is_trusted = true; + } + return AVB_IO_RESULT_OK; +} + +static AvbIOResult read_rollback_index(AvbOps* ops, + size_t rollback_index_location, + uint64_t* out_rollback_index) { + if (out_rollback_index != NULL) { + *out_rollback_index = 0; + } + return AVB_IO_RESULT_OK; +} + +static AvbIOResult write_rollback_index(AvbOps* ops, + size_t rollback_index_location, + uint64_t rollback_index) { + return AVB_IO_RESULT_OK; +} + +static AvbIOResult read_is_device_unlocked(AvbOps* ops, bool* out_is_unlocked) { + if (out_is_unlocked != NULL) { + *out_is_unlocked = true; + } + return AVB_IO_RESULT_OK; +} + +static AvbIOResult get_unique_guid_for_partition(AvbOps* ops, + const char* partition, + char* guid_buf, + size_t guid_buf_size) { + if (guid_buf != NULL && guid_buf_size > 0) { + guid_buf[0] = '\0'; + } + return AVB_IO_RESULT_OK; +} + AvbOps* avb_ops_user_new(void) { AvbOps* ops; @@ -240,6 +285,11 @@ AvbOps* avb_ops_user_new(void) { ops->read_from_partition = read_from_partition; ops->write_to_partition = write_to_partition; + ops->validate_vbmeta_public_key = validate_vbmeta_public_key; + ops->read_rollback_index = read_rollback_index; + ops->write_rollback_index = write_rollback_index; + ops->read_is_device_unlocked = read_is_device_unlocked; + ops->get_unique_guid_for_partition = get_unique_guid_for_partition; ops->ab_ops->read_ab_metadata = avb_ab_data_read; ops->ab_ops->write_ab_metadata = avb_ab_data_write; diff --git a/libavb_user/avb_ops_user.h b/libavb_user/avb_ops_user.h index 4e547b9..3e02295 100644 --- a/libavb_user/avb_ops_user.h +++ b/libavb_user/avb_ops_user.h @@ -31,8 +31,29 @@ extern "C" { #endif -/* Allocates an AvbOps instance suitable for use in userspace on the - * device. Returns NULL on OOM. +/* Allocates an AvbOps instance suitable for use in Android userspace + * on the device. Returns NULL on OOM. + * + * The returned AvbOps has the following characteristics: + * + * - The read_from_partition() and write_to_partition() operations are + * implemented, however for these operations to work the fstab file + * on the device must have a /misc entry using a by-name device file + * scheme and the containing by-name/ subdirectory must have files + * for other partitions. + * + * - The remaining operations are implemented and never fails and + * return the following values: + * - validate_vbmeta_public_key(): always returns |true|. + * - read_rollback_index(): returns 0 for any roolback index. + * - write_rollback_index(): no-op. + * - read_is_device_unlocked(): always returns |true|. + * - get_unique_guid_for_partition(): always returns the empty string. + * + * - The |ab_ops| member will point to a valid AvbABOps instance + * implemented via libavb_ab/. This should only be used if the AVB + * A/B stack is used on the device. This is what is used in + * bootctrl.avb boot control implementation. * * Free with avb_ops_user_free(). */ diff --git a/libavb_user/avb_user_verity.c b/libavb_user/avb_user_verity.c new file mode 100644 index 0000000..8098909 --- /dev/null +++ b/libavb_user/avb_user_verity.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "avb_user_verity.h" + +/* Maximum allow length (in bytes) of a partition name, including + * ab_suffix. + */ +#define AVB_PART_NAME_MAX_SIZE 32 + +/* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by + * |ab_suffix| into |vbmeta_image|. No validation, verification, or + * byteswapping is performed. + * + * If successful, |true| is returned and the partition it was loaded + * from is returned in |out_partition_name| and the offset on said + * partition is returned in |out_vbmeta_offset|. + */ +bool load_top_level_vbmeta_header( + AvbOps* ops, + const char* ab_suffix, + uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE], + char out_partition_name[AVB_PART_NAME_MAX_SIZE], + uint64_t* out_vbmeta_offset) { + uint64_t vbmeta_offset = 0; + size_t num_read; + bool ret = false; + AvbIOResult io_res; + + /* Construct full partition name. */ + if (!avb_str_concat(out_partition_name, + AVB_PART_NAME_MAX_SIZE, + "vbmeta", + 6, + ab_suffix, + avb_strlen(ab_suffix))) { + avb_error("Partition name and suffix does not fit.\n"); + goto out; + } + + /* Only read the header, not the entire struct. */ + io_res = ops->read_from_partition(ops, + out_partition_name, + vbmeta_offset, + AVB_VBMETA_IMAGE_HEADER_SIZE, + vbmeta_image, + &num_read); + if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) { + AvbFooter footer; + + /* Try looking for the vbmeta struct in 'boot' via the footer. */ + if (!avb_str_concat(out_partition_name, + AVB_PART_NAME_MAX_SIZE, + "boot", + 4, + ab_suffix, + avb_strlen(ab_suffix))) { + avb_error("Partition name and suffix does not fit.\n"); + goto out; + } + io_res = ops->read_from_partition(ops, + out_partition_name, + -AVB_FOOTER_SIZE, + AVB_FOOTER_SIZE, + &footer, + &num_read); + if (io_res != AVB_IO_RESULT_OK) { + avb_errorv("Error loading footer from partition '", + out_partition_name, + "'\n", + NULL); + goto out; + } + + if (avb_memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) { + avb_errorv("Data from '", + out_partition_name, + "' does not look like a vbmeta footer.\n", + NULL); + goto out; + } + + vbmeta_offset = avb_be64toh(footer.vbmeta_offset); + io_res = ops->read_from_partition(ops, + out_partition_name, + vbmeta_offset, + AVB_VBMETA_IMAGE_HEADER_SIZE, + vbmeta_image, + &num_read); + } + + if (io_res != AVB_IO_RESULT_OK) { + avb_errorv( + "Error loading from partition '", out_partition_name, "'\n", NULL); + goto out; + } + + if (out_vbmeta_offset != NULL) { + *out_vbmeta_offset = vbmeta_offset; + } + + ret = true; + +out: + return ret; +} + +bool avb_user_verity_get(AvbOps* ops, + const char* ab_suffix, + bool* out_verity_enabled) { + uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */ + char partition_name[AVB_PART_NAME_MAX_SIZE]; /* 32 bytes. */ + AvbVBMetaImageHeader* header; + uint32_t flags; + bool ret = false; + + if (!load_top_level_vbmeta_header( + ops, ab_suffix, vbmeta_image, partition_name, NULL)) { + goto out; + } + + if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { + avb_errorv("Data from '", + partition_name, + "' does not look like a vbmeta header.\n", + NULL); + goto out; + } + + /* Set/clear the HASHTREE_DISABLED bit, as requested. */ + header = (AvbVBMetaImageHeader*)vbmeta_image; + flags = avb_be32toh(header->flags); + + if (out_verity_enabled != NULL) { + *out_verity_enabled = !(flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED); + } + + ret = true; + +out: + return ret; +} + +bool avb_user_verity_set(AvbOps* ops, + const char* ab_suffix, + bool enable_verity) { + uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */ + char partition_name[AVB_PART_NAME_MAX_SIZE]; /* 32 bytes. */ + uint64_t vbmeta_offset; + AvbIOResult io_res; + AvbVBMetaImageHeader* header; + uint32_t flags; + bool ret = false; + + if (!load_top_level_vbmeta_header( + ops, ab_suffix, vbmeta_image, partition_name, &vbmeta_offset)) { + goto out; + } + + if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { + avb_errorv("Data from '", + partition_name, + "' does not look like a vbmeta header.\n", + NULL); + goto out; + } + + /* Set/clear the HASHTREE_DISABLED bit, as requested. */ + header = (AvbVBMetaImageHeader*)vbmeta_image; + flags = avb_be32toh(header->flags); + flags &= ~AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED; + if (!enable_verity) { + flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED; + } + header->flags = avb_htobe32(flags); + + /* Write the header. */ + io_res = ops->write_to_partition(ops, + partition_name, + vbmeta_offset, + AVB_VBMETA_IMAGE_HEADER_SIZE, + vbmeta_image); + if (io_res != AVB_IO_RESULT_OK) { + avb_errorv("Error writing to partition '", partition_name, "'\n", NULL); + goto out; + } + + ret = true; + +out: + return ret; +} diff --git a/libavb_user/avb_user_verity.h b/libavb_user/avb_user_verity.h new file mode 100644 index 0000000..139cfb1 --- /dev/null +++ b/libavb_user/avb_user_verity.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef AVB_USER_VERITY_H_ +#define AVB_USER_VERITY_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function to enable or disable dm-verity for an entire slot. The + * passed in |ops| should be obtained via avb_ops_user_new(). The + * |ab_suffix| parameter should specify the slot to modify including + * the leading underscore (e.g. "_a" or "_b"). The |enable_verity| + * parameter should be set to |true| to enable dm-verity and |false| + * to disable. + * + * Returns |true| if the operation succeeded, otherwise |false|. + */ +bool avb_user_verity_set(AvbOps* ops, + const char* ab_suffix, + bool enable_verity); + +/* Gets whether dm-verity is enabled for an entire slot. The passed in + * |ops| should be obtained via avb_ops_user_new(). The |ab_suffix| + * parameter should specify the slot to query including the leading + * underscore (e.g. "_a" or "_b"). The result is returned in the + * |out_verity_enabled| parameter. + * + * Returns |true| if the operation succeeded, otherwise |false|. + */ +bool avb_user_verity_get(AvbOps* ops, + const char* ab_suffix, + bool* out_verity_enabled); + +#ifdef __cplusplus +} +#endif + +#endif /* AVB_USER_VERITY_H_ */ diff --git a/libavb_user/libavb_user.h b/libavb_user/libavb_user.h index 4b34bdd..b9d10ab 100644 --- a/libavb_user/libavb_user.h +++ b/libavb_user/libavb_user.h @@ -34,6 +34,7 @@ #define AVB_INSIDE_LIBAVB_USER_H #include "avb_ops_user.h" +#include "avb_user_verity.h" #undef AVB_INSIDE_LIBAVB_USER_H #endif /* LIBAVB_USER_H_ */ diff --git a/tools/avbctl/avbctl.cc b/tools/avbctl/avbctl.cc index 0842c59..9d83f0b 100644 --- a/tools/avbctl/avbctl.cc +++ b/tools/avbctl/avbctl.cc @@ -26,16 +26,10 @@ #include #include -#include +#include #include -using android::sp; -using android::hardware::hidl_string; -using android::hardware::Return; -using android::hardware::boot::V1_0::IBootControl; -using android::hardware::boot::V1_0::Slot; - namespace { /* Prints program usage to |where|. */ @@ -47,178 +41,103 @@ void usage(FILE* where, int /* argc */, char* argv[]) { " %s COMMAND\n" "\n" "Commands:\n" + " %s get-verity - Prints whether verity is enabled in " + "current slot.\n" " %s disable-verity - Disable verity in current slot.\n" " %s enable-verity - Enable verity in current slot.\n", argv[0], argv[0], argv[0], + argv[0], argv[0]); } -/* Returns the A/B suffix the device booted from or the empty string - * if A/B is not in use. +/* Function to enable and disable dm-verity. The |ops| parameter + * should be an |AvbOps| from libavb_user. */ -std::string get_ab_suffix(sp module) { - std::string suffix = ""; - - if (module != nullptr) { - uint32_t num_slots = module->getNumberSlots(); - if (num_slots > 1) { - Slot cur_slot = module->getCurrentSlot(); - Return ret = - module->getSuffix(cur_slot, [&suffix](const hidl_string& value) { - suffix = std::string(value.c_str()); - }); - if (!ret.isOk()) { - fprintf(stderr, "Error getting suffix for slot %d.\n", cur_slot); - } - } - } - - return suffix; -} +int do_set_verity(AvbOps* ops, + const std::string& ab_suffix, + bool enable_verity) { + bool verity_enabled; -/* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by - * |ab_suffix| into |vbmeta_image|. No validation, verification, or - * byteswapping is performed. - * - * If successful, |true| is returned and the partition it was loaded - * from is returned in |out_partition_name| and the offset on said - * partition is returned in |out_vbmeta_offset|. - */ -bool load_top_level_vbmeta_header( - AvbOps* ops, - const std::string& ab_suffix, - uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE], - std::string* out_partition_name, - uint64_t* out_vbmeta_offset) { - std::string partition_name = std::string("vbmeta") + ab_suffix; - uint64_t vbmeta_offset = 0; - - // Only read the header. - size_t num_read; - AvbIOResult io_res = ops->read_from_partition(ops, - partition_name.c_str(), - vbmeta_offset, - AVB_VBMETA_IMAGE_HEADER_SIZE, - vbmeta_image, - &num_read); - if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) { - AvbFooter footer; - // Try looking for the vbmeta struct in 'boot' via the footer. - partition_name = std::string("boot") + ab_suffix; - io_res = ops->read_from_partition(ops, - partition_name.c_str(), - -AVB_FOOTER_SIZE, - AVB_FOOTER_SIZE, - &footer, - &num_read); - if (io_res != AVB_IO_RESULT_OK) { - fprintf(stderr, - "Error loading footer from partition '%s' (%d).\n", - partition_name.c_str(), - io_res); - return false; - } + if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) { + fprintf(stderr, "Error getting whether verity is enabled.\n"); + return EX_SOFTWARE; + } - if (memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) { - fprintf(stderr, - "Data from '%s' does not look like a vbmeta footer.\n", - partition_name.c_str()); - return false; + if ((verity_enabled && enable_verity) || + (!verity_enabled && !enable_verity)) { + fprintf(stdout, + "verity is already %s", + verity_enabled ? "enabled" : "disabled"); + if (ab_suffix != "") { + fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } - - vbmeta_offset = avb_be64toh(footer.vbmeta_offset); - io_res = ops->read_from_partition(ops, - partition_name.c_str(), - vbmeta_offset, - AVB_VBMETA_IMAGE_HEADER_SIZE, - vbmeta_image, - &num_read); + fprintf(stdout, ".\n"); + return EX_OK; } - if (io_res != AVB_IO_RESULT_OK) { - fprintf(stderr, - "Error loading from offset %" PRIu64 " of partition '%s' (%d).\n", - vbmeta_offset, - partition_name.c_str(), - io_res); - return false; + if (!avb_user_verity_set(ops, ab_suffix.c_str(), enable_verity)) { + fprintf(stderr, "Error setting verity.\n"); + return EX_SOFTWARE; } - if (out_partition_name != nullptr) { - *out_partition_name = partition_name; - } - if (out_vbmeta_offset != nullptr) { - *out_vbmeta_offset = vbmeta_offset; + fprintf( + stdout, "Successfully %s verity", enable_verity ? "enabled" : "disabled"); + if (ab_suffix != "") { + fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } - return true; + fprintf(stdout, ". Reboot the device for changes to take effect.\n"); + + return EX_OK; } -/* Function to enable and disable dm-verity. The |ops| parameter - * should be an |AvbOps| from libavb_user and |module| can either be - * |nullptr| or a valid boot_control module. +/* Function to query if dm-verity is enabled. The |ops| parameter + * should be an |AvbOps| from libavb_user. */ -int do_set_verity(AvbOps* ops, sp module, bool enable_verity) { - uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; // 256 bytes. - std::string ab_suffix; - std::string partition_name; - uint64_t vbmeta_offset; - AvbIOResult io_res; - - ab_suffix = get_ab_suffix(module); +int do_get_verity(AvbOps* ops, const std::string& ab_suffix) { + bool verity_enabled; - if (!load_top_level_vbmeta_header( - ops, ab_suffix, vbmeta_image, &partition_name, &vbmeta_offset)) { + if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) { + fprintf(stderr, "Error getting whether verity is enabled.\n"); return EX_SOFTWARE; } - if (memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { - fprintf(stderr, - "Data from '%s' does not look like a vbmeta header.\n", - partition_name.c_str()); - return EX_SOFTWARE; + fprintf(stdout, "verity is %s", verity_enabled ? "enabled" : "disabled"); + if (ab_suffix != "") { + fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } + fprintf(stdout, ".\n"); + + return EX_OK; +} - // Set/clear the HASHTREE_DISABLED bit, as requested. - AvbVBMetaImageHeader* header = - reinterpret_cast(vbmeta_image); - uint32_t flags = avb_be32toh(header->flags); - flags &= ~AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED; - if (!enable_verity) { - flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED; +/* Helper function to get A/B suffix, if any. If the device isn't + * using A/B the empty string is returned. Otherwise either "_a", + * "_b", ... is returned. + * + * Note that since sometime in O androidboot.slot_suffix is deprecated + * and androidboot.slot should be used instead. Since bootloaders may + * be out of sync with the OS, we check both and for extra safety + * prepend a leading underscore if there isn't one already. + */ +std::string get_ab_suffix() { + std::string ab_suffix = android::base::GetProperty("ro.boot.slot_suffix", ""); + if (ab_suffix == "") { + ab_suffix = android::base::GetProperty("ro.boot.slot", ""); } - header->flags = avb_htobe32(flags); - - // Write the header. - io_res = ops->write_to_partition(ops, - partition_name.c_str(), - vbmeta_offset, - AVB_VBMETA_IMAGE_HEADER_SIZE, - vbmeta_image); - if (io_res != AVB_IO_RESULT_OK) { - fprintf(stderr, - "Error writing to offset %" PRIu64 " of partition '%s' (%d).\n", - vbmeta_offset, - partition_name.c_str(), - io_res); - return EX_SOFTWARE; + if (ab_suffix.size() > 0 && ab_suffix[0] != '_') { + ab_suffix = std::string("_") + ab_suffix; } - - fprintf(stdout, - "Successfully %s verity on %s.\n", - enable_verity ? "enabled" : "disabled", - partition_name.c_str()); - - return EX_OK; + return ab_suffix; } } // namespace int main(int argc, char* argv[]) { int ret; - sp module; AvbOps* ops = nullptr; + std::string ab_suffix = get_ab_suffix(); if (argc < 2) { usage(stderr, argc, argv); @@ -233,14 +152,12 @@ int main(int argc, char* argv[]) { goto out; } - // Failing to get the boot_control HAL is not a fatal error - it can - // happen if A/B is not in use, in which case |nullptr| is returned. - module = IBootControl::getService(); - if (strcmp(argv[1], "disable-verity") == 0) { - ret = do_set_verity(ops, module, false); + ret = do_set_verity(ops, ab_suffix, false); } else if (strcmp(argv[1], "enable-verity") == 0) { - ret = do_set_verity(ops, module, true); + ret = do_set_verity(ops, ab_suffix, true); + } else if (strcmp(argv[1], "get-verity") == 0) { + ret = do_get_verity(ops, ab_suffix); } else { usage(stderr, argc, argv); ret = EX_USAGE;