xref: /rk3399_rockchip-uboot/lib/avb/libavb/avb_cmdline.c (revision 69fdc5969fe4d637d490fddd72ffd26ea0d356fe)
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  */
avb_sub_cmdline(AvbOps * ops,const char * cmdline,const char * ab_suffix,bool using_boot_for_vbmeta,const AvbCmdlineSubstList * additional_substitutions)36ab608f80SJason Zhu char* avb_sub_cmdline(AvbOps* ops,
37ab608f80SJason Zhu                       const char* cmdline,
38ab608f80SJason Zhu                       const char* ab_suffix,
39ab608f80SJason Zhu                       bool using_boot_for_vbmeta,
40ab608f80SJason 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 
61*69fdc596SJason Zhu     /* Don't attempt to query the partition guid unless its search string is
62*69fdc596SJason Zhu      * present in the command line. Note: the original cmdline is used here,
63*69fdc596SJason Zhu      * not the replaced one. See b/116010959.
64*69fdc596SJason Zhu      */
65*69fdc596SJason Zhu     if (avb_strstr(cmdline, replace_str[n]) == NULL) {
66*69fdc596SJason Zhu       continue;
67*69fdc596SJason Zhu     }
68*69fdc596SJason Zhu 
6937a7bc39SJason Zhu     if (!avb_str_concat(part_name,
7037a7bc39SJason Zhu                         sizeof part_name,
7137a7bc39SJason Zhu                         part_name_str[n],
7237a7bc39SJason Zhu                         avb_strlen(part_name_str[n]),
7337a7bc39SJason Zhu                         ab_suffix,
7437a7bc39SJason Zhu                         avb_strlen(ab_suffix))) {
7537a7bc39SJason Zhu       avb_error("Partition name and suffix does not fit.\n");
7637a7bc39SJason Zhu       goto fail;
7737a7bc39SJason Zhu     }
7837a7bc39SJason Zhu 
7937a7bc39SJason Zhu     io_ret = ops->get_unique_guid_for_partition(
8037a7bc39SJason Zhu         ops, part_name, guid_buf, sizeof guid_buf);
8137a7bc39SJason Zhu     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
82ab608f80SJason Zhu       goto fail;
8337a7bc39SJason Zhu     } else if (io_ret != AVB_IO_RESULT_OK) {
8437a7bc39SJason Zhu       avb_error("Error getting unique GUID for partition.\n");
8537a7bc39SJason Zhu       goto fail;
8637a7bc39SJason Zhu     }
8737a7bc39SJason Zhu 
8837a7bc39SJason Zhu     if (ret == NULL) {
8937a7bc39SJason Zhu       ret = avb_replace(cmdline, replace_str[n], guid_buf);
9037a7bc39SJason Zhu     } else {
9137a7bc39SJason Zhu       char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
9237a7bc39SJason Zhu       avb_free(ret);
9337a7bc39SJason Zhu       ret = new_ret;
9437a7bc39SJason Zhu     }
9537a7bc39SJason Zhu     if (ret == NULL) {
9637a7bc39SJason Zhu       goto fail;
9737a7bc39SJason Zhu     }
9837a7bc39SJason Zhu   }
9937a7bc39SJason Zhu 
100*69fdc596SJason Zhu   /* It's possible there is no _PARTUUID for replacement above.
101*69fdc596SJason Zhu    * Duplicate cmdline to ret for additional substitutions below.
102*69fdc596SJason Zhu    */
103*69fdc596SJason Zhu   if (ret == NULL) {
104*69fdc596SJason Zhu     ret = avb_strdup(cmdline);
105*69fdc596SJason Zhu     if (ret == NULL) {
106*69fdc596SJason Zhu       goto fail;
107*69fdc596SJason Zhu     }
108*69fdc596SJason Zhu   }
109ab608f80SJason Zhu 
110ab608f80SJason Zhu   /* Replace any additional substitutions. */
111ab608f80SJason Zhu   if (additional_substitutions != NULL) {
112ab608f80SJason Zhu     for (n = 0; n < additional_substitutions->size; ++n) {
113ab608f80SJason Zhu       char* new_ret = avb_replace(ret,
114ab608f80SJason Zhu                                   additional_substitutions->tokens[n],
115ab608f80SJason Zhu                                   additional_substitutions->values[n]);
116ab608f80SJason Zhu       avb_free(ret);
117ab608f80SJason Zhu       ret = new_ret;
118ab608f80SJason Zhu       if (ret == NULL) {
119ab608f80SJason Zhu         goto fail;
120ab608f80SJason Zhu       }
121ab608f80SJason Zhu     }
122ab608f80SJason Zhu   }
123ab608f80SJason Zhu 
12437a7bc39SJason Zhu   return ret;
12537a7bc39SJason Zhu 
12637a7bc39SJason Zhu fail:
12737a7bc39SJason Zhu   if (ret != NULL) {
12837a7bc39SJason Zhu     avb_free(ret);
12937a7bc39SJason Zhu   }
13037a7bc39SJason Zhu   return NULL;
13137a7bc39SJason Zhu }
13237a7bc39SJason Zhu 
cmdline_append_option(AvbSlotVerifyData * slot_data,const char * key,const char * value)13337a7bc39SJason Zhu static int cmdline_append_option(AvbSlotVerifyData* slot_data,
13437a7bc39SJason Zhu                                  const char* key,
13537a7bc39SJason Zhu                                  const char* value) {
13637a7bc39SJason Zhu   size_t offset, key_len, value_len;
13737a7bc39SJason Zhu   char* new_cmdline;
13837a7bc39SJason Zhu 
13937a7bc39SJason Zhu   key_len = avb_strlen(key);
14037a7bc39SJason Zhu   value_len = avb_strlen(value);
14137a7bc39SJason Zhu 
14237a7bc39SJason Zhu   offset = 0;
14337a7bc39SJason Zhu   if (slot_data->cmdline != NULL) {
14437a7bc39SJason Zhu     offset = avb_strlen(slot_data->cmdline);
14537a7bc39SJason Zhu     if (offset > 0) {
14637a7bc39SJason Zhu       offset += 1;
14737a7bc39SJason Zhu     }
14837a7bc39SJason Zhu   }
14937a7bc39SJason Zhu 
15037a7bc39SJason Zhu   new_cmdline = avb_calloc(offset + key_len + value_len + 2);
15137a7bc39SJason Zhu   if (new_cmdline == NULL) {
15237a7bc39SJason Zhu     return 0;
15337a7bc39SJason Zhu   }
15437a7bc39SJason Zhu   if (offset > 0) {
15537a7bc39SJason Zhu     avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
15637a7bc39SJason Zhu     new_cmdline[offset - 1] = ' ';
15737a7bc39SJason Zhu   }
15837a7bc39SJason Zhu   avb_memcpy(new_cmdline + offset, key, key_len);
15937a7bc39SJason Zhu   new_cmdline[offset + key_len] = '=';
16037a7bc39SJason Zhu   avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
16137a7bc39SJason Zhu   if (slot_data->cmdline != NULL) {
16237a7bc39SJason Zhu     avb_free(slot_data->cmdline);
16337a7bc39SJason Zhu   }
16437a7bc39SJason Zhu   slot_data->cmdline = new_cmdline;
16537a7bc39SJason Zhu 
16637a7bc39SJason Zhu   return 1;
16737a7bc39SJason Zhu }
16837a7bc39SJason Zhu 
16937a7bc39SJason Zhu #define AVB_MAX_DIGITS_UINT64 32
17037a7bc39SJason Zhu 
17137a7bc39SJason Zhu /* Writes |value| to |digits| in base 10 followed by a NUL byte.
17237a7bc39SJason Zhu  * Returns number of characters written excluding the NUL byte.
17337a7bc39SJason Zhu  */
uint64_to_base10(uint64_t value,char digits[AVB_MAX_DIGITS_UINT64])17437a7bc39SJason Zhu static size_t uint64_to_base10(uint64_t value,
17537a7bc39SJason Zhu                                char digits[AVB_MAX_DIGITS_UINT64]) {
17637a7bc39SJason Zhu   char rev_digits[AVB_MAX_DIGITS_UINT64];
17737a7bc39SJason Zhu   size_t n, num_digits;
17837a7bc39SJason Zhu 
17937a7bc39SJason Zhu   for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
18037a7bc39SJason Zhu     rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
18137a7bc39SJason Zhu     if (value == 0) {
18237a7bc39SJason Zhu       break;
18337a7bc39SJason Zhu     }
18437a7bc39SJason Zhu   }
18537a7bc39SJason Zhu 
18637a7bc39SJason Zhu   for (n = 0; n < num_digits; n++) {
18737a7bc39SJason Zhu     digits[n] = rev_digits[num_digits - 1 - n];
18837a7bc39SJason Zhu   }
18937a7bc39SJason Zhu   digits[n] = '\0';
19037a7bc39SJason Zhu   return n;
19137a7bc39SJason Zhu }
19237a7bc39SJason Zhu 
cmdline_append_version(AvbSlotVerifyData * slot_data,const char * key,uint64_t major_version,uint64_t minor_version)19337a7bc39SJason Zhu static int cmdline_append_version(AvbSlotVerifyData* slot_data,
19437a7bc39SJason Zhu                                   const char* key,
19537a7bc39SJason Zhu                                   uint64_t major_version,
19637a7bc39SJason Zhu                                   uint64_t minor_version) {
19737a7bc39SJason Zhu   char major_digits[AVB_MAX_DIGITS_UINT64];
19837a7bc39SJason Zhu   char minor_digits[AVB_MAX_DIGITS_UINT64];
19937a7bc39SJason Zhu   char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
20037a7bc39SJason Zhu   size_t num_major_digits, num_minor_digits;
20137a7bc39SJason Zhu 
20237a7bc39SJason Zhu   num_major_digits = uint64_to_base10(major_version, major_digits);
20337a7bc39SJason Zhu   num_minor_digits = uint64_to_base10(minor_version, minor_digits);
20437a7bc39SJason Zhu   avb_memcpy(combined, major_digits, num_major_digits);
20537a7bc39SJason Zhu   combined[num_major_digits] = '.';
20637a7bc39SJason Zhu   avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
20737a7bc39SJason Zhu   combined[num_major_digits + 1 + num_minor_digits] = '\0';
20837a7bc39SJason Zhu 
20937a7bc39SJason Zhu   return cmdline_append_option(slot_data, key, combined);
21037a7bc39SJason Zhu }
21137a7bc39SJason Zhu 
cmdline_append_uint64_base10(AvbSlotVerifyData * slot_data,const char * key,uint64_t value)21237a7bc39SJason Zhu static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
21337a7bc39SJason Zhu                                         const char* key,
21437a7bc39SJason Zhu                                         uint64_t value) {
21537a7bc39SJason Zhu   char digits[AVB_MAX_DIGITS_UINT64];
21637a7bc39SJason Zhu   uint64_to_base10(value, digits);
21737a7bc39SJason Zhu   return cmdline_append_option(slot_data, key, digits);
21837a7bc39SJason Zhu }
21937a7bc39SJason Zhu 
cmdline_append_hex(AvbSlotVerifyData * slot_data,const char * key,const uint8_t * data,size_t data_len)22037a7bc39SJason Zhu static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
22137a7bc39SJason Zhu                               const char* key,
22237a7bc39SJason Zhu                               const uint8_t* data,
22337a7bc39SJason Zhu                               size_t data_len) {
22437a7bc39SJason Zhu   int ret;
225ab608f80SJason Zhu   char* hex_data = avb_bin2hex(data, data_len);
22637a7bc39SJason Zhu   if (hex_data == NULL) {
22737a7bc39SJason Zhu     return 0;
22837a7bc39SJason Zhu   }
22937a7bc39SJason Zhu   ret = cmdline_append_option(slot_data, key, hex_data);
23037a7bc39SJason Zhu   avb_free(hex_data);
23137a7bc39SJason Zhu   return ret;
23237a7bc39SJason Zhu }
23337a7bc39SJason Zhu 
avb_append_options(AvbOps * ops,AvbSlotVerifyFlags flags,AvbSlotVerifyData * slot_data,AvbVBMetaImageHeader * toplevel_vbmeta,AvbAlgorithmType algorithm_type,AvbHashtreeErrorMode hashtree_error_mode,AvbHashtreeErrorMode resolved_hashtree_error_mode)23437a7bc39SJason Zhu AvbSlotVerifyResult avb_append_options(
23537a7bc39SJason Zhu     AvbOps* ops,
236*69fdc596SJason Zhu     AvbSlotVerifyFlags flags,
23737a7bc39SJason Zhu     AvbSlotVerifyData* slot_data,
23837a7bc39SJason Zhu     AvbVBMetaImageHeader* toplevel_vbmeta,
23937a7bc39SJason Zhu     AvbAlgorithmType algorithm_type,
240*69fdc596SJason Zhu     AvbHashtreeErrorMode hashtree_error_mode,
241*69fdc596SJason Zhu     AvbHashtreeErrorMode resolved_hashtree_error_mode) {
24237a7bc39SJason Zhu   AvbSlotVerifyResult ret;
24337a7bc39SJason Zhu   const char* verity_mode = NULL;
24437a7bc39SJason Zhu   bool is_device_unlocked;
24537a7bc39SJason Zhu   AvbIOResult io_ret;
24637a7bc39SJason Zhu 
247*69fdc596SJason Zhu   /* Add androidboot.vbmeta.device option... except if not using a vbmeta
248*69fdc596SJason Zhu    * partition since it doesn't make sense in that case.
249*69fdc596SJason Zhu    */
250*69fdc596SJason Zhu   if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
25137a7bc39SJason Zhu     if (!cmdline_append_option(slot_data,
25237a7bc39SJason Zhu                                "androidboot.vbmeta.device",
25337a7bc39SJason Zhu                                "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
25437a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
25537a7bc39SJason Zhu       goto out;
25637a7bc39SJason Zhu     }
257*69fdc596SJason Zhu   }
25837a7bc39SJason Zhu 
25937a7bc39SJason Zhu   /* Add androidboot.vbmeta.avb_version option. */
26037a7bc39SJason Zhu   if (!cmdline_append_version(slot_data,
26137a7bc39SJason Zhu                               "androidboot.vbmeta.avb_version",
26237a7bc39SJason Zhu                               AVB_VERSION_MAJOR,
26337a7bc39SJason Zhu                               AVB_VERSION_MINOR)) {
26437a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
26537a7bc39SJason Zhu     goto out;
26637a7bc39SJason Zhu   }
26737a7bc39SJason Zhu 
26837a7bc39SJason Zhu   /* Set androidboot.avb.device_state to "locked" or "unlocked". */
26937a7bc39SJason Zhu   io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
27037a7bc39SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
27137a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
27237a7bc39SJason Zhu     goto out;
27337a7bc39SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
27437a7bc39SJason Zhu     avb_error("Error getting device state.\n");
27537a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
27637a7bc39SJason Zhu     goto out;
27737a7bc39SJason Zhu   }
27837a7bc39SJason Zhu   if (!cmdline_append_option(slot_data,
27937a7bc39SJason Zhu                              "androidboot.vbmeta.device_state",
28037a7bc39SJason Zhu                              is_device_unlocked ? "unlocked" : "locked")) {
28137a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
28237a7bc39SJason Zhu     goto out;
28337a7bc39SJason Zhu   }
28437a7bc39SJason Zhu 
28537a7bc39SJason Zhu   /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
28637a7bc39SJason Zhu    * function as is used to sign vbmeta.
28737a7bc39SJason Zhu    */
28837a7bc39SJason Zhu   switch (algorithm_type) {
28937a7bc39SJason Zhu     /* Explicit fallthrough. */
29037a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_NONE:
29137a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
29237a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
29337a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
29437a7bc39SJason Zhu       size_t n, total_size = 0;
295ab608f80SJason Zhu       uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE];
296ab608f80SJason Zhu       avb_slot_verify_data_calculate_vbmeta_digest(
297ab608f80SJason Zhu           slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest);
29837a7bc39SJason Zhu       for (n = 0; n < slot_data->num_vbmeta_images; n++) {
29937a7bc39SJason Zhu         total_size += slot_data->vbmeta_images[n].vbmeta_size;
30037a7bc39SJason Zhu       }
30137a7bc39SJason Zhu       if (!cmdline_append_option(
30237a7bc39SJason Zhu               slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
30337a7bc39SJason Zhu           !cmdline_append_uint64_base10(
30437a7bc39SJason Zhu               slot_data, "androidboot.vbmeta.size", total_size) ||
30537a7bc39SJason Zhu           !cmdline_append_hex(slot_data,
30637a7bc39SJason Zhu                               "androidboot.vbmeta.digest",
307ab608f80SJason Zhu                               vbmeta_digest,
30837a7bc39SJason Zhu                               AVB_SHA256_DIGEST_SIZE)) {
30937a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
31037a7bc39SJason Zhu         goto out;
31137a7bc39SJason Zhu       }
31237a7bc39SJason Zhu     } break;
31337a7bc39SJason Zhu     /* Explicit fallthrough. */
31437a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
31537a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
31637a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
31737a7bc39SJason Zhu       size_t n, total_size = 0;
318ab608f80SJason Zhu       uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE];
319ab608f80SJason Zhu       avb_slot_verify_data_calculate_vbmeta_digest(
320ab608f80SJason Zhu           slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest);
32137a7bc39SJason Zhu       for (n = 0; n < slot_data->num_vbmeta_images; n++) {
32237a7bc39SJason Zhu         total_size += slot_data->vbmeta_images[n].vbmeta_size;
32337a7bc39SJason Zhu       }
32437a7bc39SJason Zhu       if (!cmdline_append_option(
32537a7bc39SJason Zhu               slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
32637a7bc39SJason Zhu           !cmdline_append_uint64_base10(
32737a7bc39SJason Zhu               slot_data, "androidboot.vbmeta.size", total_size) ||
32837a7bc39SJason Zhu           !cmdline_append_hex(slot_data,
32937a7bc39SJason Zhu                               "androidboot.vbmeta.digest",
330ab608f80SJason Zhu                               vbmeta_digest,
33137a7bc39SJason Zhu                               AVB_SHA512_DIGEST_SIZE)) {
33237a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
33337a7bc39SJason Zhu         goto out;
33437a7bc39SJason Zhu       }
33537a7bc39SJason Zhu     } break;
33637a7bc39SJason Zhu     case _AVB_ALGORITHM_NUM_TYPES:
33737a7bc39SJason Zhu       avb_assert_not_reached();
33837a7bc39SJason Zhu       break;
33937a7bc39SJason Zhu   }
34037a7bc39SJason Zhu 
34137a7bc39SJason Zhu   /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
34237a7bc39SJason Zhu   if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
34337a7bc39SJason Zhu     verity_mode = "disabled";
34437a7bc39SJason Zhu   } else {
34537a7bc39SJason Zhu     const char* dm_verity_mode = NULL;
34637a7bc39SJason Zhu     char* new_ret;
34737a7bc39SJason Zhu 
348*69fdc596SJason Zhu     switch (resolved_hashtree_error_mode) {
34937a7bc39SJason Zhu       case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
35037a7bc39SJason Zhu         if (!cmdline_append_option(
35137a7bc39SJason Zhu                 slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
35237a7bc39SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
35337a7bc39SJason Zhu           goto out;
35437a7bc39SJason Zhu         }
35537a7bc39SJason Zhu         verity_mode = "enforcing";
35637a7bc39SJason Zhu         dm_verity_mode = "restart_on_corruption";
35737a7bc39SJason Zhu         break;
35837a7bc39SJason Zhu       case AVB_HASHTREE_ERROR_MODE_RESTART:
35937a7bc39SJason Zhu         verity_mode = "enforcing";
36037a7bc39SJason Zhu         dm_verity_mode = "restart_on_corruption";
36137a7bc39SJason Zhu         break;
36237a7bc39SJason Zhu       case AVB_HASHTREE_ERROR_MODE_EIO:
36337a7bc39SJason Zhu         verity_mode = "eio";
36437a7bc39SJason Zhu         /* For now there's no option to specify the EIO mode. So
36537a7bc39SJason Zhu          * just use 'ignore_zero_blocks' since that's already set
36637a7bc39SJason Zhu          * and dm-verity-target.c supports specifying this multiple
36737a7bc39SJason Zhu          * times.
36837a7bc39SJason Zhu          */
36937a7bc39SJason Zhu         dm_verity_mode = "ignore_zero_blocks";
37037a7bc39SJason Zhu         break;
37137a7bc39SJason Zhu       case AVB_HASHTREE_ERROR_MODE_LOGGING:
37237a7bc39SJason Zhu         verity_mode = "logging";
37337a7bc39SJason Zhu         dm_verity_mode = "ignore_corruption";
37437a7bc39SJason Zhu         break;
375*69fdc596SJason Zhu       case AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO:
376*69fdc596SJason Zhu         // Should never get here because MANAGED_RESTART_AND_EIO is
377*69fdc596SJason Zhu         // remapped by avb_manage_hashtree_error_mode().
378*69fdc596SJason Zhu         avb_assert_not_reached();
379*69fdc596SJason Zhu         break;
38037a7bc39SJason Zhu     }
38137a7bc39SJason Zhu     new_ret = avb_replace(
38237a7bc39SJason Zhu         slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
38337a7bc39SJason Zhu     avb_free(slot_data->cmdline);
38437a7bc39SJason Zhu     slot_data->cmdline = new_ret;
38537a7bc39SJason Zhu     if (slot_data->cmdline == NULL) {
38637a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
38737a7bc39SJason Zhu       goto out;
38837a7bc39SJason Zhu     }
38937a7bc39SJason Zhu   }
39037a7bc39SJason Zhu   if (!cmdline_append_option(
39137a7bc39SJason Zhu           slot_data, "androidboot.veritymode", verity_mode)) {
39237a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
39337a7bc39SJason Zhu     goto out;
39437a7bc39SJason Zhu   }
395*69fdc596SJason Zhu   if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
396*69fdc596SJason Zhu     if (!cmdline_append_option(
397*69fdc596SJason Zhu             slot_data, "androidboot.veritymode.managed", "yes")) {
398*69fdc596SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
399*69fdc596SJason Zhu       goto out;
400*69fdc596SJason Zhu     }
401*69fdc596SJason Zhu   }
40237a7bc39SJason Zhu 
40337a7bc39SJason Zhu   ret = AVB_SLOT_VERIFY_RESULT_OK;
40437a7bc39SJason Zhu 
40537a7bc39SJason Zhu out:
40637a7bc39SJason Zhu 
40737a7bc39SJason Zhu   return ret;
40837a7bc39SJason Zhu }
40937a7bc39SJason Zhu 
avb_new_cmdline_subst_list()410ab608f80SJason Zhu AvbCmdlineSubstList* avb_new_cmdline_subst_list() {
411ab608f80SJason Zhu   return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList));
412ab608f80SJason Zhu }
413ab608f80SJason Zhu 
avb_free_cmdline_subst_list(AvbCmdlineSubstList * cmdline_subst)414ab608f80SJason Zhu void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) {
415ab608f80SJason Zhu   size_t i;
416ab608f80SJason Zhu   for (i = 0; i < cmdline_subst->size; ++i) {
417ab608f80SJason Zhu     avb_free(cmdline_subst->tokens[i]);
418ab608f80SJason Zhu     avb_free(cmdline_subst->values[i]);
419ab608f80SJason Zhu   }
420ab608f80SJason Zhu   cmdline_subst->size = 0;
421ab608f80SJason Zhu   avb_free(cmdline_subst);
422ab608f80SJason Zhu }
423ab608f80SJason Zhu 
avb_add_root_digest_substitution(const char * part_name,const uint8_t * digest,size_t digest_size,AvbCmdlineSubstList * out_cmdline_subst)424ab608f80SJason Zhu AvbSlotVerifyResult avb_add_root_digest_substitution(
425ab608f80SJason Zhu     const char* part_name,
426ab608f80SJason Zhu     const uint8_t* digest,
427ab608f80SJason Zhu     size_t digest_size,
428ab608f80SJason Zhu     AvbCmdlineSubstList* out_cmdline_subst) {
429ab608f80SJason Zhu   const char* kDigestSubPrefix = "$(AVB_";
430ab608f80SJason Zhu   const char* kDigestSubSuffix = "_ROOT_DIGEST)";
431ab608f80SJason Zhu   size_t part_name_len = avb_strlen(part_name);
432ab608f80SJason Zhu   size_t list_index = out_cmdline_subst->size;
433ab608f80SJason Zhu 
434ab608f80SJason Zhu   avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE);
435ab608f80SJason Zhu   avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE);
436ab608f80SJason Zhu   if (part_name_len >= AVB_PART_NAME_MAX_SIZE ||
437ab608f80SJason Zhu       digest_size > AVB_SHA512_DIGEST_SIZE) {
438ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
439ab608f80SJason Zhu   }
440ab608f80SJason Zhu 
441ab608f80SJason Zhu   if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) {
442ab608f80SJason Zhu     /* The list is full. Currently dynamic growth of this list is not supported.
443ab608f80SJason Zhu      */
444ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
445ab608f80SJason Zhu   }
446ab608f80SJason Zhu 
447ab608f80SJason Zhu   /* Construct the token to replace in the command line based on the partition
448ab608f80SJason Zhu    * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'.
449ab608f80SJason Zhu    */
450ab608f80SJason Zhu   out_cmdline_subst->tokens[list_index] =
451ab608f80SJason Zhu       avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL);
452ab608f80SJason Zhu   if (out_cmdline_subst->tokens[list_index] == NULL) {
453ab608f80SJason Zhu     goto fail;
454ab608f80SJason Zhu   }
455ab608f80SJason Zhu   avb_uppercase(out_cmdline_subst->tokens[list_index]);
456ab608f80SJason Zhu 
457ab608f80SJason Zhu   /* The digest value is hex encoded when inserted in the command line. */
458ab608f80SJason Zhu   out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size);
459ab608f80SJason Zhu   if (out_cmdline_subst->values[list_index] == NULL) {
460ab608f80SJason Zhu     goto fail;
461ab608f80SJason Zhu   }
462ab608f80SJason Zhu 
463ab608f80SJason Zhu   out_cmdline_subst->size++;
464ab608f80SJason Zhu   return AVB_SLOT_VERIFY_RESULT_OK;
465ab608f80SJason Zhu 
466ab608f80SJason Zhu fail:
467ab608f80SJason Zhu   if (out_cmdline_subst->tokens[list_index]) {
468ab608f80SJason Zhu     avb_free(out_cmdline_subst->tokens[list_index]);
469ab608f80SJason Zhu   }
470ab608f80SJason Zhu   if (out_cmdline_subst->values[list_index]) {
471ab608f80SJason Zhu     avb_free(out_cmdline_subst->values[list_index]);
472ab608f80SJason Zhu   }
473ab608f80SJason Zhu   return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
474ab608f80SJason Zhu }
475