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