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