137a7bc39SJason Zhu /* 237a7bc39SJason Zhu * Copyright (C) 2016 The Android Open Source Project 337a7bc39SJason Zhu * 437a7bc39SJason Zhu * Permission is hereby granted, free of charge, to any person 537a7bc39SJason Zhu * obtaining a copy of this software and associated documentation 637a7bc39SJason Zhu * files (the "Software"), to deal in the Software without 737a7bc39SJason Zhu * restriction, including without limitation the rights to use, copy, 837a7bc39SJason Zhu * modify, merge, publish, distribute, sublicense, and/or sell copies 937a7bc39SJason Zhu * of the Software, and to permit persons to whom the Software is 1037a7bc39SJason Zhu * furnished to do so, subject to the following conditions: 1137a7bc39SJason Zhu * 1237a7bc39SJason Zhu * The above copyright notice and this permission notice shall be 1337a7bc39SJason Zhu * included in all copies or substantial portions of the Software. 1437a7bc39SJason Zhu * 1537a7bc39SJason Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1637a7bc39SJason Zhu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1737a7bc39SJason Zhu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1837a7bc39SJason Zhu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 1937a7bc39SJason Zhu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2037a7bc39SJason Zhu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2137a7bc39SJason Zhu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2237a7bc39SJason Zhu * SOFTWARE. 2337a7bc39SJason Zhu */ 2437a7bc39SJason Zhu 2537a7bc39SJason Zhu #include <android_avb/avb_ab_flow.h> 2637a7bc39SJason Zhu 2737a7bc39SJason Zhu bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) { 2837a7bc39SJason Zhu /* Ensure magic is correct. */ 2937a7bc39SJason Zhu if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) { 3037a7bc39SJason Zhu avb_error("Magic is incorrect.\n"); 3137a7bc39SJason Zhu return false; 3237a7bc39SJason Zhu } 3337a7bc39SJason Zhu 3437a7bc39SJason Zhu avb_memcpy(dest, src, sizeof(AvbABData)); 3537a7bc39SJason Zhu dest->crc32 = avb_be32toh(dest->crc32); 3637a7bc39SJason Zhu 3737a7bc39SJason Zhu /* Ensure we don't attempt to access any fields if the major version 3837a7bc39SJason Zhu * is not supported. 3937a7bc39SJason Zhu */ 4037a7bc39SJason Zhu if (dest->version_major > AVB_AB_MAJOR_VERSION) { 4137a7bc39SJason Zhu avb_error("No support for given major version.\n"); 4237a7bc39SJason Zhu return false; 4337a7bc39SJason Zhu } 4437a7bc39SJason Zhu 4537a7bc39SJason Zhu /* Bail if CRC32 doesn't match. */ 4637a7bc39SJason Zhu if (dest->crc32 != 4737a7bc39SJason Zhu avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) { 4837a7bc39SJason Zhu avb_error("CRC32 does not match.\n"); 4937a7bc39SJason Zhu return false; 5037a7bc39SJason Zhu } 5137a7bc39SJason Zhu 5237a7bc39SJason Zhu return true; 5337a7bc39SJason Zhu } 5437a7bc39SJason Zhu 5537a7bc39SJason Zhu void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, 5637a7bc39SJason Zhu AvbABData* dest) { 5737a7bc39SJason Zhu avb_memcpy(dest, src, sizeof(AvbABData)); 5837a7bc39SJason Zhu dest->crc32 = avb_htobe32( 5937a7bc39SJason Zhu avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))); 6037a7bc39SJason Zhu } 6137a7bc39SJason Zhu 6237a7bc39SJason Zhu void avb_ab_data_init(AvbABData* data) { 6337a7bc39SJason Zhu avb_memset(data, '\0', sizeof(AvbABData)); 6437a7bc39SJason Zhu avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN); 6537a7bc39SJason Zhu data->version_major = AVB_AB_MAJOR_VERSION; 6637a7bc39SJason Zhu data->version_minor = AVB_AB_MINOR_VERSION; 6737a7bc39SJason Zhu data->slots[0].priority = AVB_AB_MAX_PRIORITY; 6837a7bc39SJason Zhu data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 6937a7bc39SJason Zhu data->slots[0].successful_boot = 0; 7037a7bc39SJason Zhu data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1; 7137a7bc39SJason Zhu data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 7237a7bc39SJason Zhu data->slots[1].successful_boot = 0; 7337a7bc39SJason Zhu } 7437a7bc39SJason Zhu 7537a7bc39SJason Zhu /* The AvbABData struct is stored 2048 bytes into the 'misc' partition 7637a7bc39SJason Zhu * following the 'struct bootloader_message' field. The struct is 7737a7bc39SJason Zhu * compatible with the guidelines in bootable/recovery/bootloader.h - 7837a7bc39SJason Zhu * e.g. it is stored in the |slot_suffix| field, starts with a 7937a7bc39SJason Zhu * NUL-byte, and is 32 bytes long. 8037a7bc39SJason Zhu */ 8137a7bc39SJason Zhu #define AB_METADATA_MISC_PARTITION_OFFSET 2048 8237a7bc39SJason Zhu 8337a7bc39SJason Zhu AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) { 8437a7bc39SJason Zhu AvbOps* ops = ab_ops->ops; 8537a7bc39SJason Zhu AvbABData serialized; 8637a7bc39SJason Zhu AvbIOResult io_ret; 8737a7bc39SJason Zhu size_t num_bytes_read; 8837a7bc39SJason Zhu 8937a7bc39SJason Zhu io_ret = ops->read_from_partition(ops, 9037a7bc39SJason Zhu "misc", 9137a7bc39SJason Zhu AB_METADATA_MISC_PARTITION_OFFSET, 9237a7bc39SJason Zhu sizeof(AvbABData), 9337a7bc39SJason Zhu &serialized, 9437a7bc39SJason Zhu &num_bytes_read); 9537a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 9637a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_OOM; 9737a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK || 9837a7bc39SJason Zhu num_bytes_read != sizeof(AvbABData)) { 9937a7bc39SJason Zhu avb_error("Error reading A/B metadata.\n"); 10037a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 10137a7bc39SJason Zhu } 10237a7bc39SJason Zhu 10337a7bc39SJason Zhu if (!avb_ab_data_verify_and_byteswap(&serialized, data)) { 10437a7bc39SJason Zhu avb_error( 10537a7bc39SJason Zhu "Error validating A/B metadata from disk. " 10637a7bc39SJason Zhu "Resetting and writing new A/B metadata to disk.\n"); 10737a7bc39SJason Zhu avb_ab_data_init(data); 10837a7bc39SJason Zhu return avb_ab_data_write(ab_ops, data); 10937a7bc39SJason Zhu } 11037a7bc39SJason Zhu 11137a7bc39SJason Zhu return AVB_IO_RESULT_OK; 11237a7bc39SJason Zhu } 11337a7bc39SJason Zhu 11437a7bc39SJason Zhu AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) { 11537a7bc39SJason Zhu AvbOps* ops = ab_ops->ops; 11637a7bc39SJason Zhu AvbABData serialized; 11737a7bc39SJason Zhu AvbIOResult io_ret; 11837a7bc39SJason Zhu 11937a7bc39SJason Zhu avb_ab_data_update_crc_and_byteswap(data, &serialized); 12037a7bc39SJason Zhu io_ret = ops->write_to_partition(ops, 12137a7bc39SJason Zhu "misc", 12237a7bc39SJason Zhu AB_METADATA_MISC_PARTITION_OFFSET, 12337a7bc39SJason Zhu sizeof(AvbABData), 12437a7bc39SJason Zhu &serialized); 12537a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 12637a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_OOM; 12737a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 12837a7bc39SJason Zhu avb_error("Error writing A/B metadata.\n"); 12937a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 13037a7bc39SJason Zhu } 13137a7bc39SJason Zhu return AVB_IO_RESULT_OK; 13237a7bc39SJason Zhu } 13337a7bc39SJason Zhu 13437a7bc39SJason Zhu static bool slot_is_bootable(AvbABSlotData* slot) { 13537a7bc39SJason Zhu return slot->priority > 0 && 13637a7bc39SJason Zhu (slot->successful_boot || (slot->tries_remaining > 0)); 13737a7bc39SJason Zhu } 13837a7bc39SJason Zhu 13937a7bc39SJason Zhu static void slot_set_unbootable(AvbABSlotData* slot) { 14037a7bc39SJason Zhu slot->priority = 0; 14137a7bc39SJason Zhu slot->tries_remaining = 0; 14237a7bc39SJason Zhu slot->successful_boot = 0; 14337a7bc39SJason Zhu } 14437a7bc39SJason Zhu 14537a7bc39SJason Zhu /* Ensure all unbootable and/or illegal states are marked as the 14637a7bc39SJason Zhu * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0, 14737a7bc39SJason Zhu * and successful_boot=0. 14837a7bc39SJason Zhu */ 14937a7bc39SJason Zhu static void slot_normalize(AvbABSlotData* slot) { 15037a7bc39SJason Zhu if (slot->priority > 0) { 15137a7bc39SJason Zhu if (slot->tries_remaining == 0 && !slot->successful_boot) { 15237a7bc39SJason Zhu /* We've exhausted all tries -> unbootable. */ 15337a7bc39SJason Zhu slot_set_unbootable(slot); 15437a7bc39SJason Zhu } 15537a7bc39SJason Zhu if (slot->tries_remaining > 0 && slot->successful_boot) { 15637a7bc39SJason Zhu /* Illegal state - avb_ab_mark_slot_successful() will clear 15737a7bc39SJason Zhu * tries_remaining when setting successful_boot. 15837a7bc39SJason Zhu */ 15937a7bc39SJason Zhu slot_set_unbootable(slot); 16037a7bc39SJason Zhu } 16137a7bc39SJason Zhu } else { 16237a7bc39SJason Zhu slot_set_unbootable(slot); 16337a7bc39SJason Zhu } 16437a7bc39SJason Zhu } 16537a7bc39SJason Zhu 16637a7bc39SJason Zhu static const char* slot_suffixes[2] = {"_a", "_b"}; 16737a7bc39SJason Zhu 16837a7bc39SJason Zhu /* Helper function to load metadata - returns AVB_IO_RESULT_OK on 16937a7bc39SJason Zhu * success, error code otherwise. 17037a7bc39SJason Zhu */ 171*187a5bc5SJason Zhu AvbIOResult load_metadata(AvbABOps* ab_ops, 17237a7bc39SJason Zhu AvbABData* ab_data, 17337a7bc39SJason Zhu AvbABData* ab_data_orig) { 17437a7bc39SJason Zhu AvbIOResult io_ret; 17537a7bc39SJason Zhu 17637a7bc39SJason Zhu io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data); 17737a7bc39SJason Zhu if (io_ret != AVB_IO_RESULT_OK) { 17837a7bc39SJason Zhu avb_error("I/O error while loading A/B metadata.\n"); 17937a7bc39SJason Zhu return io_ret; 18037a7bc39SJason Zhu } 18137a7bc39SJason Zhu *ab_data_orig = *ab_data; 18237a7bc39SJason Zhu 18337a7bc39SJason Zhu /* Ensure data is normalized, e.g. illegal states will be marked as 18437a7bc39SJason Zhu * unbootable and all unbootable states are represented with 18537a7bc39SJason Zhu * (priority=0, tries_remaining=0, successful_boot=0). 18637a7bc39SJason Zhu */ 18737a7bc39SJason Zhu slot_normalize(&ab_data->slots[0]); 18837a7bc39SJason Zhu slot_normalize(&ab_data->slots[1]); 18937a7bc39SJason Zhu return AVB_IO_RESULT_OK; 19037a7bc39SJason Zhu } 19137a7bc39SJason Zhu 19237a7bc39SJason Zhu /* Writes A/B metadata to disk only if it has changed - returns 19337a7bc39SJason Zhu * AVB_IO_RESULT_OK on success, error code otherwise. 19437a7bc39SJason Zhu */ 195*187a5bc5SJason Zhu AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops, 19637a7bc39SJason Zhu AvbABData* ab_data, 19737a7bc39SJason Zhu AvbABData* ab_data_orig) { 19837a7bc39SJason Zhu if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) { 19937a7bc39SJason Zhu avb_debug("Writing A/B metadata to disk.\n"); 20037a7bc39SJason Zhu return ab_ops->write_ab_metadata(ab_ops, ab_data); 20137a7bc39SJason Zhu } 20237a7bc39SJason Zhu return AVB_IO_RESULT_OK; 20337a7bc39SJason Zhu } 20437a7bc39SJason Zhu 20537a7bc39SJason Zhu AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, 20637a7bc39SJason Zhu const char* const* requested_partitions, 20737a7bc39SJason Zhu AvbSlotVerifyFlags flags, 20837a7bc39SJason Zhu AvbHashtreeErrorMode hashtree_error_mode, 20937a7bc39SJason Zhu AvbSlotVerifyData** out_data) { 21037a7bc39SJason Zhu AvbOps* ops = ab_ops->ops; 21137a7bc39SJason Zhu AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; 21237a7bc39SJason Zhu AvbSlotVerifyData* data = NULL; 21337a7bc39SJason Zhu AvbABFlowResult ret; 21437a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 21537a7bc39SJason Zhu size_t slot_index_to_boot, n; 21637a7bc39SJason Zhu AvbIOResult io_ret; 21737a7bc39SJason Zhu bool saw_and_allowed_verification_error = false; 21837a7bc39SJason Zhu 21937a7bc39SJason Zhu io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 22037a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 22137a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 22237a7bc39SJason Zhu goto out; 22337a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 22437a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 22537a7bc39SJason Zhu goto out; 22637a7bc39SJason Zhu } 22737a7bc39SJason Zhu 22837a7bc39SJason Zhu /* Validate all bootable slots. */ 22937a7bc39SJason Zhu for (n = 0; n < 2; n++) { 23037a7bc39SJason Zhu if (slot_is_bootable(&ab_data.slots[n])) { 23137a7bc39SJason Zhu AvbSlotVerifyResult verify_result; 23237a7bc39SJason Zhu bool set_slot_unbootable = false; 23337a7bc39SJason Zhu 23437a7bc39SJason Zhu verify_result = avb_slot_verify(ops, 23537a7bc39SJason Zhu requested_partitions, 23637a7bc39SJason Zhu slot_suffixes[n], 23737a7bc39SJason Zhu flags, 23837a7bc39SJason Zhu hashtree_error_mode, 23937a7bc39SJason Zhu &slot_data[n]); 24037a7bc39SJason Zhu switch (verify_result) { 24137a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: 24237a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 24337a7bc39SJason Zhu goto out; 24437a7bc39SJason Zhu 24537a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_IO: 24637a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 24737a7bc39SJason Zhu goto out; 24837a7bc39SJason Zhu 24937a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_OK: 25037a7bc39SJason Zhu break; 25137a7bc39SJason Zhu 25237a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: 25337a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: 25437a7bc39SJason Zhu /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR 25537a7bc39SJason Zhu * these mean game over. 25637a7bc39SJason Zhu */ 25737a7bc39SJason Zhu set_slot_unbootable = true; 25837a7bc39SJason Zhu break; 25937a7bc39SJason Zhu 26037a7bc39SJason Zhu /* explicit fallthrough. */ 26137a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: 26237a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: 26337a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: 26437a7bc39SJason Zhu if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { 26537a7bc39SJason Zhu /* Do nothing since we allow this. */ 26637a7bc39SJason Zhu avb_debugv("Allowing slot ", 26737a7bc39SJason Zhu slot_suffixes[n], 26837a7bc39SJason Zhu " which verified " 26937a7bc39SJason Zhu "with result ", 27037a7bc39SJason Zhu avb_slot_verify_result_to_string(verify_result), 27137a7bc39SJason Zhu " because " 27237a7bc39SJason Zhu "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " 27337a7bc39SJason Zhu "is set.\n", 27437a7bc39SJason Zhu NULL); 27537a7bc39SJason Zhu saw_and_allowed_verification_error = true; 27637a7bc39SJason Zhu } else { 27737a7bc39SJason Zhu set_slot_unbootable = true; 27837a7bc39SJason Zhu } 27937a7bc39SJason Zhu break; 28037a7bc39SJason Zhu 28137a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: 28237a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; 28337a7bc39SJason Zhu goto out; 28437a7bc39SJason Zhu /* Do not add a 'default:' case here because of -Wswitch. */ 28537a7bc39SJason Zhu } 28637a7bc39SJason Zhu 28737a7bc39SJason Zhu if (set_slot_unbootable) { 28837a7bc39SJason Zhu avb_errorv("Error verifying slot ", 28937a7bc39SJason Zhu slot_suffixes[n], 29037a7bc39SJason Zhu " with result ", 29137a7bc39SJason Zhu avb_slot_verify_result_to_string(verify_result), 29237a7bc39SJason Zhu " - setting unbootable.\n", 29337a7bc39SJason Zhu NULL); 29437a7bc39SJason Zhu slot_set_unbootable(&ab_data.slots[n]); 29537a7bc39SJason Zhu } 29637a7bc39SJason Zhu } 29737a7bc39SJason Zhu } 29837a7bc39SJason Zhu 29937a7bc39SJason Zhu if (slot_is_bootable(&ab_data.slots[0]) && 30037a7bc39SJason Zhu slot_is_bootable(&ab_data.slots[1])) { 30137a7bc39SJason Zhu if (ab_data.slots[1].priority > ab_data.slots[0].priority) { 30237a7bc39SJason Zhu slot_index_to_boot = 1; 30337a7bc39SJason Zhu } else { 30437a7bc39SJason Zhu slot_index_to_boot = 0; 30537a7bc39SJason Zhu } 30637a7bc39SJason Zhu } else if (slot_is_bootable(&ab_data.slots[0])) { 30737a7bc39SJason Zhu slot_index_to_boot = 0; 30837a7bc39SJason Zhu } else if (slot_is_bootable(&ab_data.slots[1])) { 30937a7bc39SJason Zhu slot_index_to_boot = 1; 31037a7bc39SJason Zhu } else { 31137a7bc39SJason Zhu /* No bootable slots! */ 31237a7bc39SJason Zhu avb_error("No bootable slots found.\n"); 31337a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; 31437a7bc39SJason Zhu goto out; 31537a7bc39SJason Zhu } 31637a7bc39SJason Zhu 31737a7bc39SJason Zhu /* Update stored rollback index such that the stored rollback index 31837a7bc39SJason Zhu * is the largest value supporting all currently bootable slots. Do 31937a7bc39SJason Zhu * this for every rollback index location. 32037a7bc39SJason Zhu */ 32137a7bc39SJason Zhu for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) { 32237a7bc39SJason Zhu uint64_t rollback_index_value = 0; 32337a7bc39SJason Zhu 32437a7bc39SJason Zhu if (slot_data[0] != NULL && slot_data[1] != NULL) { 32537a7bc39SJason Zhu uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n]; 32637a7bc39SJason Zhu uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n]; 32737a7bc39SJason Zhu rollback_index_value = 32837a7bc39SJason Zhu (a_rollback_index < b_rollback_index ? a_rollback_index 32937a7bc39SJason Zhu : b_rollback_index); 33037a7bc39SJason Zhu } else if (slot_data[0] != NULL) { 33137a7bc39SJason Zhu rollback_index_value = slot_data[0]->rollback_indexes[n]; 33237a7bc39SJason Zhu } else if (slot_data[1] != NULL) { 33337a7bc39SJason Zhu rollback_index_value = slot_data[1]->rollback_indexes[n]; 33437a7bc39SJason Zhu } 33537a7bc39SJason Zhu 33637a7bc39SJason Zhu if (rollback_index_value != 0) { 33737a7bc39SJason Zhu uint64_t current_rollback_index_value; 33837a7bc39SJason Zhu io_ret = ops->read_rollback_index(ops, n, ¤t_rollback_index_value); 33937a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 34037a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 34137a7bc39SJason Zhu goto out; 34237a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 34337a7bc39SJason Zhu avb_error("Error getting rollback index for slot.\n"); 34437a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 34537a7bc39SJason Zhu goto out; 34637a7bc39SJason Zhu } 34737a7bc39SJason Zhu if (current_rollback_index_value != rollback_index_value) { 34837a7bc39SJason Zhu io_ret = ops->write_rollback_index(ops, n, rollback_index_value); 34937a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 35037a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 35137a7bc39SJason Zhu goto out; 35237a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 35337a7bc39SJason Zhu avb_error("Error setting stored rollback index.\n"); 35437a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 35537a7bc39SJason Zhu goto out; 35637a7bc39SJason Zhu } 35737a7bc39SJason Zhu } 35837a7bc39SJason Zhu } 35937a7bc39SJason Zhu } 36037a7bc39SJason Zhu 36137a7bc39SJason Zhu /* Finally, select this slot. */ 36237a7bc39SJason Zhu avb_assert(slot_data[slot_index_to_boot] != NULL); 36337a7bc39SJason Zhu data = slot_data[slot_index_to_boot]; 36437a7bc39SJason Zhu slot_data[slot_index_to_boot] = NULL; 36537a7bc39SJason Zhu if (saw_and_allowed_verification_error) { 36637a7bc39SJason Zhu avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); 36737a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; 36837a7bc39SJason Zhu } else { 36937a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_OK; 37037a7bc39SJason Zhu } 37137a7bc39SJason Zhu 37237a7bc39SJason Zhu /* ... and decrement tries remaining, if applicable. */ 37337a7bc39SJason Zhu if (!ab_data.slots[slot_index_to_boot].successful_boot && 37437a7bc39SJason Zhu ab_data.slots[slot_index_to_boot].tries_remaining > 0) { 37537a7bc39SJason Zhu ab_data.slots[slot_index_to_boot].tries_remaining -= 1; 37637a7bc39SJason Zhu } 37737a7bc39SJason Zhu 37837a7bc39SJason Zhu out: 37937a7bc39SJason Zhu io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 38037a7bc39SJason Zhu if (io_ret != AVB_IO_RESULT_OK) { 38137a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 38237a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 38337a7bc39SJason Zhu } else { 38437a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 38537a7bc39SJason Zhu } 38637a7bc39SJason Zhu if (data != NULL) { 38737a7bc39SJason Zhu avb_slot_verify_data_free(data); 38837a7bc39SJason Zhu data = NULL; 38937a7bc39SJason Zhu } 39037a7bc39SJason Zhu } 39137a7bc39SJason Zhu 39237a7bc39SJason Zhu for (n = 0; n < 2; n++) { 39337a7bc39SJason Zhu if (slot_data[n] != NULL) { 39437a7bc39SJason Zhu avb_slot_verify_data_free(slot_data[n]); 39537a7bc39SJason Zhu } 39637a7bc39SJason Zhu } 39737a7bc39SJason Zhu 39837a7bc39SJason Zhu if (out_data != NULL) { 39937a7bc39SJason Zhu *out_data = data; 40037a7bc39SJason Zhu } else { 40137a7bc39SJason Zhu if (data != NULL) { 40237a7bc39SJason Zhu avb_slot_verify_data_free(data); 40337a7bc39SJason Zhu } 40437a7bc39SJason Zhu } 40537a7bc39SJason Zhu 40637a7bc39SJason Zhu return ret; 40737a7bc39SJason Zhu } 40837a7bc39SJason Zhu 40937a7bc39SJason Zhu AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, 41037a7bc39SJason Zhu unsigned int slot_number) { 41137a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 41237a7bc39SJason Zhu unsigned int other_slot_number; 41337a7bc39SJason Zhu AvbIOResult ret; 41437a7bc39SJason Zhu 41537a7bc39SJason Zhu avb_assert(slot_number < 2); 41637a7bc39SJason Zhu 41737a7bc39SJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 41837a7bc39SJason Zhu if (ret != AVB_IO_RESULT_OK) { 41937a7bc39SJason Zhu goto out; 42037a7bc39SJason Zhu } 42137a7bc39SJason Zhu 42237a7bc39SJason Zhu /* Make requested slot top priority, unsuccessful, and with max tries. */ 42337a7bc39SJason Zhu ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY; 42437a7bc39SJason Zhu ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 42537a7bc39SJason Zhu ab_data.slots[slot_number].successful_boot = 0; 42637a7bc39SJason Zhu 42737a7bc39SJason Zhu /* Ensure other slot doesn't have as high a priority. */ 42837a7bc39SJason Zhu other_slot_number = 1 - slot_number; 42937a7bc39SJason Zhu if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) { 43037a7bc39SJason Zhu ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1; 43137a7bc39SJason Zhu } 43237a7bc39SJason Zhu 43337a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 43437a7bc39SJason Zhu 43537a7bc39SJason Zhu out: 43637a7bc39SJason Zhu if (ret == AVB_IO_RESULT_OK) { 43737a7bc39SJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 43837a7bc39SJason Zhu } 43937a7bc39SJason Zhu return ret; 44037a7bc39SJason Zhu } 44137a7bc39SJason Zhu 44237a7bc39SJason Zhu AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops, 44337a7bc39SJason Zhu unsigned int slot_number) { 44437a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 44537a7bc39SJason Zhu AvbIOResult ret; 44637a7bc39SJason Zhu 44737a7bc39SJason Zhu avb_assert(slot_number < 2); 44837a7bc39SJason Zhu 44937a7bc39SJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 45037a7bc39SJason Zhu if (ret != AVB_IO_RESULT_OK) { 45137a7bc39SJason Zhu goto out; 45237a7bc39SJason Zhu } 45337a7bc39SJason Zhu 45437a7bc39SJason Zhu slot_set_unbootable(&ab_data.slots[slot_number]); 45537a7bc39SJason Zhu 45637a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 45737a7bc39SJason Zhu 45837a7bc39SJason Zhu out: 45937a7bc39SJason Zhu if (ret == AVB_IO_RESULT_OK) { 46037a7bc39SJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 46137a7bc39SJason Zhu } 46237a7bc39SJason Zhu return ret; 46337a7bc39SJason Zhu } 46437a7bc39SJason Zhu 46537a7bc39SJason Zhu AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops, 46637a7bc39SJason Zhu unsigned int slot_number) { 46737a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 46837a7bc39SJason Zhu AvbIOResult ret; 46937a7bc39SJason Zhu 47037a7bc39SJason Zhu avb_assert(slot_number < 2); 47137a7bc39SJason Zhu 47237a7bc39SJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 47337a7bc39SJason Zhu if (ret != AVB_IO_RESULT_OK) { 47437a7bc39SJason Zhu goto out; 47537a7bc39SJason Zhu } 47637a7bc39SJason Zhu 47737a7bc39SJason Zhu if (!slot_is_bootable(&ab_data.slots[slot_number])) { 47837a7bc39SJason Zhu avb_error("Cannot mark unbootable slot as successful.\n"); 47937a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 48037a7bc39SJason Zhu goto out; 48137a7bc39SJason Zhu } 48237a7bc39SJason Zhu 48337a7bc39SJason Zhu ab_data.slots[slot_number].tries_remaining = 0; 48437a7bc39SJason Zhu ab_data.slots[slot_number].successful_boot = 1; 48537a7bc39SJason Zhu 48637a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 48737a7bc39SJason Zhu 48837a7bc39SJason Zhu out: 48937a7bc39SJason Zhu if (ret == AVB_IO_RESULT_OK) { 49037a7bc39SJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 49137a7bc39SJason Zhu } 49237a7bc39SJason Zhu return ret; 49337a7bc39SJason Zhu } 49437a7bc39SJason Zhu 49537a7bc39SJason Zhu const char* avb_ab_flow_result_to_string(AvbABFlowResult result) { 49637a7bc39SJason Zhu const char* ret = NULL; 49737a7bc39SJason Zhu 49837a7bc39SJason Zhu switch (result) { 49937a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_OK: 50037a7bc39SJason Zhu ret = "OK"; 50137a7bc39SJason Zhu break; 50237a7bc39SJason Zhu 50337a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR: 50437a7bc39SJason Zhu ret = "OK_WITH_VERIFICATION_ERROR"; 50537a7bc39SJason Zhu break; 50637a7bc39SJason Zhu 50737a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_OOM: 50837a7bc39SJason Zhu ret = "ERROR_OOM"; 50937a7bc39SJason Zhu break; 51037a7bc39SJason Zhu 51137a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_IO: 51237a7bc39SJason Zhu ret = "ERROR_IO"; 51337a7bc39SJason Zhu break; 51437a7bc39SJason Zhu 51537a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS: 51637a7bc39SJason Zhu ret = "ERROR_NO_BOOTABLE_SLOTS"; 51737a7bc39SJason Zhu break; 51837a7bc39SJason Zhu 51937a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT: 52037a7bc39SJason Zhu ret = "ERROR_INVALID_ARGUMENT"; 52137a7bc39SJason Zhu break; 52237a7bc39SJason Zhu /* Do not add a 'default:' case here because of -Wswitch. */ 52337a7bc39SJason Zhu } 52437a7bc39SJason Zhu 52537a7bc39SJason Zhu if (ret == NULL) { 52637a7bc39SJason Zhu avb_error("Unknown AvbABFlowResult value.\n"); 52737a7bc39SJason Zhu ret = "(unknown)"; 52837a7bc39SJason Zhu } 52937a7bc39SJason Zhu 53037a7bc39SJason Zhu return ret; 53137a7bc39SJason Zhu } 532