avb_slot_verify.c revision 01ca9962bd0d18d0a958b289fe481cdab7c072ca
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "avb_slot_verify.h"
26#include "avb_chain_partition_descriptor.h"
27#include "avb_footer.h"
28#include "avb_hash_descriptor.h"
29#include "avb_kernel_cmdline_descriptor.h"
30#include "avb_sha.h"
31#include "avb_util.h"
32#include "avb_vbmeta_image.h"
33#include "avb_version.h"
34
35/* Maximum allow length (in bytes) of a partition name, including
36 * ab_suffix.
37 */
38#define PART_NAME_MAX_SIZE 32
39
40/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
41#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
42
43/* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */
44#define MAX_NUMBER_OF_VBMETA_IMAGES 32
45
46/* Maximum size of a vbmeta image - 64 KiB. */
47#define VBMETA_MAX_SIZE (64 * 1024)
48
49/* Helper function to see if we should continue with verification in
50 * allow_verification_error=true mode if something goes wrong. See the
51 * comments for the avb_slot_verify() function for more information.
52 */
53static inline bool result_should_continue(AvbSlotVerifyResult result) {
54  switch (result) {
55    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
56    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
57    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
58    case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
59    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
60      return false;
61
62    case AVB_SLOT_VERIFY_RESULT_OK:
63    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
64    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
65    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
66      return true;
67  }
68
69  return false;
70}
71
72static AvbSlotVerifyResult load_and_verify_hash_partition(
73    AvbOps* ops,
74    const char* const* requested_partitions,
75    const char* ab_suffix,
76    bool allow_verification_error,
77    const AvbDescriptor* descriptor,
78    AvbSlotVerifyData* slot_data) {
79  AvbHashDescriptor hash_desc;
80  const uint8_t* desc_partition_name = NULL;
81  const uint8_t* desc_salt;
82  const uint8_t* desc_digest;
83  char part_name[PART_NAME_MAX_SIZE];
84  AvbSlotVerifyResult ret;
85  AvbIOResult io_ret;
86  uint8_t* image_buf = NULL;
87  size_t part_num_read;
88  uint8_t* digest;
89  size_t digest_len;
90  const char* found;
91  uint64_t image_size;
92
93  if (!avb_hash_descriptor_validate_and_byteswap(
94          (const AvbHashDescriptor*)descriptor, &hash_desc)) {
95    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
96    goto out;
97  }
98
99  desc_partition_name =
100      ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
101  desc_salt = desc_partition_name + hash_desc.partition_name_len;
102  desc_digest = desc_salt + hash_desc.salt_len;
103
104  if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
105    avb_error("Partition name is not valid UTF-8.\n");
106    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
107    goto out;
108  }
109
110  /* Don't bother loading or validating unless the partition was
111   * requested in the first place.
112   */
113  found = avb_strv_find_str(requested_partitions,
114                            (const char*)desc_partition_name,
115                            hash_desc.partition_name_len);
116  if (found == NULL) {
117    ret = AVB_SLOT_VERIFY_RESULT_OK;
118    goto out;
119  }
120
121  if (!avb_str_concat(part_name,
122                      sizeof part_name,
123                      (const char*)desc_partition_name,
124                      hash_desc.partition_name_len,
125                      ab_suffix,
126                      avb_strlen(ab_suffix))) {
127    avb_error("Partition name and suffix does not fit.\n");
128    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
129    goto out;
130  }
131
132  /* If we're allowing verification errors then hash_desc.image_size
133   * may no longer match what's in the partition... so in this case
134   * just load the entire partition.
135   *
136   * For example, this can happen if a developer does 'fastboot flash
137   * boot /path/to/new/and/bigger/boot.img'. We want this to work
138   * since it's such a common workflow.
139   */
140  image_size = hash_desc.image_size;
141  if (allow_verification_error) {
142    if (ops->get_size_of_partition == NULL) {
143      avb_errorv(part_name,
144                 ": The get_size_of_partition() operation is "
145                 "not implemented so we may not load the entire partition. "
146                 "Please implement.",
147                 NULL);
148    } else {
149      io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
150      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
151        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
152        goto out;
153      } else if (io_ret != AVB_IO_RESULT_OK) {
154        avb_errorv(part_name, ": Error determining partition size.\n", NULL);
155        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
156        goto out;
157      }
158      avb_debugv(part_name, ": Loading entire partition.\n", NULL);
159    }
160  }
161
162  image_buf = avb_malloc(image_size);
163  if (image_buf == NULL) {
164    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
165    goto out;
166  }
167
168  io_ret = ops->read_from_partition(
169      ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read);
170  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
171    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
172    goto out;
173  } else if (io_ret != AVB_IO_RESULT_OK) {
174    avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
175    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
176    goto out;
177  }
178  if (part_num_read != image_size) {
179    avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
180    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
181    goto out;
182  }
183
184  if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
185    AvbSHA256Ctx sha256_ctx;
186    avb_sha256_init(&sha256_ctx);
187    avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
188    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
189    digest = avb_sha256_final(&sha256_ctx);
190    digest_len = AVB_SHA256_DIGEST_SIZE;
191  } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
192    AvbSHA512Ctx sha512_ctx;
193    avb_sha512_init(&sha512_ctx);
194    avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
195    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
196    digest = avb_sha512_final(&sha512_ctx);
197    digest_len = AVB_SHA512_DIGEST_SIZE;
198  } else {
199    avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
200    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
201    goto out;
202  }
203
204  if (digest_len != hash_desc.digest_len) {
205    avb_errorv(
206        part_name, ": Digest in descriptor not of expected size.\n", NULL);
207    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
208    goto out;
209  }
210
211  if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) {
212    avb_errorv(part_name,
213               ": Hash of data does not match digest in descriptor.\n",
214               NULL);
215    ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
216    goto out;
217  }
218
219  ret = AVB_SLOT_VERIFY_RESULT_OK;
220
221out:
222
223  /* If it worked and something was loaded, copy to slot_data. */
224  if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) &&
225      image_buf != NULL) {
226    AvbPartitionData* loaded_partition;
227    if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
228      avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
229      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
230      goto fail;
231    }
232    loaded_partition =
233        &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
234    loaded_partition->partition_name = avb_strdup(found);
235    loaded_partition->data_size = image_size;
236    loaded_partition->data = image_buf;
237    image_buf = NULL;
238  }
239
240fail:
241  if (image_buf != NULL) {
242    avb_free(image_buf);
243  }
244  return ret;
245}
246
247static AvbSlotVerifyResult load_and_verify_vbmeta(
248    AvbOps* ops,
249    const char* const* requested_partitions,
250    const char* ab_suffix,
251    bool allow_verification_error,
252    AvbVBMetaImageFlags toplevel_vbmeta_flags,
253    int rollback_index_location,
254    const char* partition_name,
255    size_t partition_name_len,
256    const uint8_t* expected_public_key,
257    size_t expected_public_key_length,
258    AvbSlotVerifyData* slot_data,
259    AvbAlgorithmType* out_algorithm_type) {
260  char full_partition_name[PART_NAME_MAX_SIZE];
261  AvbSlotVerifyResult ret;
262  AvbIOResult io_ret;
263  size_t vbmeta_offset;
264  size_t vbmeta_size;
265  uint8_t* vbmeta_buf = NULL;
266  size_t vbmeta_num_read;
267  AvbVBMetaVerifyResult vbmeta_ret;
268  const uint8_t* pk_data;
269  size_t pk_len;
270  AvbVBMetaImageHeader vbmeta_header;
271  uint64_t stored_rollback_index;
272  const AvbDescriptor** descriptors = NULL;
273  size_t num_descriptors;
274  size_t n;
275  bool is_main_vbmeta;
276  bool is_vbmeta_partition;
277  AvbVBMetaData* vbmeta_image_data = NULL;
278
279  ret = AVB_SLOT_VERIFY_RESULT_OK;
280
281  avb_assert(slot_data != NULL);
282
283  /* Since we allow top-level vbmeta in 'boot', use
284   * rollback_index_location to determine whether we're the main
285   * vbmeta struct.
286   */
287  is_main_vbmeta = (rollback_index_location == 0);
288  is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
289
290  if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
291    avb_error("Partition name is not valid UTF-8.\n");
292    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
293    goto out;
294  }
295
296  /* Construct full partition name. */
297  if (!avb_str_concat(full_partition_name,
298                      sizeof full_partition_name,
299                      partition_name,
300                      partition_name_len,
301                      ab_suffix,
302                      avb_strlen(ab_suffix))) {
303    avb_error("Partition name and suffix does not fit.\n");
304    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
305    goto out;
306  }
307
308  avb_debugv("Loading vbmeta struct from partition '",
309             full_partition_name,
310             "'.\n",
311             NULL);
312
313  /* If we're loading from the main vbmeta partition, the vbmeta
314   * struct is in the beginning. Otherwise we have to locate it via a
315   * footer.
316   */
317  if (is_vbmeta_partition) {
318    vbmeta_offset = 0;
319    vbmeta_size = VBMETA_MAX_SIZE;
320  } else {
321    uint8_t footer_buf[AVB_FOOTER_SIZE];
322    size_t footer_num_read;
323    AvbFooter footer;
324
325    io_ret = ops->read_from_partition(ops,
326                                      full_partition_name,
327                                      -AVB_FOOTER_SIZE,
328                                      AVB_FOOTER_SIZE,
329                                      footer_buf,
330                                      &footer_num_read);
331    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
332      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
333      goto out;
334    } else if (io_ret != AVB_IO_RESULT_OK) {
335      avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
336      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
337      goto out;
338    }
339    avb_assert(footer_num_read == AVB_FOOTER_SIZE);
340
341    if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
342                                          &footer)) {
343      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
344      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
345      goto out;
346    }
347
348    /* Basic footer sanity check since the data is untrusted. */
349    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
350      avb_errorv(
351          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
352      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
353      goto out;
354    }
355
356    vbmeta_offset = footer.vbmeta_offset;
357    vbmeta_size = footer.vbmeta_size;
358  }
359
360  vbmeta_buf = avb_malloc(vbmeta_size);
361  if (vbmeta_buf == NULL) {
362    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
363    goto out;
364  }
365
366  io_ret = ops->read_from_partition(ops,
367                                    full_partition_name,
368                                    vbmeta_offset,
369                                    vbmeta_size,
370                                    vbmeta_buf,
371                                    &vbmeta_num_read);
372  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
373    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
374    goto out;
375  } else if (io_ret != AVB_IO_RESULT_OK) {
376    /* If we're looking for 'vbmeta' but there is no such partition,
377     * go try to get it from the boot partition instead.
378     */
379    if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
380        is_vbmeta_partition) {
381      avb_debugv(full_partition_name,
382                 ": No such partition. Trying 'boot' instead.\n",
383                 NULL);
384      ret = load_and_verify_vbmeta(ops,
385                                   requested_partitions,
386                                   ab_suffix,
387                                   allow_verification_error,
388                                   0 /* toplevel_vbmeta_flags */,
389                                   0 /* rollback_index_location */,
390                                   "boot",
391                                   avb_strlen("boot"),
392                                   NULL /* expected_public_key */,
393                                   0 /* expected_public_key_length */,
394                                   slot_data,
395                                   out_algorithm_type);
396      goto out;
397    } else {
398      avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
399      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
400      goto out;
401    }
402  }
403  avb_assert(vbmeta_num_read <= vbmeta_size);
404
405  /* Check if the image is properly signed and get the public key used
406   * to sign the image.
407   */
408  vbmeta_ret =
409      avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
410  switch (vbmeta_ret) {
411    case AVB_VBMETA_VERIFY_RESULT_OK:
412      avb_assert(pk_data != NULL && pk_len > 0);
413      break;
414
415    case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
416    case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
417    case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
418      ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
419      avb_errorv(full_partition_name,
420                 ": Error verifying vbmeta image: ",
421                 avb_vbmeta_verify_result_to_string(vbmeta_ret),
422                 "\n",
423                 NULL);
424      if (!allow_verification_error) {
425        goto out;
426      }
427      break;
428
429    case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
430      /* No way to continue this case. */
431      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
432      avb_errorv(full_partition_name,
433                 ": Error verifying vbmeta image: invalid vbmeta header\n",
434                 NULL);
435      goto out;
436
437    case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
438      /* No way to continue this case. */
439      ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
440      avb_errorv(full_partition_name,
441                 ": Error verifying vbmeta image: unsupported AVB version\n",
442                 NULL);
443      goto out;
444  }
445
446  /* Byteswap the header. */
447  avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
448                                             &vbmeta_header);
449
450  /* If we're the toplevel, assign flags so they'll be passed down. */
451  if (is_main_vbmeta) {
452    toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags;
453  } else {
454    if (vbmeta_header.flags != 0) {
455      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
456      avb_errorv(full_partition_name,
457                 ": chained vbmeta image has non-zero flags\n",
458                 NULL);
459      goto out;
460    }
461  }
462
463  /* Check if key used to make signature matches what is expected. */
464  if (pk_data != NULL) {
465    if (expected_public_key != NULL) {
466      avb_assert(!is_main_vbmeta);
467      if (expected_public_key_length != pk_len ||
468          avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
469        avb_errorv(full_partition_name,
470                   ": Public key used to sign data does not match key in chain "
471                   "partition descriptor.\n",
472                   NULL);
473        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
474        if (!allow_verification_error) {
475          goto out;
476        }
477      }
478    } else {
479      bool key_is_trusted = false;
480      const uint8_t* pk_metadata = NULL;
481      size_t pk_metadata_len = 0;
482
483      if (vbmeta_header.public_key_metadata_size > 0) {
484        pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) +
485                      vbmeta_header.authentication_data_block_size +
486                      vbmeta_header.public_key_metadata_offset;
487        pk_metadata_len = vbmeta_header.public_key_metadata_size;
488      }
489
490      avb_assert(is_main_vbmeta);
491      io_ret = ops->validate_vbmeta_public_key(
492          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
493      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
494        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
495        goto out;
496      } else if (io_ret != AVB_IO_RESULT_OK) {
497        avb_errorv(full_partition_name,
498                   ": Error while checking public key used to sign data.\n",
499                   NULL);
500        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
501        goto out;
502      }
503      if (!key_is_trusted) {
504        avb_errorv(full_partition_name,
505                   ": Public key used to sign data rejected.\n",
506                   NULL);
507        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
508        if (!allow_verification_error) {
509          goto out;
510        }
511      }
512    }
513  }
514
515  /* Check rollback index. */
516  io_ret = ops->read_rollback_index(
517      ops, rollback_index_location, &stored_rollback_index);
518  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
519    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
520    goto out;
521  } else if (io_ret != AVB_IO_RESULT_OK) {
522    avb_errorv(full_partition_name,
523               ": Error getting rollback index for location.\n",
524               NULL);
525    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
526    goto out;
527  }
528  if (vbmeta_header.rollback_index < stored_rollback_index) {
529    avb_errorv(
530        full_partition_name,
531        ": Image rollback index is less than the stored rollback index.\n",
532        NULL);
533    ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
534    if (!allow_verification_error) {
535      goto out;
536    }
537  }
538
539  /* Copy vbmeta to vbmeta_images before recursing. */
540  if (is_main_vbmeta) {
541    avb_assert(slot_data->num_vbmeta_images == 0);
542  } else {
543    avb_assert(slot_data->num_vbmeta_images > 0);
544  }
545  if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
546    avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
547    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
548    goto out;
549  }
550  vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++];
551  vbmeta_image_data->partition_name = avb_strdup(partition_name);
552  vbmeta_image_data->vbmeta_data = vbmeta_buf;
553  /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
554   * and this includes data past the end of the image. Pass the
555   * actual size of the vbmeta image. Also, no need to use
556   * avb_safe_add() since the header has already been verified.
557   */
558  vbmeta_image_data->vbmeta_size =
559      sizeof(AvbVBMetaImageHeader) +
560      vbmeta_header.authentication_data_block_size +
561      vbmeta_header.auxiliary_data_block_size;
562  vbmeta_image_data->verify_result = vbmeta_ret;
563
564  /* Now go through all descriptors and take the appropriate action:
565   *
566   * - hash descriptor: Load data from partition, calculate hash, and
567   *   checks that it matches what's in the hash descriptor.
568   *
569   * - hashtree descriptor: Do nothing since verification happens
570   *   on-the-fly from within the OS.
571   *
572   * - chained partition descriptor: Load the footer, load the vbmeta
573   *   image, verify vbmeta image (includes rollback checks, hash
574   *   checks, bail on chained partitions).
575   */
576  descriptors =
577      avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
578  for (n = 0; n < num_descriptors; n++) {
579    AvbDescriptor desc;
580
581    if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
582      avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
583      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
584      goto out;
585    }
586
587    switch (desc.tag) {
588      case AVB_DESCRIPTOR_TAG_HASH: {
589        AvbSlotVerifyResult sub_ret;
590        sub_ret = load_and_verify_hash_partition(ops,
591                                                 requested_partitions,
592                                                 ab_suffix,
593                                                 allow_verification_error,
594                                                 descriptors[n],
595                                                 slot_data);
596        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
597          ret = sub_ret;
598          if (!allow_verification_error || !result_should_continue(ret)) {
599            goto out;
600          }
601        }
602      } break;
603
604      case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
605        AvbSlotVerifyResult sub_ret;
606        AvbChainPartitionDescriptor chain_desc;
607        const uint8_t* chain_partition_name;
608        const uint8_t* chain_public_key;
609
610        /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
611        if (!is_main_vbmeta) {
612          avb_errorv(full_partition_name,
613                     ": Encountered chain descriptor not in main image.\n",
614                     NULL);
615          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
616          goto out;
617        }
618
619        if (!avb_chain_partition_descriptor_validate_and_byteswap(
620                (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
621          avb_errorv(full_partition_name,
622                     ": Chain partition descriptor is invalid.\n",
623                     NULL);
624          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
625          goto out;
626        }
627
628        if (chain_desc.rollback_index_location == 0) {
629          avb_errorv(full_partition_name,
630                     ": Chain partition has invalid "
631                     "rollback_index_location field.\n",
632                     NULL);
633          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
634          goto out;
635        }
636
637        chain_partition_name = ((const uint8_t*)descriptors[n]) +
638                               sizeof(AvbChainPartitionDescriptor);
639        chain_public_key = chain_partition_name + chain_desc.partition_name_len;
640
641        sub_ret = load_and_verify_vbmeta(ops,
642                                         requested_partitions,
643                                         ab_suffix,
644                                         allow_verification_error,
645                                         toplevel_vbmeta_flags,
646                                         chain_desc.rollback_index_location,
647                                         (const char*)chain_partition_name,
648                                         chain_desc.partition_name_len,
649                                         chain_public_key,
650                                         chain_desc.public_key_len,
651                                         slot_data,
652                                         NULL /* out_algorithm_type */);
653        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
654          ret = sub_ret;
655          if (!result_should_continue(ret)) {
656            goto out;
657          }
658        }
659      } break;
660
661      case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
662        const uint8_t* kernel_cmdline;
663        AvbKernelCmdlineDescriptor kernel_cmdline_desc;
664        bool apply_cmdline;
665
666        if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
667                (AvbKernelCmdlineDescriptor*)descriptors[n],
668                &kernel_cmdline_desc)) {
669          avb_errorv(full_partition_name,
670                     ": Kernel cmdline descriptor is invalid.\n",
671                     NULL);
672          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
673          goto out;
674        }
675
676        kernel_cmdline = ((const uint8_t*)descriptors[n]) +
677                         sizeof(AvbKernelCmdlineDescriptor);
678
679        if (!avb_validate_utf8(kernel_cmdline,
680                               kernel_cmdline_desc.kernel_cmdline_length)) {
681          avb_errorv(full_partition_name,
682                     ": Kernel cmdline is not valid UTF-8.\n",
683                     NULL);
684          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
685          goto out;
686        }
687
688        /* Compare the flags for top-level VBMeta struct with flags in
689         * the command-line descriptor so command-line snippets only
690         * intended for a certain mode (dm-verity enabled/disabled)
691         * are skipped if applicable.
692         */
693        apply_cmdline = true;
694        if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
695          if (kernel_cmdline_desc.flags &
696              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
697            apply_cmdline = false;
698          }
699        } else {
700          if (kernel_cmdline_desc.flags &
701              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
702            apply_cmdline = false;
703          }
704        }
705
706        if (apply_cmdline) {
707          if (slot_data->cmdline == NULL) {
708            slot_data->cmdline =
709                avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
710            if (slot_data->cmdline == NULL) {
711              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
712              goto out;
713            }
714            avb_memcpy(slot_data->cmdline,
715                       kernel_cmdline,
716                       kernel_cmdline_desc.kernel_cmdline_length);
717          } else {
718            /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
719            size_t orig_size = avb_strlen(slot_data->cmdline);
720            size_t new_size =
721                orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
722            char* new_cmdline = avb_calloc(new_size);
723            if (new_cmdline == NULL) {
724              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
725              goto out;
726            }
727            avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
728            new_cmdline[orig_size] = ' ';
729            avb_memcpy(new_cmdline + orig_size + 1,
730                       kernel_cmdline,
731                       kernel_cmdline_desc.kernel_cmdline_length);
732            avb_free(slot_data->cmdline);
733            slot_data->cmdline = new_cmdline;
734          }
735        }
736      } break;
737
738      /* Explicit fall-through */
739      case AVB_DESCRIPTOR_TAG_PROPERTY:
740      case AVB_DESCRIPTOR_TAG_HASHTREE:
741        /* Do nothing. */
742        break;
743    }
744  }
745
746  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
747    avb_errorv(
748        full_partition_name, ": Invalid rollback_index_location.\n", NULL);
749    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
750    goto out;
751  }
752
753  slot_data->rollback_indexes[rollback_index_location] =
754      vbmeta_header.rollback_index;
755
756  if (out_algorithm_type != NULL) {
757    *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
758  }
759
760out:
761  /* If |vbmeta_image_data| isn't NULL it means that it adopted
762   * |vbmeta_buf| so in that case don't free it here.
763   */
764  if (vbmeta_image_data == NULL) {
765    if (vbmeta_buf != NULL) {
766      avb_free(vbmeta_buf);
767    }
768  }
769  if (descriptors != NULL) {
770    avb_free(descriptors);
771  }
772  return ret;
773}
774
775#define NUM_GUIDS 3
776
777/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
778 * values. Returns NULL on OOM, otherwise the cmdline with values
779 * replaced.
780 */
781static char* sub_cmdline(AvbOps* ops,
782                         const char* cmdline,
783                         const char* ab_suffix,
784                         bool using_boot_for_vbmeta) {
785  const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
786  const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
787                                        "$(ANDROID_BOOT_PARTUUID)",
788                                        "$(ANDROID_VBMETA_PARTUUID)"};
789  char* ret = NULL;
790  AvbIOResult io_ret;
791
792  /* Special-case for when the top-level vbmeta struct is in the boot
793   * partition.
794   */
795  if (using_boot_for_vbmeta) {
796    part_name_str[2] = "boot";
797  }
798
799  /* Replace unique partition GUIDs */
800  for (size_t n = 0; n < NUM_GUIDS; n++) {
801    char part_name[PART_NAME_MAX_SIZE];
802    char guid_buf[37];
803
804    if (!avb_str_concat(part_name,
805                        sizeof part_name,
806                        part_name_str[n],
807                        avb_strlen(part_name_str[n]),
808                        ab_suffix,
809                        avb_strlen(ab_suffix))) {
810      avb_error("Partition name and suffix does not fit.\n");
811      goto fail;
812    }
813
814    io_ret = ops->get_unique_guid_for_partition(
815        ops, part_name, guid_buf, sizeof guid_buf);
816    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
817      return NULL;
818    } else if (io_ret != AVB_IO_RESULT_OK) {
819      avb_error("Error getting unique GUID for partition.\n");
820      goto fail;
821    }
822
823    if (ret == NULL) {
824      ret = avb_replace(cmdline, replace_str[n], guid_buf);
825    } else {
826      char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
827      avb_free(ret);
828      ret = new_ret;
829    }
830    if (ret == NULL) {
831      goto fail;
832    }
833  }
834
835  return ret;
836
837fail:
838  if (ret != NULL) {
839    avb_free(ret);
840  }
841  return NULL;
842}
843
844static int cmdline_append_option(AvbSlotVerifyData* slot_data,
845                                 const char* key,
846                                 const char* value) {
847  size_t offset, key_len, value_len;
848  char* new_cmdline;
849
850  key_len = avb_strlen(key);
851  value_len = avb_strlen(value);
852
853  offset = 0;
854  if (slot_data->cmdline != NULL) {
855    offset = avb_strlen(slot_data->cmdline);
856    if (offset > 0) {
857      offset += 1;
858    }
859  }
860
861  new_cmdline = avb_calloc(offset + key_len + value_len + 2);
862  if (new_cmdline == NULL) {
863    return 0;
864  }
865  if (offset > 0) {
866    avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
867    new_cmdline[offset - 1] = ' ';
868  }
869  avb_memcpy(new_cmdline + offset, key, key_len);
870  new_cmdline[offset + key_len] = '=';
871  avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
872  if (slot_data->cmdline != NULL) {
873    avb_free(slot_data->cmdline);
874  }
875  slot_data->cmdline = new_cmdline;
876
877  return 1;
878}
879
880#define AVB_MAX_DIGITS_UINT64 32
881
882/* Writes |value| to |digits| in base 10 followed by a NUL byte.
883 * Returns number of characters written excluding the NUL byte.
884 */
885static size_t uint64_to_base10(uint64_t value,
886                               char digits[AVB_MAX_DIGITS_UINT64]) {
887  char rev_digits[AVB_MAX_DIGITS_UINT64];
888  size_t n, num_digits;
889
890  for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
891    rev_digits[num_digits++] = (value % 10) + '0';
892    value /= 10;
893    if (value == 0) {
894      break;
895    }
896  }
897
898  for (n = 0; n < num_digits; n++) {
899    digits[n] = rev_digits[num_digits - 1 - n];
900  }
901  digits[n] = '\0';
902  return n;
903}
904
905static int cmdline_append_version(AvbSlotVerifyData* slot_data,
906                                  const char* key,
907                                  uint64_t major_version,
908                                  uint64_t minor_version) {
909  char major_digits[AVB_MAX_DIGITS_UINT64];
910  char minor_digits[AVB_MAX_DIGITS_UINT64];
911  char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
912  size_t num_major_digits, num_minor_digits;
913
914  num_major_digits = uint64_to_base10(major_version, major_digits);
915  num_minor_digits = uint64_to_base10(minor_version, minor_digits);
916  avb_memcpy(combined, major_digits, num_major_digits);
917  combined[num_major_digits] = '.';
918  avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
919  combined[num_major_digits + 1 + num_minor_digits] = '\0';
920
921  return cmdline_append_option(slot_data, key, combined);
922}
923
924static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
925                                        const char* key,
926                                        uint64_t value) {
927  char digits[AVB_MAX_DIGITS_UINT64];
928  uint64_to_base10(value, digits);
929  return cmdline_append_option(slot_data, key, digits);
930}
931
932static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
933                              const char* key,
934                              const uint8_t* data,
935                              size_t data_len) {
936  char hex_digits[17] = "0123456789abcdef";
937  char* hex_data;
938  int ret;
939  size_t n;
940
941  hex_data = avb_malloc(data_len * 2 + 1);
942  if (hex_data == NULL) {
943    return 0;
944  }
945
946  for (n = 0; n < data_len; n++) {
947    hex_data[n * 2] = hex_digits[data[n] >> 4];
948    hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
949  }
950  hex_data[n * 2] = '\0';
951
952  ret = cmdline_append_option(slot_data, key, hex_data);
953  avb_free(hex_data);
954  return ret;
955}
956
957AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
958                                    const char* const* requested_partitions,
959                                    const char* ab_suffix,
960                                    AvbSlotVerifyFlags flags,
961                                    AvbHashtreeErrorMode hashtree_error_mode,
962                                    AvbSlotVerifyData** out_data) {
963  AvbSlotVerifyResult ret;
964  AvbSlotVerifyData* slot_data = NULL;
965  AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
966  AvbIOResult io_ret;
967  bool using_boot_for_vbmeta = false;
968  AvbVBMetaImageHeader toplevel_vbmeta;
969  const char* verity_mode;
970  bool allow_verification_error =
971      (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
972
973  /* Fail early if we're missing the AvbOps needed for slot verification.
974   *
975   * For now, handle get_size_of_partition() not being implemented. In
976   * a later release we may change that.
977   */
978  avb_assert(ops->read_is_device_unlocked != NULL);
979  avb_assert(ops->read_from_partition != NULL);
980  avb_assert(ops->validate_vbmeta_public_key != NULL);
981  avb_assert(ops->read_rollback_index != NULL);
982  avb_assert(ops->get_unique_guid_for_partition != NULL);
983  /* avb_assert(ops->get_size_of_partition != NULL); */
984
985  if (out_data != NULL) {
986    *out_data = NULL;
987  }
988
989  /* Allowing dm-verity errors defeats the purpose of verified boot so
990   * only allow this if set up to allow verification errors
991   * (e.g. typically only UNLOCKED mode).
992   */
993  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING &&
994      !allow_verification_error) {
995    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
996    goto fail;
997  }
998
999  slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
1000  if (slot_data == NULL) {
1001    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1002    goto fail;
1003  }
1004  slot_data->vbmeta_images =
1005      avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
1006  if (slot_data->vbmeta_images == NULL) {
1007    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1008    goto fail;
1009  }
1010  slot_data->loaded_partitions =
1011      avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
1012  if (slot_data->loaded_partitions == NULL) {
1013    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1014    goto fail;
1015  }
1016
1017  ret = load_and_verify_vbmeta(ops,
1018                               requested_partitions,
1019                               ab_suffix,
1020                               allow_verification_error,
1021                               0 /* toplevel_vbmeta_flags */,
1022                               0 /* rollback_index_location */,
1023                               "vbmeta",
1024                               avb_strlen("vbmeta"),
1025                               NULL /* expected_public_key */,
1026                               0 /* expected_public_key_length */,
1027                               slot_data,
1028                               &algorithm_type);
1029  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
1030    goto fail;
1031  }
1032
1033  /* If things check out, mangle the kernel command-line as needed. */
1034  if (result_should_continue(ret)) {
1035    if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
1036      avb_assert(
1037          avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
1038      using_boot_for_vbmeta = true;
1039    }
1040
1041    /* Byteswap top-level vbmeta header since we'll need it below. */
1042    avb_vbmeta_image_header_to_host_byte_order(
1043        (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
1044        &toplevel_vbmeta);
1045
1046    /* Fill in |ab_suffix| field. */
1047    slot_data->ab_suffix = avb_strdup(ab_suffix);
1048    if (slot_data->ab_suffix == NULL) {
1049      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1050      goto fail;
1051    }
1052
1053    /* Add androidboot.vbmeta.device option. */
1054    if (!cmdline_append_option(slot_data,
1055                               "androidboot.vbmeta.device",
1056                               "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
1057      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1058      goto fail;
1059    }
1060
1061    /* Add androidboot.vbmeta.avb_version option. */
1062    if (!cmdline_append_version(slot_data,
1063                                "androidboot.vbmeta.avb_version",
1064                                AVB_VERSION_MAJOR,
1065                                AVB_VERSION_MINOR)) {
1066      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1067      goto fail;
1068    }
1069
1070    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
1071    if (slot_data->cmdline != NULL) {
1072      char* new_cmdline;
1073      new_cmdline = sub_cmdline(
1074          ops, slot_data->cmdline, ab_suffix, using_boot_for_vbmeta);
1075      if (new_cmdline == NULL) {
1076        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1077        goto fail;
1078      }
1079      avb_free(slot_data->cmdline);
1080      slot_data->cmdline = new_cmdline;
1081    }
1082
1083    /* Set androidboot.avb.device_state to "locked" or "unlocked". */
1084    bool is_device_unlocked;
1085    io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
1086    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
1087      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1088      goto fail;
1089    } else if (io_ret != AVB_IO_RESULT_OK) {
1090      avb_error("Error getting device state.\n");
1091      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
1092      goto fail;
1093    }
1094    if (!cmdline_append_option(slot_data,
1095                               "androidboot.vbmeta.device_state",
1096                               is_device_unlocked ? "unlocked" : "locked")) {
1097      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1098      goto fail;
1099    }
1100
1101    /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
1102     * function as is used to sign vbmeta.
1103     */
1104    switch (algorithm_type) {
1105      /* Explicit fallthrough. */
1106      case AVB_ALGORITHM_TYPE_NONE:
1107      case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
1108      case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
1109      case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
1110        AvbSHA256Ctx ctx;
1111        size_t n, total_size = 0;
1112        avb_sha256_init(&ctx);
1113        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
1114          avb_sha256_update(&ctx,
1115                            slot_data->vbmeta_images[n].vbmeta_data,
1116                            slot_data->vbmeta_images[n].vbmeta_size);
1117          total_size += slot_data->vbmeta_images[n].vbmeta_size;
1118        }
1119        if (!cmdline_append_option(
1120                slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
1121            !cmdline_append_uint64_base10(
1122                slot_data, "androidboot.vbmeta.size", total_size) ||
1123            !cmdline_append_hex(slot_data,
1124                                "androidboot.vbmeta.digest",
1125                                avb_sha256_final(&ctx),
1126                                AVB_SHA256_DIGEST_SIZE)) {
1127          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1128          goto fail;
1129        }
1130      } break;
1131      /* Explicit fallthrough. */
1132      case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
1133      case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
1134      case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
1135        AvbSHA512Ctx ctx;
1136        size_t n, total_size = 0;
1137        avb_sha512_init(&ctx);
1138        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
1139          avb_sha512_update(&ctx,
1140                            slot_data->vbmeta_images[n].vbmeta_data,
1141                            slot_data->vbmeta_images[n].vbmeta_size);
1142          total_size += slot_data->vbmeta_images[n].vbmeta_size;
1143        }
1144        if (!cmdline_append_option(
1145                slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
1146            !cmdline_append_uint64_base10(
1147                slot_data, "androidboot.vbmeta.size", total_size) ||
1148            !cmdline_append_hex(slot_data,
1149                                "androidboot.vbmeta.digest",
1150                                avb_sha512_final(&ctx),
1151                                AVB_SHA512_DIGEST_SIZE)) {
1152          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1153          goto fail;
1154        }
1155      } break;
1156      case _AVB_ALGORITHM_NUM_TYPES:
1157        avb_assert_not_reached();
1158        break;
1159    }
1160
1161    /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
1162    if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
1163      verity_mode = "disabled";
1164    } else {
1165      const char* dm_verity_mode;
1166      char* new_ret;
1167
1168      switch (hashtree_error_mode) {
1169        case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
1170          if (!cmdline_append_option(
1171                  slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
1172            ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1173            goto fail;
1174          }
1175          verity_mode = "enforcing";
1176          dm_verity_mode = "restart_on_corruption";
1177          break;
1178        case AVB_HASHTREE_ERROR_MODE_RESTART:
1179          verity_mode = "enforcing";
1180          dm_verity_mode = "restart_on_corruption";
1181          break;
1182        case AVB_HASHTREE_ERROR_MODE_EIO:
1183          verity_mode = "eio";
1184          /* For now there's no option to specify the EIO mode. So
1185           * just use 'ignore_zero_blocks' since that's already set
1186           * and dm-verity-target.c supports specifying this multiple
1187           * times.
1188           */
1189          dm_verity_mode = "ignore_zero_blocks";
1190          break;
1191        case AVB_HASHTREE_ERROR_MODE_LOGGING:
1192          verity_mode = "logging";
1193          dm_verity_mode = "ignore_corruption";
1194          break;
1195      }
1196      new_ret = avb_replace(
1197          slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
1198      avb_free(slot_data->cmdline);
1199      slot_data->cmdline = new_ret;
1200      if (slot_data->cmdline == NULL) {
1201        goto fail;
1202      }
1203    }
1204    if (!cmdline_append_option(
1205            slot_data, "androidboot.veritymode", verity_mode)) {
1206      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1207      goto fail;
1208    }
1209
1210    if (out_data != NULL) {
1211      *out_data = slot_data;
1212    } else {
1213      avb_slot_verify_data_free(slot_data);
1214    }
1215  }
1216
1217  if (!allow_verification_error) {
1218    avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
1219  }
1220
1221  return ret;
1222
1223fail:
1224  if (slot_data != NULL) {
1225    avb_slot_verify_data_free(slot_data);
1226  }
1227  return ret;
1228}
1229
1230void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
1231  if (data->ab_suffix != NULL) {
1232    avb_free(data->ab_suffix);
1233  }
1234  if (data->cmdline != NULL) {
1235    avb_free(data->cmdline);
1236  }
1237  if (data->vbmeta_images != NULL) {
1238    size_t n;
1239    for (n = 0; n < data->num_vbmeta_images; n++) {
1240      AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
1241      if (vbmeta_image->partition_name != NULL) {
1242        avb_free(vbmeta_image->partition_name);
1243      }
1244      if (vbmeta_image->vbmeta_data != NULL) {
1245        avb_free(vbmeta_image->vbmeta_data);
1246      }
1247    }
1248    avb_free(data->vbmeta_images);
1249  }
1250  if (data->loaded_partitions != NULL) {
1251    size_t n;
1252    for (n = 0; n < data->num_loaded_partitions; n++) {
1253      AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
1254      if (loaded_partition->partition_name != NULL) {
1255        avb_free(loaded_partition->partition_name);
1256      }
1257      if (loaded_partition->data != NULL) {
1258        avb_free(loaded_partition->data);
1259      }
1260    }
1261    avb_free(data->loaded_partitions);
1262  }
1263  avb_free(data);
1264}
1265
1266const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
1267  const char* ret = NULL;
1268
1269  switch (result) {
1270    case AVB_SLOT_VERIFY_RESULT_OK:
1271      ret = "OK";
1272      break;
1273    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
1274      ret = "ERROR_OOM";
1275      break;
1276    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
1277      ret = "ERROR_IO";
1278      break;
1279    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
1280      ret = "ERROR_VERIFICATION";
1281      break;
1282    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
1283      ret = "ERROR_ROLLBACK_INDEX";
1284      break;
1285    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
1286      ret = "ERROR_PUBLIC_KEY_REJECTED";
1287      break;
1288    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
1289      ret = "ERROR_INVALID_METADATA";
1290      break;
1291    case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
1292      ret = "ERROR_UNSUPPORTED_VERSION";
1293      break;
1294    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
1295      ret = "ERROR_INVALID_ARGUMENT";
1296      break;
1297      /* Do not add a 'default:' case here because of -Wswitch. */
1298  }
1299
1300  if (ret == NULL) {
1301    avb_error("Unknown AvbSlotVerifyResult value.\n");
1302    ret = "(unknown)";
1303  }
1304
1305  return ret;
1306}
1307