1*37a7bc39SJason Zhu /* 2*37a7bc39SJason Zhu * Copyright (C) 2016 The Android Open Source Project 3*37a7bc39SJason Zhu * 4*37a7bc39SJason Zhu * Permission is hereby granted, free of charge, to any person 5*37a7bc39SJason Zhu * obtaining a copy of this software and associated documentation 6*37a7bc39SJason Zhu * files (the "Software"), to deal in the Software without 7*37a7bc39SJason Zhu * restriction, including without limitation the rights to use, copy, 8*37a7bc39SJason Zhu * modify, merge, publish, distribute, sublicense, and/or sell copies 9*37a7bc39SJason Zhu * of the Software, and to permit persons to whom the Software is 10*37a7bc39SJason Zhu * furnished to do so, subject to the following conditions: 11*37a7bc39SJason Zhu * 12*37a7bc39SJason Zhu * The above copyright notice and this permission notice shall be 13*37a7bc39SJason Zhu * included in all copies or substantial portions of the Software. 14*37a7bc39SJason Zhu * 15*37a7bc39SJason Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16*37a7bc39SJason Zhu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17*37a7bc39SJason Zhu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18*37a7bc39SJason Zhu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19*37a7bc39SJason Zhu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20*37a7bc39SJason Zhu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21*37a7bc39SJason Zhu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22*37a7bc39SJason Zhu * SOFTWARE. 23*37a7bc39SJason Zhu */ 24*37a7bc39SJason Zhu 25*37a7bc39SJason Zhu #include <android_avb/avb_ab_flow.h> 26*37a7bc39SJason Zhu 27*37a7bc39SJason Zhu bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) { 28*37a7bc39SJason Zhu /* Ensure magic is correct. */ 29*37a7bc39SJason Zhu if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) { 30*37a7bc39SJason Zhu avb_error("Magic is incorrect.\n"); 31*37a7bc39SJason Zhu return false; 32*37a7bc39SJason Zhu } 33*37a7bc39SJason Zhu 34*37a7bc39SJason Zhu avb_memcpy(dest, src, sizeof(AvbABData)); 35*37a7bc39SJason Zhu dest->crc32 = avb_be32toh(dest->crc32); 36*37a7bc39SJason Zhu 37*37a7bc39SJason Zhu /* Ensure we don't attempt to access any fields if the major version 38*37a7bc39SJason Zhu * is not supported. 39*37a7bc39SJason Zhu */ 40*37a7bc39SJason Zhu if (dest->version_major > AVB_AB_MAJOR_VERSION) { 41*37a7bc39SJason Zhu avb_error("No support for given major version.\n"); 42*37a7bc39SJason Zhu return false; 43*37a7bc39SJason Zhu } 44*37a7bc39SJason Zhu 45*37a7bc39SJason Zhu /* Bail if CRC32 doesn't match. */ 46*37a7bc39SJason Zhu if (dest->crc32 != 47*37a7bc39SJason Zhu avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) { 48*37a7bc39SJason Zhu avb_error("CRC32 does not match.\n"); 49*37a7bc39SJason Zhu return false; 50*37a7bc39SJason Zhu } 51*37a7bc39SJason Zhu 52*37a7bc39SJason Zhu return true; 53*37a7bc39SJason Zhu } 54*37a7bc39SJason Zhu 55*37a7bc39SJason Zhu void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, 56*37a7bc39SJason Zhu AvbABData* dest) { 57*37a7bc39SJason Zhu avb_memcpy(dest, src, sizeof(AvbABData)); 58*37a7bc39SJason Zhu dest->crc32 = avb_htobe32( 59*37a7bc39SJason Zhu avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))); 60*37a7bc39SJason Zhu } 61*37a7bc39SJason Zhu 62*37a7bc39SJason Zhu void avb_ab_data_init(AvbABData* data) { 63*37a7bc39SJason Zhu avb_memset(data, '\0', sizeof(AvbABData)); 64*37a7bc39SJason Zhu avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN); 65*37a7bc39SJason Zhu data->version_major = AVB_AB_MAJOR_VERSION; 66*37a7bc39SJason Zhu data->version_minor = AVB_AB_MINOR_VERSION; 67*37a7bc39SJason Zhu data->slots[0].priority = AVB_AB_MAX_PRIORITY; 68*37a7bc39SJason Zhu data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 69*37a7bc39SJason Zhu data->slots[0].successful_boot = 0; 70*37a7bc39SJason Zhu data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1; 71*37a7bc39SJason Zhu data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 72*37a7bc39SJason Zhu data->slots[1].successful_boot = 0; 73*37a7bc39SJason Zhu } 74*37a7bc39SJason Zhu 75*37a7bc39SJason Zhu /* The AvbABData struct is stored 2048 bytes into the 'misc' partition 76*37a7bc39SJason Zhu * following the 'struct bootloader_message' field. The struct is 77*37a7bc39SJason Zhu * compatible with the guidelines in bootable/recovery/bootloader.h - 78*37a7bc39SJason Zhu * e.g. it is stored in the |slot_suffix| field, starts with a 79*37a7bc39SJason Zhu * NUL-byte, and is 32 bytes long. 80*37a7bc39SJason Zhu */ 81*37a7bc39SJason Zhu #define AB_METADATA_MISC_PARTITION_OFFSET 2048 82*37a7bc39SJason Zhu 83*37a7bc39SJason Zhu AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) { 84*37a7bc39SJason Zhu AvbOps* ops = ab_ops->ops; 85*37a7bc39SJason Zhu AvbABData serialized; 86*37a7bc39SJason Zhu AvbIOResult io_ret; 87*37a7bc39SJason Zhu size_t num_bytes_read; 88*37a7bc39SJason Zhu 89*37a7bc39SJason Zhu io_ret = ops->read_from_partition(ops, 90*37a7bc39SJason Zhu "misc", 91*37a7bc39SJason Zhu AB_METADATA_MISC_PARTITION_OFFSET, 92*37a7bc39SJason Zhu sizeof(AvbABData), 93*37a7bc39SJason Zhu &serialized, 94*37a7bc39SJason Zhu &num_bytes_read); 95*37a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 96*37a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_OOM; 97*37a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK || 98*37a7bc39SJason Zhu num_bytes_read != sizeof(AvbABData)) { 99*37a7bc39SJason Zhu avb_error("Error reading A/B metadata.\n"); 100*37a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 101*37a7bc39SJason Zhu } 102*37a7bc39SJason Zhu 103*37a7bc39SJason Zhu if (!avb_ab_data_verify_and_byteswap(&serialized, data)) { 104*37a7bc39SJason Zhu avb_error( 105*37a7bc39SJason Zhu "Error validating A/B metadata from disk. " 106*37a7bc39SJason Zhu "Resetting and writing new A/B metadata to disk.\n"); 107*37a7bc39SJason Zhu avb_ab_data_init(data); 108*37a7bc39SJason Zhu return avb_ab_data_write(ab_ops, data); 109*37a7bc39SJason Zhu } 110*37a7bc39SJason Zhu 111*37a7bc39SJason Zhu return AVB_IO_RESULT_OK; 112*37a7bc39SJason Zhu } 113*37a7bc39SJason Zhu 114*37a7bc39SJason Zhu AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) { 115*37a7bc39SJason Zhu AvbOps* ops = ab_ops->ops; 116*37a7bc39SJason Zhu AvbABData serialized; 117*37a7bc39SJason Zhu AvbIOResult io_ret; 118*37a7bc39SJason Zhu 119*37a7bc39SJason Zhu avb_ab_data_update_crc_and_byteswap(data, &serialized); 120*37a7bc39SJason Zhu io_ret = ops->write_to_partition(ops, 121*37a7bc39SJason Zhu "misc", 122*37a7bc39SJason Zhu AB_METADATA_MISC_PARTITION_OFFSET, 123*37a7bc39SJason Zhu sizeof(AvbABData), 124*37a7bc39SJason Zhu &serialized); 125*37a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 126*37a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_OOM; 127*37a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 128*37a7bc39SJason Zhu avb_error("Error writing A/B metadata.\n"); 129*37a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 130*37a7bc39SJason Zhu } 131*37a7bc39SJason Zhu return AVB_IO_RESULT_OK; 132*37a7bc39SJason Zhu } 133*37a7bc39SJason Zhu 134*37a7bc39SJason Zhu static bool slot_is_bootable(AvbABSlotData* slot) { 135*37a7bc39SJason Zhu return slot->priority > 0 && 136*37a7bc39SJason Zhu (slot->successful_boot || (slot->tries_remaining > 0)); 137*37a7bc39SJason Zhu } 138*37a7bc39SJason Zhu 139*37a7bc39SJason Zhu static void slot_set_unbootable(AvbABSlotData* slot) { 140*37a7bc39SJason Zhu slot->priority = 0; 141*37a7bc39SJason Zhu slot->tries_remaining = 0; 142*37a7bc39SJason Zhu slot->successful_boot = 0; 143*37a7bc39SJason Zhu } 144*37a7bc39SJason Zhu 145*37a7bc39SJason Zhu /* Ensure all unbootable and/or illegal states are marked as the 146*37a7bc39SJason Zhu * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0, 147*37a7bc39SJason Zhu * and successful_boot=0. 148*37a7bc39SJason Zhu */ 149*37a7bc39SJason Zhu static void slot_normalize(AvbABSlotData* slot) { 150*37a7bc39SJason Zhu if (slot->priority > 0) { 151*37a7bc39SJason Zhu if (slot->tries_remaining == 0 && !slot->successful_boot) { 152*37a7bc39SJason Zhu /* We've exhausted all tries -> unbootable. */ 153*37a7bc39SJason Zhu slot_set_unbootable(slot); 154*37a7bc39SJason Zhu } 155*37a7bc39SJason Zhu if (slot->tries_remaining > 0 && slot->successful_boot) { 156*37a7bc39SJason Zhu /* Illegal state - avb_ab_mark_slot_successful() will clear 157*37a7bc39SJason Zhu * tries_remaining when setting successful_boot. 158*37a7bc39SJason Zhu */ 159*37a7bc39SJason Zhu slot_set_unbootable(slot); 160*37a7bc39SJason Zhu } 161*37a7bc39SJason Zhu } else { 162*37a7bc39SJason Zhu slot_set_unbootable(slot); 163*37a7bc39SJason Zhu } 164*37a7bc39SJason Zhu } 165*37a7bc39SJason Zhu 166*37a7bc39SJason Zhu static const char* slot_suffixes[2] = {"_a", "_b"}; 167*37a7bc39SJason Zhu 168*37a7bc39SJason Zhu /* Helper function to load metadata - returns AVB_IO_RESULT_OK on 169*37a7bc39SJason Zhu * success, error code otherwise. 170*37a7bc39SJason Zhu */ 171*37a7bc39SJason Zhu static AvbIOResult load_metadata(AvbABOps* ab_ops, 172*37a7bc39SJason Zhu AvbABData* ab_data, 173*37a7bc39SJason Zhu AvbABData* ab_data_orig) { 174*37a7bc39SJason Zhu AvbIOResult io_ret; 175*37a7bc39SJason Zhu 176*37a7bc39SJason Zhu io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data); 177*37a7bc39SJason Zhu if (io_ret != AVB_IO_RESULT_OK) { 178*37a7bc39SJason Zhu avb_error("I/O error while loading A/B metadata.\n"); 179*37a7bc39SJason Zhu return io_ret; 180*37a7bc39SJason Zhu } 181*37a7bc39SJason Zhu *ab_data_orig = *ab_data; 182*37a7bc39SJason Zhu 183*37a7bc39SJason Zhu /* Ensure data is normalized, e.g. illegal states will be marked as 184*37a7bc39SJason Zhu * unbootable and all unbootable states are represented with 185*37a7bc39SJason Zhu * (priority=0, tries_remaining=0, successful_boot=0). 186*37a7bc39SJason Zhu */ 187*37a7bc39SJason Zhu slot_normalize(&ab_data->slots[0]); 188*37a7bc39SJason Zhu slot_normalize(&ab_data->slots[1]); 189*37a7bc39SJason Zhu return AVB_IO_RESULT_OK; 190*37a7bc39SJason Zhu } 191*37a7bc39SJason Zhu 192*37a7bc39SJason Zhu /* Writes A/B metadata to disk only if it has changed - returns 193*37a7bc39SJason Zhu * AVB_IO_RESULT_OK on success, error code otherwise. 194*37a7bc39SJason Zhu */ 195*37a7bc39SJason Zhu static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops, 196*37a7bc39SJason Zhu AvbABData* ab_data, 197*37a7bc39SJason Zhu AvbABData* ab_data_orig) { 198*37a7bc39SJason Zhu if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) { 199*37a7bc39SJason Zhu avb_debug("Writing A/B metadata to disk.\n"); 200*37a7bc39SJason Zhu return ab_ops->write_ab_metadata(ab_ops, ab_data); 201*37a7bc39SJason Zhu } 202*37a7bc39SJason Zhu return AVB_IO_RESULT_OK; 203*37a7bc39SJason Zhu } 204*37a7bc39SJason Zhu 205*37a7bc39SJason Zhu AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, 206*37a7bc39SJason Zhu const char* const* requested_partitions, 207*37a7bc39SJason Zhu AvbSlotVerifyFlags flags, 208*37a7bc39SJason Zhu AvbHashtreeErrorMode hashtree_error_mode, 209*37a7bc39SJason Zhu AvbSlotVerifyData** out_data) { 210*37a7bc39SJason Zhu AvbOps* ops = ab_ops->ops; 211*37a7bc39SJason Zhu AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; 212*37a7bc39SJason Zhu AvbSlotVerifyData* data = NULL; 213*37a7bc39SJason Zhu AvbABFlowResult ret; 214*37a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 215*37a7bc39SJason Zhu size_t slot_index_to_boot, n; 216*37a7bc39SJason Zhu AvbIOResult io_ret; 217*37a7bc39SJason Zhu bool saw_and_allowed_verification_error = false; 218*37a7bc39SJason Zhu 219*37a7bc39SJason Zhu io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 220*37a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 221*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 222*37a7bc39SJason Zhu goto out; 223*37a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 224*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 225*37a7bc39SJason Zhu goto out; 226*37a7bc39SJason Zhu } 227*37a7bc39SJason Zhu 228*37a7bc39SJason Zhu /* Validate all bootable slots. */ 229*37a7bc39SJason Zhu for (n = 0; n < 2; n++) { 230*37a7bc39SJason Zhu if (slot_is_bootable(&ab_data.slots[n])) { 231*37a7bc39SJason Zhu AvbSlotVerifyResult verify_result; 232*37a7bc39SJason Zhu bool set_slot_unbootable = false; 233*37a7bc39SJason Zhu 234*37a7bc39SJason Zhu verify_result = avb_slot_verify(ops, 235*37a7bc39SJason Zhu requested_partitions, 236*37a7bc39SJason Zhu slot_suffixes[n], 237*37a7bc39SJason Zhu flags, 238*37a7bc39SJason Zhu hashtree_error_mode, 239*37a7bc39SJason Zhu &slot_data[n]); 240*37a7bc39SJason Zhu switch (verify_result) { 241*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: 242*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 243*37a7bc39SJason Zhu goto out; 244*37a7bc39SJason Zhu 245*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_IO: 246*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 247*37a7bc39SJason Zhu goto out; 248*37a7bc39SJason Zhu 249*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_OK: 250*37a7bc39SJason Zhu break; 251*37a7bc39SJason Zhu 252*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: 253*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: 254*37a7bc39SJason Zhu /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR 255*37a7bc39SJason Zhu * these mean game over. 256*37a7bc39SJason Zhu */ 257*37a7bc39SJason Zhu set_slot_unbootable = true; 258*37a7bc39SJason Zhu break; 259*37a7bc39SJason Zhu 260*37a7bc39SJason Zhu /* explicit fallthrough. */ 261*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: 262*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: 263*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: 264*37a7bc39SJason Zhu if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { 265*37a7bc39SJason Zhu /* Do nothing since we allow this. */ 266*37a7bc39SJason Zhu avb_debugv("Allowing slot ", 267*37a7bc39SJason Zhu slot_suffixes[n], 268*37a7bc39SJason Zhu " which verified " 269*37a7bc39SJason Zhu "with result ", 270*37a7bc39SJason Zhu avb_slot_verify_result_to_string(verify_result), 271*37a7bc39SJason Zhu " because " 272*37a7bc39SJason Zhu "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " 273*37a7bc39SJason Zhu "is set.\n", 274*37a7bc39SJason Zhu NULL); 275*37a7bc39SJason Zhu saw_and_allowed_verification_error = true; 276*37a7bc39SJason Zhu } else { 277*37a7bc39SJason Zhu set_slot_unbootable = true; 278*37a7bc39SJason Zhu } 279*37a7bc39SJason Zhu break; 280*37a7bc39SJason Zhu 281*37a7bc39SJason Zhu case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: 282*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; 283*37a7bc39SJason Zhu goto out; 284*37a7bc39SJason Zhu /* Do not add a 'default:' case here because of -Wswitch. */ 285*37a7bc39SJason Zhu } 286*37a7bc39SJason Zhu 287*37a7bc39SJason Zhu if (set_slot_unbootable) { 288*37a7bc39SJason Zhu avb_errorv("Error verifying slot ", 289*37a7bc39SJason Zhu slot_suffixes[n], 290*37a7bc39SJason Zhu " with result ", 291*37a7bc39SJason Zhu avb_slot_verify_result_to_string(verify_result), 292*37a7bc39SJason Zhu " - setting unbootable.\n", 293*37a7bc39SJason Zhu NULL); 294*37a7bc39SJason Zhu slot_set_unbootable(&ab_data.slots[n]); 295*37a7bc39SJason Zhu } 296*37a7bc39SJason Zhu } 297*37a7bc39SJason Zhu } 298*37a7bc39SJason Zhu 299*37a7bc39SJason Zhu if (slot_is_bootable(&ab_data.slots[0]) && 300*37a7bc39SJason Zhu slot_is_bootable(&ab_data.slots[1])) { 301*37a7bc39SJason Zhu if (ab_data.slots[1].priority > ab_data.slots[0].priority) { 302*37a7bc39SJason Zhu slot_index_to_boot = 1; 303*37a7bc39SJason Zhu } else { 304*37a7bc39SJason Zhu slot_index_to_boot = 0; 305*37a7bc39SJason Zhu } 306*37a7bc39SJason Zhu } else if (slot_is_bootable(&ab_data.slots[0])) { 307*37a7bc39SJason Zhu slot_index_to_boot = 0; 308*37a7bc39SJason Zhu } else if (slot_is_bootable(&ab_data.slots[1])) { 309*37a7bc39SJason Zhu slot_index_to_boot = 1; 310*37a7bc39SJason Zhu } else { 311*37a7bc39SJason Zhu /* No bootable slots! */ 312*37a7bc39SJason Zhu avb_error("No bootable slots found.\n"); 313*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; 314*37a7bc39SJason Zhu goto out; 315*37a7bc39SJason Zhu } 316*37a7bc39SJason Zhu 317*37a7bc39SJason Zhu /* Update stored rollback index such that the stored rollback index 318*37a7bc39SJason Zhu * is the largest value supporting all currently bootable slots. Do 319*37a7bc39SJason Zhu * this for every rollback index location. 320*37a7bc39SJason Zhu */ 321*37a7bc39SJason Zhu for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) { 322*37a7bc39SJason Zhu uint64_t rollback_index_value = 0; 323*37a7bc39SJason Zhu 324*37a7bc39SJason Zhu if (slot_data[0] != NULL && slot_data[1] != NULL) { 325*37a7bc39SJason Zhu uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n]; 326*37a7bc39SJason Zhu uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n]; 327*37a7bc39SJason Zhu rollback_index_value = 328*37a7bc39SJason Zhu (a_rollback_index < b_rollback_index ? a_rollback_index 329*37a7bc39SJason Zhu : b_rollback_index); 330*37a7bc39SJason Zhu } else if (slot_data[0] != NULL) { 331*37a7bc39SJason Zhu rollback_index_value = slot_data[0]->rollback_indexes[n]; 332*37a7bc39SJason Zhu } else if (slot_data[1] != NULL) { 333*37a7bc39SJason Zhu rollback_index_value = slot_data[1]->rollback_indexes[n]; 334*37a7bc39SJason Zhu } 335*37a7bc39SJason Zhu 336*37a7bc39SJason Zhu if (rollback_index_value != 0) { 337*37a7bc39SJason Zhu uint64_t current_rollback_index_value; 338*37a7bc39SJason Zhu io_ret = ops->read_rollback_index(ops, n, ¤t_rollback_index_value); 339*37a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 340*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 341*37a7bc39SJason Zhu goto out; 342*37a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 343*37a7bc39SJason Zhu avb_error("Error getting rollback index for slot.\n"); 344*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 345*37a7bc39SJason Zhu goto out; 346*37a7bc39SJason Zhu } 347*37a7bc39SJason Zhu if (current_rollback_index_value != rollback_index_value) { 348*37a7bc39SJason Zhu io_ret = ops->write_rollback_index(ops, n, rollback_index_value); 349*37a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 350*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 351*37a7bc39SJason Zhu goto out; 352*37a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 353*37a7bc39SJason Zhu avb_error("Error setting stored rollback index.\n"); 354*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 355*37a7bc39SJason Zhu goto out; 356*37a7bc39SJason Zhu } 357*37a7bc39SJason Zhu } 358*37a7bc39SJason Zhu } 359*37a7bc39SJason Zhu } 360*37a7bc39SJason Zhu 361*37a7bc39SJason Zhu /* Finally, select this slot. */ 362*37a7bc39SJason Zhu avb_assert(slot_data[slot_index_to_boot] != NULL); 363*37a7bc39SJason Zhu data = slot_data[slot_index_to_boot]; 364*37a7bc39SJason Zhu slot_data[slot_index_to_boot] = NULL; 365*37a7bc39SJason Zhu if (saw_and_allowed_verification_error) { 366*37a7bc39SJason Zhu avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); 367*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; 368*37a7bc39SJason Zhu } else { 369*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_OK; 370*37a7bc39SJason Zhu } 371*37a7bc39SJason Zhu 372*37a7bc39SJason Zhu /* ... and decrement tries remaining, if applicable. */ 373*37a7bc39SJason Zhu if (!ab_data.slots[slot_index_to_boot].successful_boot && 374*37a7bc39SJason Zhu ab_data.slots[slot_index_to_boot].tries_remaining > 0) { 375*37a7bc39SJason Zhu ab_data.slots[slot_index_to_boot].tries_remaining -= 1; 376*37a7bc39SJason Zhu } 377*37a7bc39SJason Zhu 378*37a7bc39SJason Zhu out: 379*37a7bc39SJason Zhu io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 380*37a7bc39SJason Zhu if (io_ret != AVB_IO_RESULT_OK) { 381*37a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 382*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_OOM; 383*37a7bc39SJason Zhu } else { 384*37a7bc39SJason Zhu ret = AVB_AB_FLOW_RESULT_ERROR_IO; 385*37a7bc39SJason Zhu } 386*37a7bc39SJason Zhu if (data != NULL) { 387*37a7bc39SJason Zhu avb_slot_verify_data_free(data); 388*37a7bc39SJason Zhu data = NULL; 389*37a7bc39SJason Zhu } 390*37a7bc39SJason Zhu } 391*37a7bc39SJason Zhu 392*37a7bc39SJason Zhu for (n = 0; n < 2; n++) { 393*37a7bc39SJason Zhu if (slot_data[n] != NULL) { 394*37a7bc39SJason Zhu avb_slot_verify_data_free(slot_data[n]); 395*37a7bc39SJason Zhu } 396*37a7bc39SJason Zhu } 397*37a7bc39SJason Zhu 398*37a7bc39SJason Zhu if (out_data != NULL) { 399*37a7bc39SJason Zhu *out_data = data; 400*37a7bc39SJason Zhu } else { 401*37a7bc39SJason Zhu if (data != NULL) { 402*37a7bc39SJason Zhu avb_slot_verify_data_free(data); 403*37a7bc39SJason Zhu } 404*37a7bc39SJason Zhu } 405*37a7bc39SJason Zhu 406*37a7bc39SJason Zhu return ret; 407*37a7bc39SJason Zhu } 408*37a7bc39SJason Zhu 409*37a7bc39SJason Zhu AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, 410*37a7bc39SJason Zhu unsigned int slot_number) { 411*37a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 412*37a7bc39SJason Zhu unsigned int other_slot_number; 413*37a7bc39SJason Zhu AvbIOResult ret; 414*37a7bc39SJason Zhu 415*37a7bc39SJason Zhu avb_assert(slot_number < 2); 416*37a7bc39SJason Zhu 417*37a7bc39SJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 418*37a7bc39SJason Zhu if (ret != AVB_IO_RESULT_OK) { 419*37a7bc39SJason Zhu goto out; 420*37a7bc39SJason Zhu } 421*37a7bc39SJason Zhu 422*37a7bc39SJason Zhu /* Make requested slot top priority, unsuccessful, and with max tries. */ 423*37a7bc39SJason Zhu ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY; 424*37a7bc39SJason Zhu ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 425*37a7bc39SJason Zhu ab_data.slots[slot_number].successful_boot = 0; 426*37a7bc39SJason Zhu 427*37a7bc39SJason Zhu /* Ensure other slot doesn't have as high a priority. */ 428*37a7bc39SJason Zhu other_slot_number = 1 - slot_number; 429*37a7bc39SJason Zhu if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) { 430*37a7bc39SJason Zhu ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1; 431*37a7bc39SJason Zhu } 432*37a7bc39SJason Zhu 433*37a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 434*37a7bc39SJason Zhu 435*37a7bc39SJason Zhu out: 436*37a7bc39SJason Zhu if (ret == AVB_IO_RESULT_OK) { 437*37a7bc39SJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 438*37a7bc39SJason Zhu } 439*37a7bc39SJason Zhu return ret; 440*37a7bc39SJason Zhu } 441*37a7bc39SJason Zhu 442*37a7bc39SJason Zhu AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops, 443*37a7bc39SJason Zhu unsigned int slot_number) { 444*37a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 445*37a7bc39SJason Zhu AvbIOResult ret; 446*37a7bc39SJason Zhu 447*37a7bc39SJason Zhu avb_assert(slot_number < 2); 448*37a7bc39SJason Zhu 449*37a7bc39SJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 450*37a7bc39SJason Zhu if (ret != AVB_IO_RESULT_OK) { 451*37a7bc39SJason Zhu goto out; 452*37a7bc39SJason Zhu } 453*37a7bc39SJason Zhu 454*37a7bc39SJason Zhu slot_set_unbootable(&ab_data.slots[slot_number]); 455*37a7bc39SJason Zhu 456*37a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 457*37a7bc39SJason Zhu 458*37a7bc39SJason Zhu out: 459*37a7bc39SJason Zhu if (ret == AVB_IO_RESULT_OK) { 460*37a7bc39SJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 461*37a7bc39SJason Zhu } 462*37a7bc39SJason Zhu return ret; 463*37a7bc39SJason Zhu } 464*37a7bc39SJason Zhu 465*37a7bc39SJason Zhu AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops, 466*37a7bc39SJason Zhu unsigned int slot_number) { 467*37a7bc39SJason Zhu AvbABData ab_data, ab_data_orig; 468*37a7bc39SJason Zhu AvbIOResult ret; 469*37a7bc39SJason Zhu 470*37a7bc39SJason Zhu avb_assert(slot_number < 2); 471*37a7bc39SJason Zhu 472*37a7bc39SJason Zhu ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); 473*37a7bc39SJason Zhu if (ret != AVB_IO_RESULT_OK) { 474*37a7bc39SJason Zhu goto out; 475*37a7bc39SJason Zhu } 476*37a7bc39SJason Zhu 477*37a7bc39SJason Zhu if (!slot_is_bootable(&ab_data.slots[slot_number])) { 478*37a7bc39SJason Zhu avb_error("Cannot mark unbootable slot as successful.\n"); 479*37a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 480*37a7bc39SJason Zhu goto out; 481*37a7bc39SJason Zhu } 482*37a7bc39SJason Zhu 483*37a7bc39SJason Zhu ab_data.slots[slot_number].tries_remaining = 0; 484*37a7bc39SJason Zhu ab_data.slots[slot_number].successful_boot = 1; 485*37a7bc39SJason Zhu 486*37a7bc39SJason Zhu ret = AVB_IO_RESULT_OK; 487*37a7bc39SJason Zhu 488*37a7bc39SJason Zhu out: 489*37a7bc39SJason Zhu if (ret == AVB_IO_RESULT_OK) { 490*37a7bc39SJason Zhu ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); 491*37a7bc39SJason Zhu } 492*37a7bc39SJason Zhu return ret; 493*37a7bc39SJason Zhu } 494*37a7bc39SJason Zhu 495*37a7bc39SJason Zhu const char* avb_ab_flow_result_to_string(AvbABFlowResult result) { 496*37a7bc39SJason Zhu const char* ret = NULL; 497*37a7bc39SJason Zhu 498*37a7bc39SJason Zhu switch (result) { 499*37a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_OK: 500*37a7bc39SJason Zhu ret = "OK"; 501*37a7bc39SJason Zhu break; 502*37a7bc39SJason Zhu 503*37a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR: 504*37a7bc39SJason Zhu ret = "OK_WITH_VERIFICATION_ERROR"; 505*37a7bc39SJason Zhu break; 506*37a7bc39SJason Zhu 507*37a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_OOM: 508*37a7bc39SJason Zhu ret = "ERROR_OOM"; 509*37a7bc39SJason Zhu break; 510*37a7bc39SJason Zhu 511*37a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_IO: 512*37a7bc39SJason Zhu ret = "ERROR_IO"; 513*37a7bc39SJason Zhu break; 514*37a7bc39SJason Zhu 515*37a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS: 516*37a7bc39SJason Zhu ret = "ERROR_NO_BOOTABLE_SLOTS"; 517*37a7bc39SJason Zhu break; 518*37a7bc39SJason Zhu 519*37a7bc39SJason Zhu case AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT: 520*37a7bc39SJason Zhu ret = "ERROR_INVALID_ARGUMENT"; 521*37a7bc39SJason Zhu break; 522*37a7bc39SJason Zhu /* Do not add a 'default:' case here because of -Wswitch. */ 523*37a7bc39SJason Zhu } 524*37a7bc39SJason Zhu 525*37a7bc39SJason Zhu if (ret == NULL) { 526*37a7bc39SJason Zhu avb_error("Unknown AvbABFlowResult value.\n"); 527*37a7bc39SJason Zhu ret = "(unknown)"; 528*37a7bc39SJason Zhu } 529*37a7bc39SJason Zhu 530*37a7bc39SJason Zhu return ret; 531*37a7bc39SJason Zhu } 532