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_cmdline.h> 2637a7bc39SJason Zhu #include <android_avb/avb_sha.h> 2737a7bc39SJason Zhu #include <android_avb/avb_util.h> 2837a7bc39SJason Zhu #include <android_avb/avb_version.h> 2937a7bc39SJason Zhu 3037a7bc39SJason Zhu #define NUM_GUIDS 3 3137a7bc39SJason Zhu 3237a7bc39SJason Zhu /* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with 3337a7bc39SJason Zhu * values. Returns NULL on OOM, otherwise the cmdline with values 3437a7bc39SJason Zhu * replaced. 3537a7bc39SJason Zhu */ 36*ab608f80SJason Zhu char* avb_sub_cmdline(AvbOps* ops, 37*ab608f80SJason Zhu const char* cmdline, 38*ab608f80SJason Zhu const char* ab_suffix, 39*ab608f80SJason Zhu bool using_boot_for_vbmeta, 40*ab608f80SJason Zhu const AvbCmdlineSubstList* additional_substitutions) { 4137a7bc39SJason Zhu const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"}; 4237a7bc39SJason Zhu const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)", 4337a7bc39SJason Zhu "$(ANDROID_BOOT_PARTUUID)", 4437a7bc39SJason Zhu "$(ANDROID_VBMETA_PARTUUID)"}; 4537a7bc39SJason Zhu char* ret = NULL; 4637a7bc39SJason Zhu AvbIOResult io_ret; 4737a7bc39SJason Zhu size_t n; 4837a7bc39SJason Zhu 4937a7bc39SJason Zhu /* Special-case for when the top-level vbmeta struct is in the boot 5037a7bc39SJason Zhu * partition. 5137a7bc39SJason Zhu */ 5237a7bc39SJason Zhu if (using_boot_for_vbmeta) { 5337a7bc39SJason Zhu part_name_str[2] = "boot"; 5437a7bc39SJason Zhu } 5537a7bc39SJason Zhu 5637a7bc39SJason Zhu /* Replace unique partition GUIDs */ 5737a7bc39SJason Zhu for (n = 0; n < NUM_GUIDS; n++) { 5837a7bc39SJason Zhu char part_name[AVB_PART_NAME_MAX_SIZE]; 5937a7bc39SJason Zhu char guid_buf[37]; 6037a7bc39SJason Zhu 6137a7bc39SJason Zhu if (!avb_str_concat(part_name, 6237a7bc39SJason Zhu sizeof part_name, 6337a7bc39SJason Zhu part_name_str[n], 6437a7bc39SJason Zhu avb_strlen(part_name_str[n]), 6537a7bc39SJason Zhu ab_suffix, 6637a7bc39SJason Zhu avb_strlen(ab_suffix))) { 6737a7bc39SJason Zhu avb_error("Partition name and suffix does not fit.\n"); 6837a7bc39SJason Zhu goto fail; 6937a7bc39SJason Zhu } 7037a7bc39SJason Zhu 7137a7bc39SJason Zhu io_ret = ops->get_unique_guid_for_partition( 7237a7bc39SJason Zhu ops, part_name, guid_buf, sizeof guid_buf); 7337a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 74*ab608f80SJason Zhu goto fail; 7537a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 7637a7bc39SJason Zhu avb_error("Error getting unique GUID for partition.\n"); 7737a7bc39SJason Zhu goto fail; 7837a7bc39SJason Zhu } 7937a7bc39SJason Zhu 8037a7bc39SJason Zhu if (ret == NULL) { 8137a7bc39SJason Zhu ret = avb_replace(cmdline, replace_str[n], guid_buf); 8237a7bc39SJason Zhu } else { 8337a7bc39SJason Zhu char* new_ret = avb_replace(ret, replace_str[n], guid_buf); 8437a7bc39SJason Zhu avb_free(ret); 8537a7bc39SJason Zhu ret = new_ret; 8637a7bc39SJason Zhu } 8737a7bc39SJason Zhu if (ret == NULL) { 8837a7bc39SJason Zhu goto fail; 8937a7bc39SJason Zhu } 9037a7bc39SJason Zhu } 9137a7bc39SJason Zhu 92*ab608f80SJason Zhu avb_assert(ret != NULL); 93*ab608f80SJason Zhu 94*ab608f80SJason Zhu /* Replace any additional substitutions. */ 95*ab608f80SJason Zhu if (additional_substitutions != NULL) { 96*ab608f80SJason Zhu for (n = 0; n < additional_substitutions->size; ++n) { 97*ab608f80SJason Zhu char* new_ret = avb_replace(ret, 98*ab608f80SJason Zhu additional_substitutions->tokens[n], 99*ab608f80SJason Zhu additional_substitutions->values[n]); 100*ab608f80SJason Zhu avb_free(ret); 101*ab608f80SJason Zhu ret = new_ret; 102*ab608f80SJason Zhu if (ret == NULL) { 103*ab608f80SJason Zhu goto fail; 104*ab608f80SJason Zhu } 105*ab608f80SJason Zhu } 106*ab608f80SJason Zhu } 107*ab608f80SJason Zhu 10837a7bc39SJason Zhu return ret; 10937a7bc39SJason Zhu 11037a7bc39SJason Zhu fail: 11137a7bc39SJason Zhu if (ret != NULL) { 11237a7bc39SJason Zhu avb_free(ret); 11337a7bc39SJason Zhu } 11437a7bc39SJason Zhu return NULL; 11537a7bc39SJason Zhu } 11637a7bc39SJason Zhu 11737a7bc39SJason Zhu static int cmdline_append_option(AvbSlotVerifyData* slot_data, 11837a7bc39SJason Zhu const char* key, 11937a7bc39SJason Zhu const char* value) { 12037a7bc39SJason Zhu size_t offset, key_len, value_len; 12137a7bc39SJason Zhu char* new_cmdline; 12237a7bc39SJason Zhu 12337a7bc39SJason Zhu key_len = avb_strlen(key); 12437a7bc39SJason Zhu value_len = avb_strlen(value); 12537a7bc39SJason Zhu 12637a7bc39SJason Zhu offset = 0; 12737a7bc39SJason Zhu if (slot_data->cmdline != NULL) { 12837a7bc39SJason Zhu offset = avb_strlen(slot_data->cmdline); 12937a7bc39SJason Zhu if (offset > 0) { 13037a7bc39SJason Zhu offset += 1; 13137a7bc39SJason Zhu } 13237a7bc39SJason Zhu } 13337a7bc39SJason Zhu 13437a7bc39SJason Zhu new_cmdline = avb_calloc(offset + key_len + value_len + 2); 13537a7bc39SJason Zhu if (new_cmdline == NULL) { 13637a7bc39SJason Zhu return 0; 13737a7bc39SJason Zhu } 13837a7bc39SJason Zhu if (offset > 0) { 13937a7bc39SJason Zhu avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1); 14037a7bc39SJason Zhu new_cmdline[offset - 1] = ' '; 14137a7bc39SJason Zhu } 14237a7bc39SJason Zhu avb_memcpy(new_cmdline + offset, key, key_len); 14337a7bc39SJason Zhu new_cmdline[offset + key_len] = '='; 14437a7bc39SJason Zhu avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len); 14537a7bc39SJason Zhu if (slot_data->cmdline != NULL) { 14637a7bc39SJason Zhu avb_free(slot_data->cmdline); 14737a7bc39SJason Zhu } 14837a7bc39SJason Zhu slot_data->cmdline = new_cmdline; 14937a7bc39SJason Zhu 15037a7bc39SJason Zhu return 1; 15137a7bc39SJason Zhu } 15237a7bc39SJason Zhu 15337a7bc39SJason Zhu #define AVB_MAX_DIGITS_UINT64 32 15437a7bc39SJason Zhu 15537a7bc39SJason Zhu /* Writes |value| to |digits| in base 10 followed by a NUL byte. 15637a7bc39SJason Zhu * Returns number of characters written excluding the NUL byte. 15737a7bc39SJason Zhu */ 15837a7bc39SJason Zhu static size_t uint64_to_base10(uint64_t value, 15937a7bc39SJason Zhu char digits[AVB_MAX_DIGITS_UINT64]) { 16037a7bc39SJason Zhu char rev_digits[AVB_MAX_DIGITS_UINT64]; 16137a7bc39SJason Zhu size_t n, num_digits; 16237a7bc39SJason Zhu 16337a7bc39SJason Zhu for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) { 16437a7bc39SJason Zhu rev_digits[num_digits++] = avb_div_by_10(&value) + '0'; 16537a7bc39SJason Zhu if (value == 0) { 16637a7bc39SJason Zhu break; 16737a7bc39SJason Zhu } 16837a7bc39SJason Zhu } 16937a7bc39SJason Zhu 17037a7bc39SJason Zhu for (n = 0; n < num_digits; n++) { 17137a7bc39SJason Zhu digits[n] = rev_digits[num_digits - 1 - n]; 17237a7bc39SJason Zhu } 17337a7bc39SJason Zhu digits[n] = '\0'; 17437a7bc39SJason Zhu return n; 17537a7bc39SJason Zhu } 17637a7bc39SJason Zhu 17737a7bc39SJason Zhu static int cmdline_append_version(AvbSlotVerifyData* slot_data, 17837a7bc39SJason Zhu const char* key, 17937a7bc39SJason Zhu uint64_t major_version, 18037a7bc39SJason Zhu uint64_t minor_version) { 18137a7bc39SJason Zhu char major_digits[AVB_MAX_DIGITS_UINT64]; 18237a7bc39SJason Zhu char minor_digits[AVB_MAX_DIGITS_UINT64]; 18337a7bc39SJason Zhu char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1]; 18437a7bc39SJason Zhu size_t num_major_digits, num_minor_digits; 18537a7bc39SJason Zhu 18637a7bc39SJason Zhu num_major_digits = uint64_to_base10(major_version, major_digits); 18737a7bc39SJason Zhu num_minor_digits = uint64_to_base10(minor_version, minor_digits); 18837a7bc39SJason Zhu avb_memcpy(combined, major_digits, num_major_digits); 18937a7bc39SJason Zhu combined[num_major_digits] = '.'; 19037a7bc39SJason Zhu avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits); 19137a7bc39SJason Zhu combined[num_major_digits + 1 + num_minor_digits] = '\0'; 19237a7bc39SJason Zhu 19337a7bc39SJason Zhu return cmdline_append_option(slot_data, key, combined); 19437a7bc39SJason Zhu } 19537a7bc39SJason Zhu 19637a7bc39SJason Zhu static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data, 19737a7bc39SJason Zhu const char* key, 19837a7bc39SJason Zhu uint64_t value) { 19937a7bc39SJason Zhu char digits[AVB_MAX_DIGITS_UINT64]; 20037a7bc39SJason Zhu uint64_to_base10(value, digits); 20137a7bc39SJason Zhu return cmdline_append_option(slot_data, key, digits); 20237a7bc39SJason Zhu } 20337a7bc39SJason Zhu 20437a7bc39SJason Zhu static int cmdline_append_hex(AvbSlotVerifyData* slot_data, 20537a7bc39SJason Zhu const char* key, 20637a7bc39SJason Zhu const uint8_t* data, 20737a7bc39SJason Zhu size_t data_len) { 20837a7bc39SJason Zhu int ret; 209*ab608f80SJason Zhu char* hex_data = avb_bin2hex(data, data_len); 21037a7bc39SJason Zhu if (hex_data == NULL) { 21137a7bc39SJason Zhu return 0; 21237a7bc39SJason Zhu } 21337a7bc39SJason Zhu ret = cmdline_append_option(slot_data, key, hex_data); 21437a7bc39SJason Zhu avb_free(hex_data); 21537a7bc39SJason Zhu return ret; 21637a7bc39SJason Zhu } 21737a7bc39SJason Zhu 21837a7bc39SJason Zhu AvbSlotVerifyResult avb_append_options( 21937a7bc39SJason Zhu AvbOps* ops, 22037a7bc39SJason Zhu AvbSlotVerifyData* slot_data, 22137a7bc39SJason Zhu AvbVBMetaImageHeader* toplevel_vbmeta, 22237a7bc39SJason Zhu AvbAlgorithmType algorithm_type, 22337a7bc39SJason Zhu AvbHashtreeErrorMode hashtree_error_mode) { 22437a7bc39SJason Zhu AvbSlotVerifyResult ret; 22537a7bc39SJason Zhu const char* verity_mode = NULL; 22637a7bc39SJason Zhu bool is_device_unlocked; 22737a7bc39SJason Zhu AvbIOResult io_ret; 22837a7bc39SJason Zhu 22937a7bc39SJason Zhu /* Add androidboot.vbmeta.device option. */ 23037a7bc39SJason Zhu if (!cmdline_append_option(slot_data, 23137a7bc39SJason Zhu "androidboot.vbmeta.device", 23237a7bc39SJason Zhu "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { 23337a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 23437a7bc39SJason Zhu goto out; 23537a7bc39SJason Zhu } 23637a7bc39SJason Zhu 23737a7bc39SJason Zhu /* Add androidboot.vbmeta.avb_version option. */ 23837a7bc39SJason Zhu if (!cmdline_append_version(slot_data, 23937a7bc39SJason Zhu "androidboot.vbmeta.avb_version", 24037a7bc39SJason Zhu AVB_VERSION_MAJOR, 24137a7bc39SJason Zhu AVB_VERSION_MINOR)) { 24237a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 24337a7bc39SJason Zhu goto out; 24437a7bc39SJason Zhu } 24537a7bc39SJason Zhu 24637a7bc39SJason Zhu /* Set androidboot.avb.device_state to "locked" or "unlocked". */ 24737a7bc39SJason Zhu io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); 24837a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) { 24937a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 25037a7bc39SJason Zhu goto out; 25137a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) { 25237a7bc39SJason Zhu avb_error("Error getting device state.\n"); 25337a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; 25437a7bc39SJason Zhu goto out; 25537a7bc39SJason Zhu } 25637a7bc39SJason Zhu if (!cmdline_append_option(slot_data, 25737a7bc39SJason Zhu "androidboot.vbmeta.device_state", 25837a7bc39SJason Zhu is_device_unlocked ? "unlocked" : "locked")) { 25937a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 26037a7bc39SJason Zhu goto out; 26137a7bc39SJason Zhu } 26237a7bc39SJason Zhu 26337a7bc39SJason Zhu /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash 26437a7bc39SJason Zhu * function as is used to sign vbmeta. 26537a7bc39SJason Zhu */ 26637a7bc39SJason Zhu switch (algorithm_type) { 26737a7bc39SJason Zhu /* Explicit fallthrough. */ 26837a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_NONE: 26937a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA2048: 27037a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA4096: 27137a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { 27237a7bc39SJason Zhu size_t n, total_size = 0; 273*ab608f80SJason Zhu uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE]; 274*ab608f80SJason Zhu avb_slot_verify_data_calculate_vbmeta_digest( 275*ab608f80SJason Zhu slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest); 27637a7bc39SJason Zhu for (n = 0; n < slot_data->num_vbmeta_images; n++) { 27737a7bc39SJason Zhu total_size += slot_data->vbmeta_images[n].vbmeta_size; 27837a7bc39SJason Zhu } 27937a7bc39SJason Zhu if (!cmdline_append_option( 28037a7bc39SJason Zhu slot_data, "androidboot.vbmeta.hash_alg", "sha256") || 28137a7bc39SJason Zhu !cmdline_append_uint64_base10( 28237a7bc39SJason Zhu slot_data, "androidboot.vbmeta.size", total_size) || 28337a7bc39SJason Zhu !cmdline_append_hex(slot_data, 28437a7bc39SJason Zhu "androidboot.vbmeta.digest", 285*ab608f80SJason Zhu vbmeta_digest, 28637a7bc39SJason Zhu AVB_SHA256_DIGEST_SIZE)) { 28737a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 28837a7bc39SJason Zhu goto out; 28937a7bc39SJason Zhu } 29037a7bc39SJason Zhu } break; 29137a7bc39SJason Zhu /* Explicit fallthrough. */ 29237a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA2048: 29337a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA4096: 29437a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { 29537a7bc39SJason Zhu size_t n, total_size = 0; 296*ab608f80SJason Zhu uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE]; 297*ab608f80SJason Zhu avb_slot_verify_data_calculate_vbmeta_digest( 298*ab608f80SJason Zhu slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest); 29937a7bc39SJason Zhu for (n = 0; n < slot_data->num_vbmeta_images; n++) { 30037a7bc39SJason Zhu total_size += slot_data->vbmeta_images[n].vbmeta_size; 30137a7bc39SJason Zhu } 30237a7bc39SJason Zhu if (!cmdline_append_option( 30337a7bc39SJason Zhu slot_data, "androidboot.vbmeta.hash_alg", "sha512") || 30437a7bc39SJason Zhu !cmdline_append_uint64_base10( 30537a7bc39SJason Zhu slot_data, "androidboot.vbmeta.size", total_size) || 30637a7bc39SJason Zhu !cmdline_append_hex(slot_data, 30737a7bc39SJason Zhu "androidboot.vbmeta.digest", 308*ab608f80SJason Zhu vbmeta_digest, 30937a7bc39SJason Zhu AVB_SHA512_DIGEST_SIZE)) { 31037a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 31137a7bc39SJason Zhu goto out; 31237a7bc39SJason Zhu } 31337a7bc39SJason Zhu } break; 31437a7bc39SJason Zhu case _AVB_ALGORITHM_NUM_TYPES: 31537a7bc39SJason Zhu avb_assert_not_reached(); 31637a7bc39SJason Zhu break; 31737a7bc39SJason Zhu } 31837a7bc39SJason Zhu 31937a7bc39SJason Zhu /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */ 32037a7bc39SJason Zhu if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { 32137a7bc39SJason Zhu verity_mode = "disabled"; 32237a7bc39SJason Zhu } else { 32337a7bc39SJason Zhu const char* dm_verity_mode = NULL; 32437a7bc39SJason Zhu char* new_ret; 32537a7bc39SJason Zhu 32637a7bc39SJason Zhu switch (hashtree_error_mode) { 32737a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE: 32837a7bc39SJason Zhu if (!cmdline_append_option( 32937a7bc39SJason Zhu slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) { 33037a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 33137a7bc39SJason Zhu goto out; 33237a7bc39SJason Zhu } 33337a7bc39SJason Zhu verity_mode = "enforcing"; 33437a7bc39SJason Zhu dm_verity_mode = "restart_on_corruption"; 33537a7bc39SJason Zhu break; 33637a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_RESTART: 33737a7bc39SJason Zhu verity_mode = "enforcing"; 33837a7bc39SJason Zhu dm_verity_mode = "restart_on_corruption"; 33937a7bc39SJason Zhu break; 34037a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_EIO: 34137a7bc39SJason Zhu verity_mode = "eio"; 34237a7bc39SJason Zhu /* For now there's no option to specify the EIO mode. So 34337a7bc39SJason Zhu * just use 'ignore_zero_blocks' since that's already set 34437a7bc39SJason Zhu * and dm-verity-target.c supports specifying this multiple 34537a7bc39SJason Zhu * times. 34637a7bc39SJason Zhu */ 34737a7bc39SJason Zhu dm_verity_mode = "ignore_zero_blocks"; 34837a7bc39SJason Zhu break; 34937a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_LOGGING: 35037a7bc39SJason Zhu verity_mode = "logging"; 35137a7bc39SJason Zhu dm_verity_mode = "ignore_corruption"; 35237a7bc39SJason Zhu break; 35337a7bc39SJason Zhu } 35437a7bc39SJason Zhu new_ret = avb_replace( 35537a7bc39SJason Zhu slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode); 35637a7bc39SJason Zhu avb_free(slot_data->cmdline); 35737a7bc39SJason Zhu slot_data->cmdline = new_ret; 35837a7bc39SJason Zhu if (slot_data->cmdline == NULL) { 35937a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 36037a7bc39SJason Zhu goto out; 36137a7bc39SJason Zhu } 36237a7bc39SJason Zhu } 36337a7bc39SJason Zhu if (!cmdline_append_option( 36437a7bc39SJason Zhu slot_data, "androidboot.veritymode", verity_mode)) { 36537a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 36637a7bc39SJason Zhu goto out; 36737a7bc39SJason Zhu } 36837a7bc39SJason Zhu 36937a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_OK; 37037a7bc39SJason Zhu 37137a7bc39SJason Zhu out: 37237a7bc39SJason Zhu 37337a7bc39SJason Zhu return ret; 37437a7bc39SJason Zhu } 37537a7bc39SJason Zhu 376*ab608f80SJason Zhu AvbCmdlineSubstList* avb_new_cmdline_subst_list() { 377*ab608f80SJason Zhu return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList)); 378*ab608f80SJason Zhu } 379*ab608f80SJason Zhu 380*ab608f80SJason Zhu void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) { 381*ab608f80SJason Zhu size_t i; 382*ab608f80SJason Zhu for (i = 0; i < cmdline_subst->size; ++i) { 383*ab608f80SJason Zhu avb_free(cmdline_subst->tokens[i]); 384*ab608f80SJason Zhu avb_free(cmdline_subst->values[i]); 385*ab608f80SJason Zhu } 386*ab608f80SJason Zhu cmdline_subst->size = 0; 387*ab608f80SJason Zhu avb_free(cmdline_subst); 388*ab608f80SJason Zhu } 389*ab608f80SJason Zhu 390*ab608f80SJason Zhu AvbSlotVerifyResult avb_add_root_digest_substitution( 391*ab608f80SJason Zhu const char* part_name, 392*ab608f80SJason Zhu const uint8_t* digest, 393*ab608f80SJason Zhu size_t digest_size, 394*ab608f80SJason Zhu AvbCmdlineSubstList* out_cmdline_subst) { 395*ab608f80SJason Zhu const char* kDigestSubPrefix = "$(AVB_"; 396*ab608f80SJason Zhu const char* kDigestSubSuffix = "_ROOT_DIGEST)"; 397*ab608f80SJason Zhu size_t part_name_len = avb_strlen(part_name); 398*ab608f80SJason Zhu size_t list_index = out_cmdline_subst->size; 399*ab608f80SJason Zhu 400*ab608f80SJason Zhu avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE); 401*ab608f80SJason Zhu avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE); 402*ab608f80SJason Zhu if (part_name_len >= AVB_PART_NAME_MAX_SIZE || 403*ab608f80SJason Zhu digest_size > AVB_SHA512_DIGEST_SIZE) { 404*ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; 405*ab608f80SJason Zhu } 406*ab608f80SJason Zhu 407*ab608f80SJason Zhu if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) { 408*ab608f80SJason Zhu /* The list is full. Currently dynamic growth of this list is not supported. 409*ab608f80SJason Zhu */ 410*ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; 411*ab608f80SJason Zhu } 412*ab608f80SJason Zhu 413*ab608f80SJason Zhu /* Construct the token to replace in the command line based on the partition 414*ab608f80SJason Zhu * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'. 415*ab608f80SJason Zhu */ 416*ab608f80SJason Zhu out_cmdline_subst->tokens[list_index] = 417*ab608f80SJason Zhu avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL); 418*ab608f80SJason Zhu if (out_cmdline_subst->tokens[list_index] == NULL) { 419*ab608f80SJason Zhu goto fail; 420*ab608f80SJason Zhu } 421*ab608f80SJason Zhu avb_uppercase(out_cmdline_subst->tokens[list_index]); 422*ab608f80SJason Zhu 423*ab608f80SJason Zhu /* The digest value is hex encoded when inserted in the command line. */ 424*ab608f80SJason Zhu out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size); 425*ab608f80SJason Zhu if (out_cmdline_subst->values[list_index] == NULL) { 426*ab608f80SJason Zhu goto fail; 427*ab608f80SJason Zhu } 428*ab608f80SJason Zhu 429*ab608f80SJason Zhu out_cmdline_subst->size++; 430*ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_OK; 431*ab608f80SJason Zhu 432*ab608f80SJason Zhu fail: 433*ab608f80SJason Zhu if (out_cmdline_subst->tokens[list_index]) { 434*ab608f80SJason Zhu avb_free(out_cmdline_subst->tokens[list_index]); 435*ab608f80SJason Zhu } 436*ab608f80SJason Zhu if (out_cmdline_subst->values[list_index]) { 437*ab608f80SJason Zhu avb_free(out_cmdline_subst->values[list_index]); 438*ab608f80SJason Zhu } 439*ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; 440*ab608f80SJason Zhu } 441