1/* 2 * Copyright (C) 2017 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_atx_slot_verify.h" 26 27#include <libavb/avb_sha.h> 28#include <libavb/libavb.h> 29#include <libavb_atx/libavb_atx.h> 30 31/* Chosen to be generous but still require a huge number of increase operations 32 * before exhausting the 64-bit space. 33 */ 34static const uint64_t kRollbackIndexIncreaseThreshold = 1000000000; 35 36/* By convention, when a rollback index is not used the value remains zero. */ 37static const uint64_t kRollbackIndexNotUsed = 0; 38 39typedef struct _AvbAtxOpsContext { 40 size_t key_version_location[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS]; 41 uint64_t key_version_value[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS]; 42 size_t next_key_version_slot; 43} AvbAtxOpsContext; 44 45typedef struct _AvbAtxOpsWithContext { 46 AvbAtxOps atx_ops; 47 AvbAtxOpsContext context; 48} AvbAtxOpsWithContext; 49 50/* Returns context associated with |atx_ops| returned by 51 * setup_ops_with_context(). 52 */ 53static AvbAtxOpsContext* get_ops_context(AvbAtxOps* atx_ops) { 54 return &((AvbAtxOpsWithContext*)atx_ops)->context; 55} 56 57/* An implementation of AvbAtxOps::set_key_version that saves the key version 58 * information to ops context data. 59 */ 60static void save_key_version_to_context(AvbAtxOps* atx_ops, 61 size_t rollback_index_location, 62 uint64_t key_version) { 63 AvbAtxOpsContext* context = get_ops_context(atx_ops); 64 size_t offset = context->next_key_version_slot++; 65 if (offset < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) { 66 context->key_version_location[offset] = rollback_index_location; 67 context->key_version_value[offset] = key_version; 68 } 69} 70 71/* Attaches context data to |existing_ops| and returns new ops. The 72 * |ops_with_context| will be used to store the new combined ops and context. 73 * The set_key_version function will be replaced in order to collect the key 74 * version information in the context. 75 */ 76static AvbAtxOps* setup_ops_with_context( 77 const AvbAtxOps* existing_ops, AvbAtxOpsWithContext* ops_with_context) { 78 avb_memset(ops_with_context, 0, sizeof(AvbAtxOpsWithContext)); 79 ops_with_context->atx_ops = *existing_ops; 80 // Close the loop on the circular reference. 81 ops_with_context->atx_ops.ops->atx_ops = &ops_with_context->atx_ops; 82 ops_with_context->atx_ops.set_key_version = save_key_version_to_context; 83 return &ops_with_context->atx_ops; 84} 85 86/* Updates the stored rollback index value for |location| to match |value|. */ 87static AvbSlotVerifyResult update_rollback_index(AvbOps* ops, 88 size_t location, 89 uint64_t value) { 90 AvbIOResult io_result = AVB_IO_RESULT_OK; 91 uint64_t current_value; 92 io_result = ops->read_rollback_index(ops, location, ¤t_value); 93 if (io_result == AVB_IO_RESULT_ERROR_OOM) { 94 return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 95 } else if (io_result != AVB_IO_RESULT_OK) { 96 avb_error("Error getting rollback index for slot.\n"); 97 return AVB_SLOT_VERIFY_RESULT_ERROR_IO; 98 } 99 if (current_value == value) { 100 // No update necessary. 101 return AVB_SLOT_VERIFY_RESULT_OK; 102 } 103 // The difference between the new and current value must not exceed the 104 // increase threshold, and the value must not decrease. 105 if (value - current_value > kRollbackIndexIncreaseThreshold) { 106 avb_error("Rollback index value cannot increase beyond the threshold.\n"); 107 return AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX; 108 } 109 // This should have been checked during verification, but check again here as 110 // a safeguard. 111 if (value < current_value) { 112 avb_error("Rollback index value cannot decrease.\n"); 113 return AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX; 114 } 115 io_result = ops->write_rollback_index(ops, location, value); 116 if (io_result == AVB_IO_RESULT_ERROR_OOM) { 117 return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 118 } else if (io_result != AVB_IO_RESULT_OK) { 119 avb_error("Error setting stored rollback index.\n"); 120 return AVB_SLOT_VERIFY_RESULT_ERROR_IO; 121 } 122 return AVB_SLOT_VERIFY_RESULT_OK; 123} 124 125AvbSlotVerifyResult avb_atx_slot_verify( 126 AvbAtxOps* atx_ops, 127 const char* ab_suffix, 128 AvbAtxLockState lock_state, 129 AvbAtxSlotState slot_state, 130 AvbAtxOemDataState oem_data_state, 131 AvbSlotVerifyData** verify_data, 132 uint8_t vbh_extension[AVB_SHA256_DIGEST_SIZE]) { 133 const char* partitions_without_oem[] = {"boot", NULL}; 134 const char* partitions_with_oem[] = {"boot", "oem_bootloader", NULL}; 135 AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK; 136 AvbSHA256Ctx ctx; 137 size_t i = 0; 138 AvbAtxOpsWithContext ops_with_context; 139 140 atx_ops = setup_ops_with_context(atx_ops, &ops_with_context); 141 142 result = avb_slot_verify(atx_ops->ops, 143 (oem_data_state == AVB_ATX_OEM_DATA_NOT_USED) 144 ? partitions_without_oem 145 : partitions_with_oem, 146 ab_suffix, 147 (lock_state == AVB_ATX_UNLOCKED) 148 ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR 149 : AVB_SLOT_VERIFY_FLAGS_NONE, 150 AVB_HASHTREE_ERROR_MODE_EIO, 151 verify_data); 152 153 if (result != AVB_SLOT_VERIFY_RESULT_OK || lock_state == AVB_ATX_UNLOCKED) { 154 return result; 155 } 156 157 /* Compute the Android Things Verified Boot Hash (VBH) extension. */ 158 avb_sha256_init(&ctx); 159 for (i = 0; i < (*verify_data)->num_vbmeta_images; i++) { 160 avb_sha256_update(&ctx, 161 (*verify_data)->vbmeta_images[i].vbmeta_data, 162 (*verify_data)->vbmeta_images[i].vbmeta_size); 163 } 164 avb_memcpy(vbh_extension, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE); 165 166 /* Increase rollback index values to match the verified slot. */ 167 if (slot_state == AVB_ATX_SLOT_MARKED_SUCCESSFUL) { 168 for (i = 0; i < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; i++) { 169 uint64_t rollback_index_value = (*verify_data)->rollback_indexes[i]; 170 if (rollback_index_value != kRollbackIndexNotUsed) { 171 result = update_rollback_index(atx_ops->ops, i, rollback_index_value); 172 if (result != AVB_SLOT_VERIFY_RESULT_OK) { 173 goto out; 174 } 175 } 176 } 177 178 /* Also increase rollback index values for Android Things key version 179 * locations. 180 */ 181 for (i = 0; i < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; i++) { 182 size_t rollback_index_location = 183 ops_with_context.context.key_version_location[i]; 184 uint64_t rollback_index_value = 185 ops_with_context.context.key_version_value[i]; 186 if (rollback_index_value != kRollbackIndexNotUsed) { 187 result = update_rollback_index( 188 atx_ops->ops, rollback_index_location, rollback_index_value); 189 if (result != AVB_SLOT_VERIFY_RESULT_OK) { 190 goto out; 191 } 192 } 193 } 194 } 195 196out: 197 if (result != AVB_SLOT_VERIFY_RESULT_OK) { 198 avb_slot_verify_data_free(*verify_data); 199 *verify_data = NULL; 200 } 201 return result; 202} 203