xref: /rk3399_rockchip-uboot/lib/avb/libavb/avb_cmdline.c (revision ab608f806ee1d7fa63a18cc035e8ea62b67634e5)
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