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