diff options
-rw-r--r-- | lib/avb/libavb/avb_ab_flow.c | 441 | ||||
-rw-r--r-- | lib/avb/libavb/avb_ab_flow.h | 226 | ||||
-rw-r--r-- | lib/avb/libavb_ab/avb_ab_flow.c | 16 |
3 files changed, 16 insertions, 667 deletions
diff --git a/lib/avb/libavb/avb_ab_flow.c b/lib/avb/libavb/avb_ab_flow.c deleted file mode 100644 index bcd6740..0000000 --- a/lib/avb/libavb/avb_ab_flow.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (C) 2016 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_ab_flow.h" -#include "avb_util.h" - -bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) { - /* Ensure magic is correct. */ - if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) { - avb_error("Magic is incorrect.\n"); - return false; - } - - avb_memcpy(dest, src, sizeof(AvbABData)); - dest->crc32 = avb_be32toh(dest->crc32); - - /* Ensure we don't attempt to access any fields if the major version - * is not supported. - */ - if (dest->version_major > AVB_AB_MAJOR_VERSION) { - avb_error("No support for given major version.\n"); - return false; - } - - /* Bail if CRC32 doesn't match. */ - if (dest->crc32 != - avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) { - avb_error("CRC32 does not match.\n"); - return false; - } - - return true; -} - -void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, - AvbABData* dest) { - avb_memcpy(dest, src, sizeof(AvbABData)); - dest->crc32 = avb_htobe32( - avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))); -} - -void avb_ab_data_init(AvbABData* data) { - avb_memset(data, '\0', sizeof(AvbABData)); - avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN); - data->version_major = AVB_AB_MAJOR_VERSION; - data->version_minor = AVB_AB_MINOR_VERSION; - data->slots[0].priority = AVB_AB_MAX_PRIORITY; - data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; - data->slots[0].successful_boot = 0; - data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1; - data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; - data->slots[1].successful_boot = 0; -} - -/* The AvbABData struct is stored 2048 bytes into the 'misc' partition - * following the 'struct bootloader_message' field. The struct is - * compatible with the guidelines in bootable/recovery/bootloader.h - - * e.g. it is stored in the |slot_suffix| field, starts with a - * NUL-byte, and is 32 bytes long. - */ -#define AB_METADATA_MISC_PARTITION_OFFSET 2048 - -AvbIOResult avb_ab_data_read(AvbOps* ops, AvbABData* data) { - AvbABData serialized; - AvbIOResult io_ret; - size_t num_bytes_read; - - io_ret = - ops->read_from_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET, - sizeof(AvbABData), &serialized, &num_bytes_read); - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - return AVB_IO_RESULT_ERROR_OOM; - } else if (io_ret != AVB_IO_RESULT_OK || - num_bytes_read != sizeof(AvbABData)) { - avb_error("Error reading A/B metadata.\n"); - return AVB_IO_RESULT_ERROR_IO; - } - - if (!avb_ab_data_verify_and_byteswap(&serialized, data)) { - avb_error( - "Error validating A/B metadata from disk. " - "Resetting and writing new A/B metadata to disk.\n"); - avb_ab_data_init(data); - return avb_ab_data_write(ops, data); - } - - return AVB_IO_RESULT_OK; -} - -AvbIOResult avb_ab_data_write(AvbOps* ops, const AvbABData* data) { - AvbABData serialized; - AvbIOResult io_ret; - - avb_ab_data_update_crc_and_byteswap(data, &serialized); - io_ret = - ops->write_to_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET, - sizeof(AvbABData), &serialized); - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - return AVB_IO_RESULT_ERROR_OOM; - } else if (io_ret != AVB_IO_RESULT_OK) { - avb_error("Error writing A/B metadata.\n"); - return AVB_IO_RESULT_ERROR_IO; - } - return AVB_IO_RESULT_OK; -} - -static bool slot_is_bootable(AvbABSlotData* slot) { - return slot->priority > 0 && - (slot->successful_boot || (slot->tries_remaining > 0)); -} - -static void slot_set_unbootable(AvbABSlotData* slot) { - slot->priority = 0; - slot->tries_remaining = 0; - slot->successful_boot = 0; -} - -/* Ensure all unbootable and/or illegal states are marked as the - * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0, - * and successful_boot=0. - */ -static void slot_normalize(AvbABSlotData* slot) { - if (slot->priority > 0) { - if (slot->tries_remaining == 0 && !slot->successful_boot) { - /* We've exhausted all tries -> unbootable. */ - slot_set_unbootable(slot); - } - if (slot->tries_remaining > 0 && slot->successful_boot) { - /* Illegal state - avb_ab_mark_slot_successful() will clear - * tries_remaining when setting successful_boot. - */ - slot_set_unbootable(slot); - } - } else { - slot_set_unbootable(slot); - } -} - -static const char* slot_suffixes[2] = {"_a", "_b"}; - -/* Helper function to load metadata - returns AVB_IO_RESULT_OK on - * success, error code otherwise. - */ -static AvbIOResult load_metadata(AvbOps* ops, AvbABData* ab_data, - AvbABData* ab_data_orig) { - AvbIOResult io_ret; - - io_ret = ops->read_ab_metadata(ops, ab_data); - if (io_ret != AVB_IO_RESULT_OK) { - avb_error("I/O error while loading A/B metadata.\n"); - return io_ret; - } - *ab_data_orig = *ab_data; - - /* Ensure data is normalized, e.g. illegal states will be marked as - * unbootable and all unbootable states are represented with - * (priority=0, tries_remaining=0, successful_boot=0). - */ - slot_normalize(&ab_data->slots[0]); - slot_normalize(&ab_data->slots[1]); - return AVB_IO_RESULT_OK; -} - -/* Writes A/B metadata to disk only if it has changed - returns - * AVB_IO_RESULT_OK on success, error code otherwise. - */ -static AvbIOResult save_metadata_if_changed(AvbOps* ops, AvbABData* ab_data, - AvbABData* ab_data_orig) { - if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) { - avb_debug("Writing A/B metadata to disk.\n"); - return ops->write_ab_metadata(ops, ab_data); - } - return AVB_IO_RESULT_OK; -} - -AvbABFlowResult avb_ab_flow(AvbOps* ops, - const char* const* requested_partitions, - AvbSlotVerifyData** out_data) { - AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; - AvbSlotVerifyData* data = NULL; - AvbABFlowResult ret; - AvbABData ab_data, ab_data_orig; - size_t slot_index_to_boot, n; - bool is_device_unlocked; - AvbIOResult io_ret; - - io_ret = load_metadata(ops, &ab_data, &ab_data_orig); - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; - goto out; - } else if (io_ret != AVB_IO_RESULT_OK) { - ret = AVB_AB_FLOW_RESULT_ERROR_IO; - goto out; - } - - /* Validate all bootable slots. */ - for (n = 0; n < 2; n++) { - if (slot_is_bootable(&ab_data.slots[n])) { - AvbSlotVerifyResult verify_result; - verify_result = avb_slot_verify(ops, requested_partitions, - slot_suffixes[n], &slot_data[n]); - if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) { - if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_OOM) { - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; - goto out; - } - if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_IO) { - ret = AVB_AB_FLOW_RESULT_ERROR_IO; - goto out; - } - avb_errorv("Error verifying slot ", slot_suffixes[n], " with result ", - avb_slot_verify_result_to_string(verify_result), - " - setting unbootable.\n", NULL); - slot_set_unbootable(&ab_data.slots[n]); - } - } - } - - if (slot_is_bootable(&ab_data.slots[0]) && - slot_is_bootable(&ab_data.slots[1])) { - if (ab_data.slots[1].priority > ab_data.slots[0].priority) { - slot_index_to_boot = 1; - } else { - slot_index_to_boot = 0; - } - } else if (slot_is_bootable(&ab_data.slots[0])) { - slot_index_to_boot = 0; - } else if (slot_is_bootable(&ab_data.slots[1])) { - slot_index_to_boot = 1; - } else { - /* No bootable slots! */ - avb_error("No bootable slots found.\n"); - ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; - goto out; - } - - /* Update stored rollback index such that the stored rollback index - * is the largest value supporting all currently bootable slots. Do - * this for every rollback index slot. - */ - for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) { - uint64_t rollback_index_value = 0; - - if (slot_data[0] != NULL && slot_data[1] != NULL) { - uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n]; - uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n]; - rollback_index_value = - (a_rollback_index < b_rollback_index ? a_rollback_index - : b_rollback_index); - } else if (slot_data[0] != NULL) { - rollback_index_value = slot_data[0]->rollback_indexes[n]; - } else if (slot_data[1] != NULL) { - rollback_index_value = slot_data[1]->rollback_indexes[n]; - } - - if (rollback_index_value != 0) { - uint64_t current_rollback_index_value; - io_ret = ops->read_rollback_index(ops, n, ¤t_rollback_index_value); - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; - goto out; - } else if (io_ret != AVB_IO_RESULT_OK) { - avb_error("Error getting rollback index for slot.\n"); - ret = AVB_AB_FLOW_RESULT_ERROR_IO; - goto out; - } - if (current_rollback_index_value != rollback_index_value) { - io_ret = ops->write_rollback_index(ops, n, rollback_index_value); - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; - goto out; - } else if (io_ret != AVB_IO_RESULT_OK) { - avb_error("Error setting stored rollback index.\n"); - ret = AVB_AB_FLOW_RESULT_ERROR_IO; - goto out; - } - } - } - } - - /* Finally, select this slot. */ - avb_assert(slot_data[slot_index_to_boot] != NULL); - data = slot_data[slot_index_to_boot]; - slot_data[slot_index_to_boot] = NULL; - ret = AVB_AB_FLOW_RESULT_OK; - - /* ... and decrement tries remaining, if applicable. */ - if (!ab_data.slots[slot_index_to_boot].successful_boot && - ab_data.slots[slot_index_to_boot].tries_remaining > 0) { - ab_data.slots[slot_index_to_boot].tries_remaining -= 1; - } - -out: - /* do not touch metadata in UNLOCK state */ - io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; - goto fail; - } else if (io_ret != AVB_IO_RESULT_OK) { - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; - avb_error("Error getting device state.\n"); - goto fail; - } - if (is_device_unlocked) - goto ret; - -fail: - io_ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig); - if (io_ret != AVB_IO_RESULT_OK) { - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; - } else { - ret = AVB_AB_FLOW_RESULT_ERROR_IO; - } - if (data != NULL) { - avb_slot_verify_data_free(data); - data = NULL; - } - } - -ret: - for (n = 0; n < 2; n++) { - if (slot_data[n] != NULL) { - avb_slot_verify_data_free(slot_data[n]); - } - } - - if (out_data != NULL) { - *out_data = data; - } else { - if (data != NULL) { - avb_slot_verify_data_free(data); - } - } - - return ret; -} - -AvbIOResult avb_ab_mark_slot_active(AvbOps* ops, unsigned int slot_number) { - AvbABData ab_data, ab_data_orig; - unsigned int other_slot_number; - AvbIOResult ret; - - avb_assert(slot_number < 2); - - ret = load_metadata(ops, &ab_data, &ab_data_orig); - if (ret != AVB_IO_RESULT_OK) { - goto out; - } - - /* Make requested slot top priority, unsuccessful, and with max tries. */ - ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY; - ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; - ab_data.slots[slot_number].successful_boot = 0; - - /* Ensure other slot doesn't have as high a priority. */ - other_slot_number = 1 - slot_number; - if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) { - ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1; - } - - ret = AVB_IO_RESULT_OK; - -out: - if (ret == AVB_IO_RESULT_OK) { - ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig); - } - return ret; -} - -AvbIOResult avb_ab_mark_slot_unbootable(AvbOps* ops, unsigned int slot_number) { - AvbABData ab_data, ab_data_orig; - AvbIOResult ret; - - avb_assert(slot_number < 2); - - ret = load_metadata(ops, &ab_data, &ab_data_orig); - if (ret != AVB_IO_RESULT_OK) { - goto out; - } - - slot_set_unbootable(&ab_data.slots[slot_number]); - - ret = AVB_IO_RESULT_OK; - -out: - if (ret == AVB_IO_RESULT_OK) { - ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig); - } - return ret; -} - -AvbIOResult avb_ab_mark_slot_successful(AvbOps* ops, unsigned int slot_number) { - AvbABData ab_data, ab_data_orig; - AvbIOResult ret; - - avb_assert(slot_number < 2); - - ret = load_metadata(ops, &ab_data, &ab_data_orig); - if (ret != AVB_IO_RESULT_OK) { - goto out; - } - - if (!slot_is_bootable(&ab_data.slots[slot_number])) { - avb_error("Cannot mark unbootable slot as successful.\n"); - ret = AVB_IO_RESULT_OK; - goto out; - } - - ab_data.slots[slot_number].tries_remaining = 0; - ab_data.slots[slot_number].successful_boot = 1; - - ret = AVB_IO_RESULT_OK; - -out: - if (ret == AVB_IO_RESULT_OK) { - ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig); - } - return ret; -} diff --git a/lib/avb/libavb/avb_ab_flow.h b/lib/avb/libavb/avb_ab_flow.h deleted file mode 100644 index c19f846..0000000 --- a/lib/avb/libavb/avb_ab_flow.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION) -#error "Never include this file directly, include libavb.h instead." -#endif - -#ifndef AVB_AB_FLOW_H_ -#define AVB_AB_FLOW_H_ - -#include "avb_ops.h" -#include "avb_slot_verify.h" -#include "avb_vbmeta_image.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Magic for the A/B struct when serialized. */ -#define AVB_AB_MAGIC "\0AB0" -#define AVB_AB_MAGIC_LEN 4 - -/* Versioning for the on-disk A/B metadata - keep in sync with avbtool. */ -#define AVB_AB_MAJOR_VERSION 1 -#define AVB_AB_MINOR_VERSION 0 - -/* Size of AvbABData struct. */ -#define AVB_AB_DATA_SIZE 32 - -/* Maximum values for slot data */ -#define AVB_AB_MAX_PRIORITY 15 -#define AVB_AB_MAX_TRIES_REMAINING 7 - -/* Struct used for recording per-slot metadata. - * - * When serialized, data is stored in network byte-order. - */ -typedef struct AvbABSlotData { - /* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY, - * both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY - * being the highest. The special value 0 is used to indicate the - * slot is unbootable. - */ - uint8_t priority; - - /* Number of times left attempting to boot this slot ranging from 0 - * to AVB_AB_MAX_TRIES_REMAINING. - */ - uint8_t tries_remaining; - - /* Non-zero if this slot has booted successfully, 0 otherwise. */ - uint8_t successful_boot; - - /* Reserved for future use. */ - uint8_t reserved[1]; -} AVB_ATTR_PACKED AvbABSlotData; - -/* Struct used for recording A/B metadata. - * - * When serialized, data is stored in network byte-order. - */ -typedef struct AvbABData { - /* Magic number used for identification - see AVB_AB_MAGIC. */ - uint8_t magic[AVB_AB_MAGIC_LEN]; - - /* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */ - uint8_t version_major; - uint8_t version_minor; - - /* Padding to ensure |slots| field start eight bytes in. */ - uint8_t reserved1[2]; - - /* Per-slot metadata. */ - AvbABSlotData slots[2]; - - /* Reserved for future use. */ - uint8_t reserved2[12]; - - /* CRC32 of all 28 bytes preceding this field. */ - uint32_t crc32; -} AVB_ATTR_PACKED AvbABData; - -/* Copies |src| to |dest|, byte-swapping fields in the - * process. Returns false if the data is invalid (e.g. wrong magic, - * wrong CRC32 etc.), true otherwise. - */ -bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest); - -/* Copies |src| to |dest|, byte-swapping fields in the process. Also - * updates the |crc32| field in |dest|. - */ -void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, AvbABData* dest); - -/* Initializes |data| such that it has two slots and both slots have - * maximum tries remaining. The CRC is not set. - */ -void avb_ab_data_init(AvbABData* data); - -/* Reads A/B metadata from the 'misc' partition using |ops|. Returned - * data is properly byteswapped. Returns AVB_IO_RESULT_OK on - * success, error code otherwise. - * - * If the data read from disk is invalid (e.g. wrong magic or CRC - * checksum failure), the metadata will be reset using - * avb_ab_data_init() and then written to disk. - */ -AvbIOResult avb_ab_data_read(AvbOps* ops, AvbABData* data); - -/* Writes A/B metadata to the 'misc' partition using |ops|. This will - * byteswap and update the CRC as needed. Returns AVB_IO_RESULT_OK on - * success, error code otherwise. - */ -AvbIOResult avb_ab_data_write(AvbOps* ops, const AvbABData* data); - -/* Return codes used in avb_ab_flow(), see that function for - * documentation of each value. - */ -typedef enum { - AVB_AB_FLOW_RESULT_OK, - AVB_AB_FLOW_RESULT_ERROR_OOM, - AVB_AB_FLOW_RESULT_ERROR_IO, - AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS -} AvbABFlowResult; - -/* High-level function to select a slot to boot. The following - * algorithm is used: - * - * 1. A/B metadata is loaded and validated using the - * read_ab_metadata() operation. Typically this means it's read from - * the 'misc' partition and if it's invalid then it's reset using - * avb_ab_data_init() and this reset metadata is returned. - * - * 2. All bootable slots listed in the A/B metadata are verified using - * avb_slot_verify(). If a slot fails verification, it will be marked - * as unbootable in the A/B metadata and the metadata will be saved to - * disk before returning. - * - * 3. If there are no bootable slots, the value - * AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS is returned. - * - * 4. For each bootable slot, the Stored Rollback Indexes are updated - * such that for each rollback index slot, the Stored Rollback Index - * is the largest number smaller than or equal to the Rollback Index - * of each slot. - * - * 5. The bootable slot with the highest priority is selected and - * returned in |out_data|. If this slot is already marked as - * successful, the A/B metadata is not modified. However, if the slot - * is not marked as bootable its |tries_remaining| count is - * decremented and the A/B metadata is saved to disk before returning. - * In either case the value AVB_AB_FLOW_RESULT_OK is returning. - * - * The partitions to load is given in |requested_partitions| as a - * NULL-terminated array of NUL-terminated strings. Typically the - * |requested_partitions| array only contains a single item for the - * boot partition, 'boot'. - * - * If an I/O operation - such as loading/saving metadata or checking - * rollback indexes - fail, the value AVB_AB_FLOW_RESULT_ERROR_IO is - * returned. - * - * If memory allocation fails, AVB_AB_FLOW_RESULT_ERROR_OOM is - * returned. - * - * Reasonable behavior for handling AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS - * is to initiate device recovery (which is device-dependent). - */ -AvbABFlowResult avb_ab_flow(AvbOps* ops, - const char* const* requested_partitions, - AvbSlotVerifyData** out_data); - -/* Marks the slot with the given slot number as active. Returns - * AVB_IO_RESULT_OK on success, error code otherwise. - * - * This function is typically used by the OS updater when completing - * an update. It can also used by the firmware for implementing the - * "set_active" command. - */ -AvbIOResult avb_ab_mark_slot_active(AvbOps* ops, unsigned int slot_number); - -/* Marks the slot with the given slot number as unbootable. Returns - * AVB_IO_RESULT_OK on success, error code otherwise. - * - * This function is typically used by the OS updater before writing to - * a slot. - */ -AvbIOResult avb_ab_mark_slot_unbootable(AvbOps* ops, unsigned int slot_number); - -/* Marks the slot with the given slot number as having booted - * successfully. Returns AVB_IO_RESULT_OK on success, error code - * otherwise. - * - * Calling this on an unbootable slot is an error - AVB_IO_RESULT_OK - * will be returned yet the function will have no side-effects. - * - * This function is typically used by the OS updater after having - * confirmed that the slot works as intended. - */ -AvbIOResult avb_ab_mark_slot_successful(AvbOps* ops, unsigned int slot_number); - -#ifdef __cplusplus -} -#endif - -#endif /* AVB_AB_FLOW_H_ */ diff --git a/lib/avb/libavb_ab/avb_ab_flow.c b/lib/avb/libavb_ab/avb_ab_flow.c index da8e4ea..c6a37a9 100644 --- a/lib/avb/libavb_ab/avb_ab_flow.c +++ b/lib/avb/libavb_ab/avb_ab_flow.c @@ -205,6 +205,7 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, AvbABFlowResult ret; AvbABData ab_data, ab_data_orig; size_t slot_index_to_boot, n; + bool is_device_unlocked; AvbIOResult io_ret; io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); @@ -314,6 +315,20 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, } out: + /* do not touch metadata in UNLOCK state */ + io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; + goto fail; + } else if (io_ret != AVB_IO_RESULT_OK) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; + avb_error("Error getting device state.\n"); + goto fail; + } + if (is_device_unlocked) + goto ret; + +fail: io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); if (io_ret != AVB_IO_RESULT_OK) { if (io_ret == AVB_IO_RESULT_ERROR_OOM) { @@ -327,6 +342,7 @@ out: } } +ret: for (n = 0; n < 2; n++) { if (slot_data[n] != NULL) { avb_slot_verify_data_free(slot_data[n]); |