1*d8f9d2afSIgor Opaniuk /* 2*d8f9d2afSIgor Opaniuk * Copyright (C) 2016 The Android Open Source Project 3*d8f9d2afSIgor Opaniuk * 4*d8f9d2afSIgor Opaniuk * SPDX-License-Identifier: MIT 5*d8f9d2afSIgor Opaniuk */ 6*d8f9d2afSIgor Opaniuk 7*d8f9d2afSIgor Opaniuk #include "avb_cmdline.h" 8*d8f9d2afSIgor Opaniuk #include "avb_sha.h" 9*d8f9d2afSIgor Opaniuk #include "avb_util.h" 10*d8f9d2afSIgor Opaniuk #include "avb_version.h" 11*d8f9d2afSIgor Opaniuk 12*d8f9d2afSIgor Opaniuk #define NUM_GUIDS 3 13*d8f9d2afSIgor Opaniuk 14*d8f9d2afSIgor Opaniuk /* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with 15*d8f9d2afSIgor Opaniuk * values. Returns NULL on OOM, otherwise the cmdline with values 16*d8f9d2afSIgor Opaniuk * replaced. 17*d8f9d2afSIgor Opaniuk */ 18*d8f9d2afSIgor Opaniuk char* avb_sub_cmdline(AvbOps* ops, 19*d8f9d2afSIgor Opaniuk const char* cmdline, 20*d8f9d2afSIgor Opaniuk const char* ab_suffix, 21*d8f9d2afSIgor Opaniuk bool using_boot_for_vbmeta, 22*d8f9d2afSIgor Opaniuk const AvbCmdlineSubstList* additional_substitutions) { 23*d8f9d2afSIgor Opaniuk const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"}; 24*d8f9d2afSIgor Opaniuk const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)", 25*d8f9d2afSIgor Opaniuk "$(ANDROID_BOOT_PARTUUID)", 26*d8f9d2afSIgor Opaniuk "$(ANDROID_VBMETA_PARTUUID)"}; 27*d8f9d2afSIgor Opaniuk char* ret = NULL; 28*d8f9d2afSIgor Opaniuk AvbIOResult io_ret; 29*d8f9d2afSIgor Opaniuk size_t n; 30*d8f9d2afSIgor Opaniuk 31*d8f9d2afSIgor Opaniuk /* Special-case for when the top-level vbmeta struct is in the boot 32*d8f9d2afSIgor Opaniuk * partition. 33*d8f9d2afSIgor Opaniuk */ 34*d8f9d2afSIgor Opaniuk if (using_boot_for_vbmeta) { 35*d8f9d2afSIgor Opaniuk part_name_str[2] = "boot"; 36*d8f9d2afSIgor Opaniuk } 37*d8f9d2afSIgor Opaniuk 38*d8f9d2afSIgor Opaniuk /* Replace unique partition GUIDs */ 39*d8f9d2afSIgor Opaniuk for (n = 0; n < NUM_GUIDS; n++) { 40*d8f9d2afSIgor Opaniuk char part_name[AVB_PART_NAME_MAX_SIZE]; 41*d8f9d2afSIgor Opaniuk char guid_buf[37]; 42*d8f9d2afSIgor Opaniuk 43*d8f9d2afSIgor Opaniuk if (!avb_str_concat(part_name, 44*d8f9d2afSIgor Opaniuk sizeof part_name, 45*d8f9d2afSIgor Opaniuk part_name_str[n], 46*d8f9d2afSIgor Opaniuk avb_strlen(part_name_str[n]), 47*d8f9d2afSIgor Opaniuk ab_suffix, 48*d8f9d2afSIgor Opaniuk avb_strlen(ab_suffix))) { 49*d8f9d2afSIgor Opaniuk avb_error("Partition name and suffix does not fit.\n"); 50*d8f9d2afSIgor Opaniuk goto fail; 51*d8f9d2afSIgor Opaniuk } 52*d8f9d2afSIgor Opaniuk 53*d8f9d2afSIgor Opaniuk io_ret = ops->get_unique_guid_for_partition( 54*d8f9d2afSIgor Opaniuk ops, part_name, guid_buf, sizeof guid_buf); 55*d8f9d2afSIgor Opaniuk if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 56*d8f9d2afSIgor Opaniuk goto fail; 57*d8f9d2afSIgor Opaniuk } else if (io_ret != AVB_IO_RESULT_OK) { 58*d8f9d2afSIgor Opaniuk avb_error("Error getting unique GUID for partition.\n"); 59*d8f9d2afSIgor Opaniuk goto fail; 60*d8f9d2afSIgor Opaniuk } 61*d8f9d2afSIgor Opaniuk 62*d8f9d2afSIgor Opaniuk if (ret == NULL) { 63*d8f9d2afSIgor Opaniuk ret = avb_replace(cmdline, replace_str[n], guid_buf); 64*d8f9d2afSIgor Opaniuk } else { 65*d8f9d2afSIgor Opaniuk char* new_ret = avb_replace(ret, replace_str[n], guid_buf); 66*d8f9d2afSIgor Opaniuk avb_free(ret); 67*d8f9d2afSIgor Opaniuk ret = new_ret; 68*d8f9d2afSIgor Opaniuk } 69*d8f9d2afSIgor Opaniuk if (ret == NULL) { 70*d8f9d2afSIgor Opaniuk goto fail; 71*d8f9d2afSIgor Opaniuk } 72*d8f9d2afSIgor Opaniuk } 73*d8f9d2afSIgor Opaniuk 74*d8f9d2afSIgor Opaniuk avb_assert(ret != NULL); 75*d8f9d2afSIgor Opaniuk 76*d8f9d2afSIgor Opaniuk /* Replace any additional substitutions. */ 77*d8f9d2afSIgor Opaniuk if (additional_substitutions != NULL) { 78*d8f9d2afSIgor Opaniuk for (n = 0; n < additional_substitutions->size; ++n) { 79*d8f9d2afSIgor Opaniuk char* new_ret = avb_replace(ret, 80*d8f9d2afSIgor Opaniuk additional_substitutions->tokens[n], 81*d8f9d2afSIgor Opaniuk additional_substitutions->values[n]); 82*d8f9d2afSIgor Opaniuk avb_free(ret); 83*d8f9d2afSIgor Opaniuk ret = new_ret; 84*d8f9d2afSIgor Opaniuk if (ret == NULL) { 85*d8f9d2afSIgor Opaniuk goto fail; 86*d8f9d2afSIgor Opaniuk } 87*d8f9d2afSIgor Opaniuk } 88*d8f9d2afSIgor Opaniuk } 89*d8f9d2afSIgor Opaniuk 90*d8f9d2afSIgor Opaniuk return ret; 91*d8f9d2afSIgor Opaniuk 92*d8f9d2afSIgor Opaniuk fail: 93*d8f9d2afSIgor Opaniuk if (ret != NULL) { 94*d8f9d2afSIgor Opaniuk avb_free(ret); 95*d8f9d2afSIgor Opaniuk } 96*d8f9d2afSIgor Opaniuk return NULL; 97*d8f9d2afSIgor Opaniuk } 98*d8f9d2afSIgor Opaniuk 99*d8f9d2afSIgor Opaniuk static int cmdline_append_option(AvbSlotVerifyData* slot_data, 100*d8f9d2afSIgor Opaniuk const char* key, 101*d8f9d2afSIgor Opaniuk const char* value) { 102*d8f9d2afSIgor Opaniuk size_t offset, key_len, value_len; 103*d8f9d2afSIgor Opaniuk char* new_cmdline; 104*d8f9d2afSIgor Opaniuk 105*d8f9d2afSIgor Opaniuk key_len = avb_strlen(key); 106*d8f9d2afSIgor Opaniuk value_len = avb_strlen(value); 107*d8f9d2afSIgor Opaniuk 108*d8f9d2afSIgor Opaniuk offset = 0; 109*d8f9d2afSIgor Opaniuk if (slot_data->cmdline != NULL) { 110*d8f9d2afSIgor Opaniuk offset = avb_strlen(slot_data->cmdline); 111*d8f9d2afSIgor Opaniuk if (offset > 0) { 112*d8f9d2afSIgor Opaniuk offset += 1; 113*d8f9d2afSIgor Opaniuk } 114*d8f9d2afSIgor Opaniuk } 115*d8f9d2afSIgor Opaniuk 116*d8f9d2afSIgor Opaniuk new_cmdline = avb_calloc(offset + key_len + value_len + 2); 117*d8f9d2afSIgor Opaniuk if (new_cmdline == NULL) { 118*d8f9d2afSIgor Opaniuk return 0; 119*d8f9d2afSIgor Opaniuk } 120*d8f9d2afSIgor Opaniuk if (offset > 0) { 121*d8f9d2afSIgor Opaniuk avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1); 122*d8f9d2afSIgor Opaniuk new_cmdline[offset - 1] = ' '; 123*d8f9d2afSIgor Opaniuk } 124*d8f9d2afSIgor Opaniuk avb_memcpy(new_cmdline + offset, key, key_len); 125*d8f9d2afSIgor Opaniuk new_cmdline[offset + key_len] = '='; 126*d8f9d2afSIgor Opaniuk avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len); 127*d8f9d2afSIgor Opaniuk if (slot_data->cmdline != NULL) { 128*d8f9d2afSIgor Opaniuk avb_free(slot_data->cmdline); 129*d8f9d2afSIgor Opaniuk } 130*d8f9d2afSIgor Opaniuk slot_data->cmdline = new_cmdline; 131*d8f9d2afSIgor Opaniuk 132*d8f9d2afSIgor Opaniuk return 1; 133*d8f9d2afSIgor Opaniuk } 134*d8f9d2afSIgor Opaniuk 135*d8f9d2afSIgor Opaniuk #define AVB_MAX_DIGITS_UINT64 32 136*d8f9d2afSIgor Opaniuk 137*d8f9d2afSIgor Opaniuk /* Writes |value| to |digits| in base 10 followed by a NUL byte. 138*d8f9d2afSIgor Opaniuk * Returns number of characters written excluding the NUL byte. 139*d8f9d2afSIgor Opaniuk */ 140*d8f9d2afSIgor Opaniuk static size_t uint64_to_base10(uint64_t value, 141*d8f9d2afSIgor Opaniuk char digits[AVB_MAX_DIGITS_UINT64]) { 142*d8f9d2afSIgor Opaniuk char rev_digits[AVB_MAX_DIGITS_UINT64]; 143*d8f9d2afSIgor Opaniuk size_t n, num_digits; 144*d8f9d2afSIgor Opaniuk 145*d8f9d2afSIgor Opaniuk for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) { 146*d8f9d2afSIgor Opaniuk rev_digits[num_digits++] = avb_div_by_10(&value) + '0'; 147*d8f9d2afSIgor Opaniuk if (value == 0) { 148*d8f9d2afSIgor Opaniuk break; 149*d8f9d2afSIgor Opaniuk } 150*d8f9d2afSIgor Opaniuk } 151*d8f9d2afSIgor Opaniuk 152*d8f9d2afSIgor Opaniuk for (n = 0; n < num_digits; n++) { 153*d8f9d2afSIgor Opaniuk digits[n] = rev_digits[num_digits - 1 - n]; 154*d8f9d2afSIgor Opaniuk } 155*d8f9d2afSIgor Opaniuk digits[n] = '\0'; 156*d8f9d2afSIgor Opaniuk return n; 157*d8f9d2afSIgor Opaniuk } 158*d8f9d2afSIgor Opaniuk 159*d8f9d2afSIgor Opaniuk static int cmdline_append_version(AvbSlotVerifyData* slot_data, 160*d8f9d2afSIgor Opaniuk const char* key, 161*d8f9d2afSIgor Opaniuk uint64_t major_version, 162*d8f9d2afSIgor Opaniuk uint64_t minor_version) { 163*d8f9d2afSIgor Opaniuk char major_digits[AVB_MAX_DIGITS_UINT64]; 164*d8f9d2afSIgor Opaniuk char minor_digits[AVB_MAX_DIGITS_UINT64]; 165*d8f9d2afSIgor Opaniuk char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1]; 166*d8f9d2afSIgor Opaniuk size_t num_major_digits, num_minor_digits; 167*d8f9d2afSIgor Opaniuk 168*d8f9d2afSIgor Opaniuk num_major_digits = uint64_to_base10(major_version, major_digits); 169*d8f9d2afSIgor Opaniuk num_minor_digits = uint64_to_base10(minor_version, minor_digits); 170*d8f9d2afSIgor Opaniuk avb_memcpy(combined, major_digits, num_major_digits); 171*d8f9d2afSIgor Opaniuk combined[num_major_digits] = '.'; 172*d8f9d2afSIgor Opaniuk avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits); 173*d8f9d2afSIgor Opaniuk combined[num_major_digits + 1 + num_minor_digits] = '\0'; 174*d8f9d2afSIgor Opaniuk 175*d8f9d2afSIgor Opaniuk return cmdline_append_option(slot_data, key, combined); 176*d8f9d2afSIgor Opaniuk } 177*d8f9d2afSIgor Opaniuk 178*d8f9d2afSIgor Opaniuk static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data, 179*d8f9d2afSIgor Opaniuk const char* key, 180*d8f9d2afSIgor Opaniuk uint64_t value) { 181*d8f9d2afSIgor Opaniuk char digits[AVB_MAX_DIGITS_UINT64]; 182*d8f9d2afSIgor Opaniuk uint64_to_base10(value, digits); 183*d8f9d2afSIgor Opaniuk return cmdline_append_option(slot_data, key, digits); 184*d8f9d2afSIgor Opaniuk } 185*d8f9d2afSIgor Opaniuk 186*d8f9d2afSIgor Opaniuk static int cmdline_append_hex(AvbSlotVerifyData* slot_data, 187*d8f9d2afSIgor Opaniuk const char* key, 188*d8f9d2afSIgor Opaniuk const uint8_t* data, 189*d8f9d2afSIgor Opaniuk size_t data_len) { 190*d8f9d2afSIgor Opaniuk int ret; 191*d8f9d2afSIgor Opaniuk char* hex_data = avb_bin2hex(data, data_len); 192*d8f9d2afSIgor Opaniuk if (hex_data == NULL) { 193*d8f9d2afSIgor Opaniuk return 0; 194*d8f9d2afSIgor Opaniuk } 195*d8f9d2afSIgor Opaniuk ret = cmdline_append_option(slot_data, key, hex_data); 196*d8f9d2afSIgor Opaniuk avb_free(hex_data); 197*d8f9d2afSIgor Opaniuk return ret; 198*d8f9d2afSIgor Opaniuk } 199*d8f9d2afSIgor Opaniuk 200*d8f9d2afSIgor Opaniuk AvbSlotVerifyResult avb_append_options( 201*d8f9d2afSIgor Opaniuk AvbOps* ops, 202*d8f9d2afSIgor Opaniuk AvbSlotVerifyData* slot_data, 203*d8f9d2afSIgor Opaniuk AvbVBMetaImageHeader* toplevel_vbmeta, 204*d8f9d2afSIgor Opaniuk AvbAlgorithmType algorithm_type, 205*d8f9d2afSIgor Opaniuk AvbHashtreeErrorMode hashtree_error_mode) { 206*d8f9d2afSIgor Opaniuk AvbSlotVerifyResult ret; 207*d8f9d2afSIgor Opaniuk const char* verity_mode; 208*d8f9d2afSIgor Opaniuk bool is_device_unlocked; 209*d8f9d2afSIgor Opaniuk AvbIOResult io_ret; 210*d8f9d2afSIgor Opaniuk 211*d8f9d2afSIgor Opaniuk /* Add androidboot.vbmeta.device option. */ 212*d8f9d2afSIgor Opaniuk if (!cmdline_append_option(slot_data, 213*d8f9d2afSIgor Opaniuk "androidboot.vbmeta.device", 214*d8f9d2afSIgor Opaniuk "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { 215*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 216*d8f9d2afSIgor Opaniuk goto out; 217*d8f9d2afSIgor Opaniuk } 218*d8f9d2afSIgor Opaniuk 219*d8f9d2afSIgor Opaniuk /* Add androidboot.vbmeta.avb_version option. */ 220*d8f9d2afSIgor Opaniuk if (!cmdline_append_version(slot_data, 221*d8f9d2afSIgor Opaniuk "androidboot.vbmeta.avb_version", 222*d8f9d2afSIgor Opaniuk AVB_VERSION_MAJOR, 223*d8f9d2afSIgor Opaniuk AVB_VERSION_MINOR)) { 224*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 225*d8f9d2afSIgor Opaniuk goto out; 226*d8f9d2afSIgor Opaniuk } 227*d8f9d2afSIgor Opaniuk 228*d8f9d2afSIgor Opaniuk /* Set androidboot.avb.device_state to "locked" or "unlocked". */ 229*d8f9d2afSIgor Opaniuk io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); 230*d8f9d2afSIgor Opaniuk if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 231*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 232*d8f9d2afSIgor Opaniuk goto out; 233*d8f9d2afSIgor Opaniuk } else if (io_ret != AVB_IO_RESULT_OK) { 234*d8f9d2afSIgor Opaniuk avb_error("Error getting device state.\n"); 235*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; 236*d8f9d2afSIgor Opaniuk goto out; 237*d8f9d2afSIgor Opaniuk } 238*d8f9d2afSIgor Opaniuk if (!cmdline_append_option(slot_data, 239*d8f9d2afSIgor Opaniuk "androidboot.vbmeta.device_state", 240*d8f9d2afSIgor Opaniuk is_device_unlocked ? "unlocked" : "locked")) { 241*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 242*d8f9d2afSIgor Opaniuk goto out; 243*d8f9d2afSIgor Opaniuk } 244*d8f9d2afSIgor Opaniuk 245*d8f9d2afSIgor Opaniuk /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash 246*d8f9d2afSIgor Opaniuk * function as is used to sign vbmeta. 247*d8f9d2afSIgor Opaniuk */ 248*d8f9d2afSIgor Opaniuk switch (algorithm_type) { 249*d8f9d2afSIgor Opaniuk /* Explicit fallthrough. */ 250*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_NONE: 251*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA2048: 252*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA4096: 253*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { 254*d8f9d2afSIgor Opaniuk size_t n, total_size = 0; 255*d8f9d2afSIgor Opaniuk uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE]; 256*d8f9d2afSIgor Opaniuk avb_slot_verify_data_calculate_vbmeta_digest( 257*d8f9d2afSIgor Opaniuk slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest); 258*d8f9d2afSIgor Opaniuk for (n = 0; n < slot_data->num_vbmeta_images; n++) { 259*d8f9d2afSIgor Opaniuk total_size += slot_data->vbmeta_images[n].vbmeta_size; 260*d8f9d2afSIgor Opaniuk } 261*d8f9d2afSIgor Opaniuk if (!cmdline_append_option( 262*d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.hash_alg", "sha256") || 263*d8f9d2afSIgor Opaniuk !cmdline_append_uint64_base10( 264*d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.size", total_size) || 265*d8f9d2afSIgor Opaniuk !cmdline_append_hex(slot_data, 266*d8f9d2afSIgor Opaniuk "androidboot.vbmeta.digest", 267*d8f9d2afSIgor Opaniuk vbmeta_digest, 268*d8f9d2afSIgor Opaniuk AVB_SHA256_DIGEST_SIZE)) { 269*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 270*d8f9d2afSIgor Opaniuk goto out; 271*d8f9d2afSIgor Opaniuk } 272*d8f9d2afSIgor Opaniuk } break; 273*d8f9d2afSIgor Opaniuk /* Explicit fallthrough. */ 274*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA2048: 275*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA4096: 276*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { 277*d8f9d2afSIgor Opaniuk size_t n, total_size = 0; 278*d8f9d2afSIgor Opaniuk uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE]; 279*d8f9d2afSIgor Opaniuk avb_slot_verify_data_calculate_vbmeta_digest( 280*d8f9d2afSIgor Opaniuk slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest); 281*d8f9d2afSIgor Opaniuk for (n = 0; n < slot_data->num_vbmeta_images; n++) { 282*d8f9d2afSIgor Opaniuk total_size += slot_data->vbmeta_images[n].vbmeta_size; 283*d8f9d2afSIgor Opaniuk } 284*d8f9d2afSIgor Opaniuk if (!cmdline_append_option( 285*d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.hash_alg", "sha512") || 286*d8f9d2afSIgor Opaniuk !cmdline_append_uint64_base10( 287*d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.size", total_size) || 288*d8f9d2afSIgor Opaniuk !cmdline_append_hex(slot_data, 289*d8f9d2afSIgor Opaniuk "androidboot.vbmeta.digest", 290*d8f9d2afSIgor Opaniuk vbmeta_digest, 291*d8f9d2afSIgor Opaniuk AVB_SHA512_DIGEST_SIZE)) { 292*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 293*d8f9d2afSIgor Opaniuk goto out; 294*d8f9d2afSIgor Opaniuk } 295*d8f9d2afSIgor Opaniuk } break; 296*d8f9d2afSIgor Opaniuk case _AVB_ALGORITHM_NUM_TYPES: 297*d8f9d2afSIgor Opaniuk avb_assert_not_reached(); 298*d8f9d2afSIgor Opaniuk break; 299*d8f9d2afSIgor Opaniuk } 300*d8f9d2afSIgor Opaniuk 301*d8f9d2afSIgor Opaniuk /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */ 302*d8f9d2afSIgor Opaniuk if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { 303*d8f9d2afSIgor Opaniuk verity_mode = "disabled"; 304*d8f9d2afSIgor Opaniuk } else { 305*d8f9d2afSIgor Opaniuk const char* dm_verity_mode; 306*d8f9d2afSIgor Opaniuk char* new_ret; 307*d8f9d2afSIgor Opaniuk 308*d8f9d2afSIgor Opaniuk switch (hashtree_error_mode) { 309*d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE: 310*d8f9d2afSIgor Opaniuk if (!cmdline_append_option( 311*d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) { 312*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 313*d8f9d2afSIgor Opaniuk goto out; 314*d8f9d2afSIgor Opaniuk } 315*d8f9d2afSIgor Opaniuk verity_mode = "enforcing"; 316*d8f9d2afSIgor Opaniuk dm_verity_mode = "restart_on_corruption"; 317*d8f9d2afSIgor Opaniuk break; 318*d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_RESTART: 319*d8f9d2afSIgor Opaniuk verity_mode = "enforcing"; 320*d8f9d2afSIgor Opaniuk dm_verity_mode = "restart_on_corruption"; 321*d8f9d2afSIgor Opaniuk break; 322*d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_EIO: 323*d8f9d2afSIgor Opaniuk verity_mode = "eio"; 324*d8f9d2afSIgor Opaniuk /* For now there's no option to specify the EIO mode. So 325*d8f9d2afSIgor Opaniuk * just use 'ignore_zero_blocks' since that's already set 326*d8f9d2afSIgor Opaniuk * and dm-verity-target.c supports specifying this multiple 327*d8f9d2afSIgor Opaniuk * times. 328*d8f9d2afSIgor Opaniuk */ 329*d8f9d2afSIgor Opaniuk dm_verity_mode = "ignore_zero_blocks"; 330*d8f9d2afSIgor Opaniuk break; 331*d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_LOGGING: 332*d8f9d2afSIgor Opaniuk verity_mode = "logging"; 333*d8f9d2afSIgor Opaniuk dm_verity_mode = "ignore_corruption"; 334*d8f9d2afSIgor Opaniuk break; 335*d8f9d2afSIgor Opaniuk } 336*d8f9d2afSIgor Opaniuk new_ret = avb_replace( 337*d8f9d2afSIgor Opaniuk slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode); 338*d8f9d2afSIgor Opaniuk avb_free(slot_data->cmdline); 339*d8f9d2afSIgor Opaniuk slot_data->cmdline = new_ret; 340*d8f9d2afSIgor Opaniuk if (slot_data->cmdline == NULL) { 341*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 342*d8f9d2afSIgor Opaniuk goto out; 343*d8f9d2afSIgor Opaniuk } 344*d8f9d2afSIgor Opaniuk } 345*d8f9d2afSIgor Opaniuk if (!cmdline_append_option( 346*d8f9d2afSIgor Opaniuk slot_data, "androidboot.veritymode", verity_mode)) { 347*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 348*d8f9d2afSIgor Opaniuk goto out; 349*d8f9d2afSIgor Opaniuk } 350*d8f9d2afSIgor Opaniuk 351*d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_OK; 352*d8f9d2afSIgor Opaniuk 353*d8f9d2afSIgor Opaniuk out: 354*d8f9d2afSIgor Opaniuk 355*d8f9d2afSIgor Opaniuk return ret; 356*d8f9d2afSIgor Opaniuk } 357*d8f9d2afSIgor Opaniuk 358*d8f9d2afSIgor Opaniuk AvbCmdlineSubstList* avb_new_cmdline_subst_list() { 359*d8f9d2afSIgor Opaniuk return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList)); 360*d8f9d2afSIgor Opaniuk } 361*d8f9d2afSIgor Opaniuk 362*d8f9d2afSIgor Opaniuk void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) { 363*d8f9d2afSIgor Opaniuk size_t i; 364*d8f9d2afSIgor Opaniuk for (i = 0; i < cmdline_subst->size; ++i) { 365*d8f9d2afSIgor Opaniuk avb_free(cmdline_subst->tokens[i]); 366*d8f9d2afSIgor Opaniuk avb_free(cmdline_subst->values[i]); 367*d8f9d2afSIgor Opaniuk } 368*d8f9d2afSIgor Opaniuk cmdline_subst->size = 0; 369*d8f9d2afSIgor Opaniuk avb_free(cmdline_subst); 370*d8f9d2afSIgor Opaniuk } 371*d8f9d2afSIgor Opaniuk 372*d8f9d2afSIgor Opaniuk AvbSlotVerifyResult avb_add_root_digest_substitution( 373*d8f9d2afSIgor Opaniuk const char* part_name, 374*d8f9d2afSIgor Opaniuk const uint8_t* digest, 375*d8f9d2afSIgor Opaniuk size_t digest_size, 376*d8f9d2afSIgor Opaniuk AvbCmdlineSubstList* out_cmdline_subst) { 377*d8f9d2afSIgor Opaniuk const char* kDigestSubPrefix = "$(AVB_"; 378*d8f9d2afSIgor Opaniuk const char* kDigestSubSuffix = "_ROOT_DIGEST)"; 379*d8f9d2afSIgor Opaniuk size_t part_name_len = avb_strlen(part_name); 380*d8f9d2afSIgor Opaniuk size_t list_index = out_cmdline_subst->size; 381*d8f9d2afSIgor Opaniuk 382*d8f9d2afSIgor Opaniuk avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE); 383*d8f9d2afSIgor Opaniuk avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE); 384*d8f9d2afSIgor Opaniuk if (part_name_len >= AVB_PART_NAME_MAX_SIZE || 385*d8f9d2afSIgor Opaniuk digest_size > AVB_SHA512_DIGEST_SIZE) { 386*d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; 387*d8f9d2afSIgor Opaniuk } 388*d8f9d2afSIgor Opaniuk 389*d8f9d2afSIgor Opaniuk if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) { 390*d8f9d2afSIgor Opaniuk /* The list is full. Currently dynamic growth of this list is not supported. 391*d8f9d2afSIgor Opaniuk */ 392*d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; 393*d8f9d2afSIgor Opaniuk } 394*d8f9d2afSIgor Opaniuk 395*d8f9d2afSIgor Opaniuk /* Construct the token to replace in the command line based on the partition 396*d8f9d2afSIgor Opaniuk * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'. 397*d8f9d2afSIgor Opaniuk */ 398*d8f9d2afSIgor Opaniuk out_cmdline_subst->tokens[list_index] = 399*d8f9d2afSIgor Opaniuk avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL); 400*d8f9d2afSIgor Opaniuk if (out_cmdline_subst->tokens[list_index] == NULL) { 401*d8f9d2afSIgor Opaniuk goto fail; 402*d8f9d2afSIgor Opaniuk } 403*d8f9d2afSIgor Opaniuk avb_uppercase(out_cmdline_subst->tokens[list_index]); 404*d8f9d2afSIgor Opaniuk 405*d8f9d2afSIgor Opaniuk /* The digest value is hex encoded when inserted in the command line. */ 406*d8f9d2afSIgor Opaniuk out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size); 407*d8f9d2afSIgor Opaniuk if (out_cmdline_subst->values[list_index] == NULL) { 408*d8f9d2afSIgor Opaniuk goto fail; 409*d8f9d2afSIgor Opaniuk } 410*d8f9d2afSIgor Opaniuk 411*d8f9d2afSIgor Opaniuk out_cmdline_subst->size++; 412*d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_OK; 413*d8f9d2afSIgor Opaniuk 414*d8f9d2afSIgor Opaniuk fail: 415*d8f9d2afSIgor Opaniuk if (out_cmdline_subst->tokens[list_index]) { 416*d8f9d2afSIgor Opaniuk avb_free(out_cmdline_subst->tokens[list_index]); 417*d8f9d2afSIgor Opaniuk } 418*d8f9d2afSIgor Opaniuk if (out_cmdline_subst->values[list_index]) { 419*d8f9d2afSIgor Opaniuk avb_free(out_cmdline_subst->values[list_index]); 420*d8f9d2afSIgor Opaniuk } 421*d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 422*d8f9d2afSIgor Opaniuk } 423