avb_slot_verify.c revision 4b6a634e48353da1e119ebe0287299f7b919d778
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
34/* Maximum allow length (in bytes) of a partition name, including
35 * ab_suffix.
36 */
37#define PART_NAME_MAX_SIZE 32
38
39/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
40#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
41
42/* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */
43#define MAX_NUMBER_OF_VBMETA_IMAGES 32
44
45/* Maximum size of a vbmeta image - 64 KiB. */
46#define VBMETA_MAX_SIZE (64 * 1024)
47
48/* Helper function to see if we should continue with verification in
49 * allow_verification_error=true mode if something goes wrong. See the
50 * comments for the avb_slot_verify() function for more information.
51 */
52static inline bool result_should_continue(AvbSlotVerifyResult result) {
53  switch (result) {
54    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
55    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
56    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
57      return false;
58
59    case AVB_SLOT_VERIFY_RESULT_OK:
60    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
61    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
62    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
63      return true;
64  }
65
66  return false;
67}
68
69static AvbSlotVerifyResult load_and_verify_hash_partition(
70    AvbOps* ops,
71    const char* const* requested_partitions,
72    const char* ab_suffix,
73    bool allow_verification_error,
74    const AvbDescriptor* descriptor,
75    AvbSlotVerifyData* slot_data) {
76  AvbHashDescriptor hash_desc;
77  const uint8_t* desc_partition_name = NULL;
78  const uint8_t* desc_salt;
79  const uint8_t* desc_digest;
80  char part_name[PART_NAME_MAX_SIZE];
81  AvbSlotVerifyResult ret;
82  AvbIOResult io_ret;
83  uint8_t* image_buf = NULL;
84  size_t part_num_read;
85  uint8_t* digest;
86  size_t digest_len;
87  const char* found;
88
89  if (!avb_hash_descriptor_validate_and_byteswap(
90          (const AvbHashDescriptor*)descriptor, &hash_desc)) {
91    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
92    goto out;
93  }
94
95  desc_partition_name =
96      ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
97  desc_salt = desc_partition_name + hash_desc.partition_name_len;
98  desc_digest = desc_salt + hash_desc.salt_len;
99
100  if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
101    avb_error("Partition name is not valid UTF-8.\n");
102    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
103    goto out;
104  }
105
106  if (!avb_str_concat(part_name,
107                      sizeof part_name,
108                      (const char*)desc_partition_name,
109                      hash_desc.partition_name_len,
110                      ab_suffix,
111                      avb_strlen(ab_suffix))) {
112    avb_error("Partition name and suffix does not fit.\n");
113    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
114    goto out;
115  }
116
117  image_buf = avb_malloc(hash_desc.image_size);
118  if (image_buf == NULL) {
119    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
120    goto out;
121  }
122
123  io_ret = ops->read_from_partition(ops,
124                                    part_name,
125                                    0 /* offset */,
126                                    hash_desc.image_size,
127                                    image_buf,
128                                    &part_num_read);
129  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
130    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
131    goto out;
132  } else if (io_ret != AVB_IO_RESULT_OK) {
133    avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
134    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
135    goto out;
136  }
137  if (part_num_read != hash_desc.image_size) {
138    avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
139    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
140    goto out;
141  }
142
143  if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
144    AvbSHA256Ctx sha256_ctx;
145    avb_sha256_init(&sha256_ctx);
146    avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
147    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
148    digest = avb_sha256_final(&sha256_ctx);
149    digest_len = AVB_SHA256_DIGEST_SIZE;
150  } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
151    AvbSHA512Ctx sha512_ctx;
152    avb_sha512_init(&sha512_ctx);
153    avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
154    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
155    digest = avb_sha512_final(&sha512_ctx);
156    digest_len = AVB_SHA512_DIGEST_SIZE;
157  } else {
158    avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
159    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
160    goto out;
161  }
162
163  if (digest_len != hash_desc.digest_len) {
164    avb_errorv(
165        part_name, ": Digest in descriptor not of expected size.\n", NULL);
166    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
167    goto out;
168  }
169
170  if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) {
171    avb_errorv(part_name,
172               ": Hash of data does not match digest in descriptor.\n",
173               NULL);
174    ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
175    goto out;
176  }
177
178  ret = AVB_SLOT_VERIFY_RESULT_OK;
179
180out:
181
182  if (ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) {
183    /* If this is the requested partition, copy to slot_data. */
184    found = avb_strv_find_str(requested_partitions,
185                              (const char*)desc_partition_name,
186                              hash_desc.partition_name_len);
187    if (found != NULL) {
188      AvbPartitionData* loaded_partition;
189      if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
190        avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
191        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
192        goto fail;
193      }
194      loaded_partition =
195          &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
196      loaded_partition->partition_name = avb_strdup(found);
197      loaded_partition->data_size = hash_desc.image_size;
198      loaded_partition->data = image_buf;
199      image_buf = NULL;
200    }
201  }
202
203fail:
204  if (image_buf != NULL) {
205    avb_free(image_buf);
206  }
207  return ret;
208}
209
210static AvbSlotVerifyResult load_and_verify_vbmeta(
211    AvbOps* ops,
212    const char* const* requested_partitions,
213    const char* ab_suffix,
214    bool allow_verification_error,
215    AvbVBMetaImageFlags toplevel_vbmeta_flags,
216    int rollback_index_location,
217    const char* partition_name,
218    size_t partition_name_len,
219    const uint8_t* expected_public_key,
220    size_t expected_public_key_length,
221    AvbSlotVerifyData* slot_data,
222    AvbAlgorithmType* out_algorithm_type) {
223  char full_partition_name[PART_NAME_MAX_SIZE];
224  AvbSlotVerifyResult ret;
225  AvbIOResult io_ret;
226  size_t vbmeta_offset;
227  size_t vbmeta_size;
228  uint8_t* vbmeta_buf = NULL;
229  size_t vbmeta_num_read;
230  AvbVBMetaVerifyResult vbmeta_ret;
231  const uint8_t* pk_data;
232  size_t pk_len;
233  AvbVBMetaImageHeader vbmeta_header;
234  uint64_t stored_rollback_index;
235  const AvbDescriptor** descriptors = NULL;
236  size_t num_descriptors;
237  size_t n;
238  int is_main_vbmeta;
239  AvbVBMetaData* vbmeta_image_data = NULL;
240
241  ret = AVB_SLOT_VERIFY_RESULT_OK;
242
243  avb_assert(slot_data != NULL);
244
245  is_main_vbmeta = (avb_strcmp(partition_name, "vbmeta") == 0);
246
247  if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
248    avb_error("Partition name is not valid UTF-8.\n");
249    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
250    goto out;
251  }
252
253  /* Construct full partition name. */
254  if (!avb_str_concat(full_partition_name,
255                      sizeof full_partition_name,
256                      partition_name,
257                      partition_name_len,
258                      ab_suffix,
259                      avb_strlen(ab_suffix))) {
260    avb_error("Partition name and suffix does not fit.\n");
261    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
262    goto out;
263  }
264
265  avb_debugv("Loading vbmeta struct from partition '",
266             full_partition_name,
267             "'.\n",
268             NULL);
269
270  /* If we're loading from the main vbmeta partition, the vbmeta
271   * struct is in the beginning. Otherwise we have to locate it via a
272   * footer.
273   */
274  if (is_main_vbmeta) {
275    vbmeta_offset = 0;
276    vbmeta_size = VBMETA_MAX_SIZE;
277  } else {
278    uint8_t footer_buf[AVB_FOOTER_SIZE];
279    size_t footer_num_read;
280    AvbFooter footer;
281
282    io_ret = ops->read_from_partition(ops,
283                                      full_partition_name,
284                                      -AVB_FOOTER_SIZE,
285                                      AVB_FOOTER_SIZE,
286                                      footer_buf,
287                                      &footer_num_read);
288    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
289      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
290      goto out;
291    } else if (io_ret != AVB_IO_RESULT_OK) {
292      avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
293      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
294      goto out;
295    }
296    avb_assert(footer_num_read == AVB_FOOTER_SIZE);
297
298    if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
299                                          &footer)) {
300      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
301      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
302      goto out;
303    }
304
305    /* Basic footer sanity check since the data is untrusted. */
306    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
307      avb_errorv(
308          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
309      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
310      goto out;
311    }
312
313    vbmeta_offset = footer.vbmeta_offset;
314    vbmeta_size = footer.vbmeta_size;
315  }
316
317  vbmeta_buf = avb_malloc(vbmeta_size);
318  if (vbmeta_buf == NULL) {
319    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
320    goto out;
321  }
322
323  io_ret = ops->read_from_partition(ops,
324                                    full_partition_name,
325                                    vbmeta_offset,
326                                    vbmeta_size,
327                                    vbmeta_buf,
328                                    &vbmeta_num_read);
329  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
330    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
331    goto out;
332  } else if (io_ret != AVB_IO_RESULT_OK) {
333    avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
334    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
335    goto out;
336  }
337  avb_assert(vbmeta_num_read <= vbmeta_size);
338
339  /* Check if the image is properly signed and get the public key used
340   * to sign the image.
341   */
342  vbmeta_ret =
343      avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
344  switch (vbmeta_ret) {
345    case AVB_VBMETA_VERIFY_RESULT_OK:
346      avb_assert(pk_data != NULL && pk_len > 0);
347      break;
348
349    case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
350    case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
351    case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
352      ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
353      avb_errorv(full_partition_name,
354                 ": Error verifying vbmeta image: ",
355                 avb_vbmeta_verify_result_to_string(vbmeta_ret),
356                 "\n",
357                 NULL);
358      if (!allow_verification_error) {
359        goto out;
360      }
361      break;
362
363    case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
364      /* No way to continue this case. */
365      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
366      avb_errorv(full_partition_name,
367                 ": Error verifying vbmeta image: invalid vbmeta header\n",
368                 NULL);
369      goto out;
370  }
371
372  /* Byteswap the header. */
373  avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
374                                             &vbmeta_header);
375
376  /* If we're the toplevel, assign flags so they'll be passed down. */
377  if (is_main_vbmeta) {
378    toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags;
379  } else {
380    if (vbmeta_header.flags != 0) {
381      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
382      avb_errorv(full_partition_name,
383                 ": chained vbmeta image has non-zero flags\n",
384                 NULL);
385      goto out;
386    }
387  }
388
389  /* Check if key used to make signature matches what is expected. */
390  if (pk_data != NULL) {
391    if (expected_public_key != NULL) {
392      avb_assert(!is_main_vbmeta);
393      if (expected_public_key_length != pk_len ||
394          avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
395        avb_errorv(full_partition_name,
396                   ": Public key used to sign data does not match key in chain "
397                   "partition descriptor.\n",
398                   NULL);
399        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
400        if (!allow_verification_error) {
401          goto out;
402        }
403      }
404    } else {
405      bool key_is_trusted = false;
406      const uint8_t* pk_metadata = NULL;
407      size_t pk_metadata_len = 0;
408
409      if (vbmeta_header.public_key_metadata_size > 0) {
410        pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) +
411                      vbmeta_header.authentication_data_block_size +
412                      vbmeta_header.public_key_metadata_offset;
413        pk_metadata_len = vbmeta_header.public_key_metadata_size;
414      }
415
416      avb_assert(is_main_vbmeta);
417      io_ret = ops->validate_vbmeta_public_key(
418          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
419      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
420        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
421        goto out;
422      } else if (io_ret != AVB_IO_RESULT_OK) {
423        avb_errorv(full_partition_name,
424                   ": Error while checking public key used to sign data.\n",
425                   NULL);
426        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
427        goto out;
428      }
429      if (!key_is_trusted) {
430        avb_errorv(full_partition_name,
431                   ": Public key used to sign data rejected.\n",
432                   NULL);
433        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
434        if (!allow_verification_error) {
435          goto out;
436        }
437      }
438    }
439  }
440
441  /* Check rollback index. */
442  io_ret = ops->read_rollback_index(
443      ops, rollback_index_location, &stored_rollback_index);
444  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
445    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
446    goto out;
447  } else if (io_ret != AVB_IO_RESULT_OK) {
448    avb_errorv(full_partition_name,
449               ": Error getting rollback index for location.\n",
450               NULL);
451    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
452    goto out;
453  }
454  if (vbmeta_header.rollback_index < stored_rollback_index) {
455    avb_errorv(
456        full_partition_name,
457        ": Image rollback index is less than the stored rollback index.\n",
458        NULL);
459    ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
460    if (!allow_verification_error) {
461      goto out;
462    }
463  }
464
465  /* Copy vbmeta to vbmeta_images before recursing. */
466  if (is_main_vbmeta) {
467    avb_assert(slot_data->num_vbmeta_images == 0);
468  } else {
469    avb_assert(slot_data->num_vbmeta_images > 0);
470  }
471  if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
472    avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
473    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
474    goto out;
475  }
476  vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++];
477  vbmeta_image_data->partition_name = avb_strdup(partition_name);
478  vbmeta_image_data->vbmeta_data = vbmeta_buf;
479  /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
480   * and this includes data past the end of the image. Pass the
481   * actual size of the vbmeta image. Also, no need to use
482   * avb_safe_add() since the header has already been verified.
483   */
484  vbmeta_image_data->vbmeta_size =
485      sizeof(AvbVBMetaImageHeader) +
486      vbmeta_header.authentication_data_block_size +
487      vbmeta_header.auxiliary_data_block_size;
488  vbmeta_image_data->verify_result = vbmeta_ret;
489
490  /* Now go through all descriptors and take the appropriate action:
491   *
492   * - hash descriptor: Load data from partition, calculate hash, and
493   *   checks that it matches what's in the hash descriptor.
494   *
495   * - hashtree descriptor: Do nothing since verification happens
496   *   on-the-fly from within the OS.
497   *
498   * - chained partition descriptor: Load the footer, load the vbmeta
499   *   image, verify vbmeta image (includes rollback checks, hash
500   *   checks, bail on chained partitions).
501   */
502  descriptors =
503      avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
504  for (n = 0; n < num_descriptors; n++) {
505    AvbDescriptor desc;
506
507    if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
508      avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
509      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
510      goto out;
511    }
512
513    switch (desc.tag) {
514      case AVB_DESCRIPTOR_TAG_HASH: {
515        AvbSlotVerifyResult sub_ret;
516        sub_ret = load_and_verify_hash_partition(ops,
517                                                 requested_partitions,
518                                                 ab_suffix,
519                                                 allow_verification_error,
520                                                 descriptors[n],
521                                                 slot_data);
522        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
523          ret = sub_ret;
524          if (!allow_verification_error || !result_should_continue(ret)) {
525            goto out;
526          }
527        }
528      } break;
529
530      case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
531        AvbSlotVerifyResult sub_ret;
532        AvbChainPartitionDescriptor chain_desc;
533        const uint8_t* chain_partition_name;
534        const uint8_t* chain_public_key;
535
536        /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
537        if (!is_main_vbmeta) {
538          avb_errorv(full_partition_name,
539                     ": Encountered chain descriptor not in main image.\n",
540                     NULL);
541          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
542          goto out;
543        }
544
545        if (!avb_chain_partition_descriptor_validate_and_byteswap(
546                (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
547          avb_errorv(full_partition_name,
548                     ": Chain partition descriptor is invalid.\n",
549                     NULL);
550          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
551          goto out;
552        }
553
554        chain_partition_name = ((const uint8_t*)descriptors[n]) +
555                               sizeof(AvbChainPartitionDescriptor);
556        chain_public_key = chain_partition_name + chain_desc.partition_name_len;
557
558        sub_ret = load_and_verify_vbmeta(ops,
559                                         requested_partitions,
560                                         ab_suffix,
561                                         allow_verification_error,
562                                         toplevel_vbmeta_flags,
563                                         chain_desc.rollback_index_location,
564                                         (const char*)chain_partition_name,
565                                         chain_desc.partition_name_len,
566                                         chain_public_key,
567                                         chain_desc.public_key_len,
568                                         slot_data,
569                                         NULL /* out_algorithm_type */);
570        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
571          ret = sub_ret;
572          if (!result_should_continue(ret)) {
573            goto out;
574          }
575        }
576      } break;
577
578      case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
579        const uint8_t* kernel_cmdline;
580        AvbKernelCmdlineDescriptor kernel_cmdline_desc;
581        bool apply_cmdline;
582
583        if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
584                (AvbKernelCmdlineDescriptor*)descriptors[n],
585                &kernel_cmdline_desc)) {
586          avb_errorv(full_partition_name,
587                     ": Kernel cmdline descriptor is invalid.\n",
588                     NULL);
589          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
590          goto out;
591        }
592
593        kernel_cmdline = ((const uint8_t*)descriptors[n]) +
594                         sizeof(AvbKernelCmdlineDescriptor);
595
596        if (!avb_validate_utf8(kernel_cmdline,
597                               kernel_cmdline_desc.kernel_cmdline_length)) {
598          avb_errorv(full_partition_name,
599                     ": Kernel cmdline is not valid UTF-8.\n",
600                     NULL);
601          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
602          goto out;
603        }
604
605        /* Compare the flags for top-level VBMeta struct with flags in
606         * the command-line descriptor so command-line snippets only
607         * intended for a certain mode (dm-verity enabled/disabled)
608         * are skipped if applicable.
609         */
610        apply_cmdline = true;
611        if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
612          if (kernel_cmdline_desc.flags &
613              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
614            apply_cmdline = false;
615          }
616        } else {
617          if (kernel_cmdline_desc.flags &
618              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
619            apply_cmdline = false;
620          }
621        }
622
623        if (apply_cmdline) {
624          if (slot_data->cmdline == NULL) {
625            slot_data->cmdline =
626                avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
627            if (slot_data->cmdline == NULL) {
628              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
629              goto out;
630            }
631            avb_memcpy(slot_data->cmdline,
632                       kernel_cmdline,
633                       kernel_cmdline_desc.kernel_cmdline_length);
634          } else {
635            /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
636            size_t orig_size = avb_strlen(slot_data->cmdline);
637            size_t new_size =
638                orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
639            char* new_cmdline = avb_calloc(new_size);
640            if (new_cmdline == NULL) {
641              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
642              goto out;
643            }
644            avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
645            new_cmdline[orig_size] = ' ';
646            avb_memcpy(new_cmdline + orig_size + 1,
647                       kernel_cmdline,
648                       kernel_cmdline_desc.kernel_cmdline_length);
649            avb_free(slot_data->cmdline);
650            slot_data->cmdline = new_cmdline;
651          }
652        }
653      } break;
654
655      /* Explicit fall-through */
656      case AVB_DESCRIPTOR_TAG_PROPERTY:
657      case AVB_DESCRIPTOR_TAG_HASHTREE:
658        /* Do nothing. */
659        break;
660    }
661  }
662
663  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
664    avb_errorv(
665        full_partition_name, ": Invalid rollback_index_location.\n", NULL);
666    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
667    goto out;
668  }
669
670  slot_data->rollback_indexes[rollback_index_location] =
671      vbmeta_header.rollback_index;
672
673  if (out_algorithm_type != NULL) {
674    *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
675  }
676
677out:
678  /* If |vbmeta_image_data| isn't NULL it means that it adopted
679   * |vbmeta_buf| so in that case don't free it here.
680   */
681  if (vbmeta_image_data == NULL) {
682    if (vbmeta_buf != NULL) {
683      avb_free(vbmeta_buf);
684    }
685  }
686  if (descriptors != NULL) {
687    avb_free(descriptors);
688  }
689  return ret;
690}
691
692#define NUM_GUIDS 3
693
694/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
695 * values. Returns NULL on OOM, otherwise the cmdline with values
696 * replaced.
697 */
698static char* sub_cmdline(AvbOps* ops,
699                         const char* cmdline,
700                         const char* ab_suffix) {
701  const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
702  const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
703                                        "$(ANDROID_BOOT_PARTUUID)",
704                                        "$(ANDROID_VBMETA_PARTUUID)"};
705  char* ret = NULL;
706  AvbIOResult io_ret;
707
708  /* Replace unique partition GUIDs */
709  for (size_t n = 0; n < NUM_GUIDS; n++) {
710    char part_name[PART_NAME_MAX_SIZE];
711    char guid_buf[37];
712    char* new_ret;
713
714    if (!avb_str_concat(part_name,
715                        sizeof part_name,
716                        part_name_str[n],
717                        avb_strlen(part_name_str[n]),
718                        ab_suffix,
719                        avb_strlen(ab_suffix))) {
720      avb_error("Partition name and suffix does not fit.\n");
721      goto fail;
722    }
723
724    io_ret = ops->get_unique_guid_for_partition(
725        ops, part_name, guid_buf, sizeof guid_buf);
726    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
727      return NULL;
728    } else if (io_ret != AVB_IO_RESULT_OK) {
729      avb_error("Error getting unique GUID for partition.\n");
730      goto fail;
731    }
732
733    if (ret == NULL) {
734      new_ret = avb_replace(cmdline, replace_str[n], guid_buf);
735    } else {
736      new_ret = avb_replace(ret, replace_str[n], guid_buf);
737    }
738    if (new_ret == NULL) {
739      goto fail;
740    }
741    ret = new_ret;
742  }
743
744  return ret;
745
746fail:
747  if (ret != NULL) {
748    avb_free(ret);
749  }
750  return NULL;
751}
752
753static int cmdline_append_option(AvbSlotVerifyData* slot_data,
754                                 const char* key,
755                                 const char* value) {
756  size_t offset, key_len, value_len;
757  char* new_cmdline;
758
759  key_len = avb_strlen(key);
760  value_len = avb_strlen(value);
761
762  offset = 0;
763  if (slot_data->cmdline != NULL) {
764    offset = avb_strlen(slot_data->cmdline);
765    if (offset > 0) {
766      offset += 1;
767    }
768  }
769
770  new_cmdline = avb_calloc(offset + key_len + value_len + 2);
771  if (new_cmdline == NULL) {
772    return 0;
773  }
774  if (offset > 0) {
775    avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
776    new_cmdline[offset - 1] = ' ';
777  }
778  avb_memcpy(new_cmdline + offset, key, key_len);
779  new_cmdline[offset + key_len] = '=';
780  avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
781  if (slot_data->cmdline != NULL) {
782    avb_free(slot_data->cmdline);
783  }
784  slot_data->cmdline = new_cmdline;
785
786  return 1;
787}
788
789static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
790                                        const char* key,
791                                        uint64_t value) {
792  const int MAX_DIGITS = 32;
793  char rev_digits[MAX_DIGITS];
794  char digits[MAX_DIGITS];
795  size_t n, num_digits;
796
797  for (num_digits = 0; num_digits < MAX_DIGITS - 1;) {
798    rev_digits[num_digits++] = (value % 10) + '0';
799    value /= 10;
800    if (value == 0) {
801      break;
802    }
803  }
804
805  for (n = 0; n < num_digits; n++) {
806    digits[n] = rev_digits[num_digits - 1 - n];
807  }
808  digits[n] = '\0';
809
810  return cmdline_append_option(slot_data, key, digits);
811}
812
813static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
814                              const char* key,
815                              const uint8_t* data,
816                              size_t data_len) {
817  char hex_digits[17] = "0123456789abcdef";
818  char* hex_data;
819  int ret;
820  size_t n;
821
822  hex_data = avb_malloc(data_len * 2 + 1);
823  if (hex_data == NULL) {
824    return 0;
825  }
826
827  for (n = 0; n < data_len; n++) {
828    hex_data[n * 2] = hex_digits[data[n] >> 4];
829    hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
830  }
831  hex_data[n * 2] = '\0';
832
833  ret = cmdline_append_option(slot_data, key, hex_data);
834  avb_free(hex_data);
835  return ret;
836}
837
838AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
839                                    const char* const* requested_partitions,
840                                    const char* ab_suffix,
841                                    bool allow_verification_error,
842                                    AvbSlotVerifyData** out_data) {
843  AvbSlotVerifyResult ret;
844  AvbSlotVerifyData* slot_data = NULL;
845  AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
846  AvbIOResult io_ret;
847
848  if (out_data != NULL) {
849    *out_data = NULL;
850  }
851
852  slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
853  if (slot_data == NULL) {
854    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
855    goto fail;
856  }
857  slot_data->vbmeta_images =
858      avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
859  if (slot_data->vbmeta_images == NULL) {
860    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
861    goto fail;
862  }
863  slot_data->loaded_partitions =
864      avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
865  if (slot_data->loaded_partitions == NULL) {
866    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
867    goto fail;
868  }
869
870  ret = load_and_verify_vbmeta(ops,
871                               requested_partitions,
872                               ab_suffix,
873                               allow_verification_error,
874                               0, /* toplevel_vbmeta_flags */
875                               0 /* rollback_index_location */,
876                               "vbmeta",
877                               avb_strlen("vbmeta"),
878                               NULL /* expected_public_key */,
879                               0 /* expected_public_key_length */,
880                               slot_data,
881                               &algorithm_type);
882  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
883    goto fail;
884  }
885
886  /* If things check out, mangle the kernel command-line as needed. */
887  if (result_should_continue(ret)) {
888    /* Fill in |ab_suffix| field. */
889    slot_data->ab_suffix = avb_strdup(ab_suffix);
890    if (slot_data->ab_suffix == NULL) {
891      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
892      goto fail;
893    }
894
895    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
896    if (slot_data->cmdline != NULL) {
897      char* new_cmdline = sub_cmdline(ops, slot_data->cmdline, ab_suffix);
898      if (new_cmdline == NULL) {
899        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
900        goto fail;
901      }
902      avb_free(slot_data->cmdline);
903      slot_data->cmdline = new_cmdline;
904    }
905
906    /* Add androidboot.slot_suffix, if applicable. */
907    if (avb_strlen(ab_suffix) > 0) {
908      if (!cmdline_append_option(
909              slot_data, "androidboot.slot_suffix", ab_suffix)) {
910        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
911        goto fail;
912      }
913    }
914
915    /* Set androidboot.avb.device_state to "locked" or "unlocked". */
916    bool is_device_unlocked;
917    io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
918    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
919      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
920      goto fail;
921    } else if (io_ret != AVB_IO_RESULT_OK) {
922      avb_error("Error getting device state.\n");
923      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
924      goto fail;
925    }
926    if (!cmdline_append_option(slot_data,
927                               "androidboot.vbmeta.device_state",
928                               is_device_unlocked ? "unlocked" : "locked")) {
929      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
930      goto fail;
931    }
932
933    /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
934     * function as is used to sign vbmeta.
935     */
936    switch (algorithm_type) {
937      /* Explicit fallthrough. */
938      case AVB_ALGORITHM_TYPE_NONE:
939      case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
940      case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
941      case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
942        AvbSHA256Ctx ctx;
943        size_t n, total_size = 0;
944        avb_sha256_init(&ctx);
945        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
946          avb_sha256_update(&ctx,
947                            slot_data->vbmeta_images[n].vbmeta_data,
948                            slot_data->vbmeta_images[n].vbmeta_size);
949          total_size += slot_data->vbmeta_images[n].vbmeta_size;
950        }
951        if (!cmdline_append_option(
952                slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
953            !cmdline_append_uint64_base10(
954                slot_data, "androidboot.vbmeta.size", total_size) ||
955            !cmdline_append_hex(slot_data,
956                                "androidboot.vbmeta.digest",
957                                avb_sha256_final(&ctx),
958                                AVB_SHA256_DIGEST_SIZE)) {
959          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
960          goto fail;
961        }
962      } break;
963      /* Explicit fallthrough. */
964      case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
965      case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
966      case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
967        AvbSHA512Ctx ctx;
968        size_t n, total_size = 0;
969        ;
970        avb_sha512_init(&ctx);
971        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
972          avb_sha512_update(&ctx,
973                            slot_data->vbmeta_images[n].vbmeta_data,
974                            slot_data->vbmeta_images[n].vbmeta_size);
975          total_size += slot_data->vbmeta_images[n].vbmeta_size;
976        }
977        if (!cmdline_append_option(
978                slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
979            !cmdline_append_uint64_base10(
980                slot_data, "androidboot.vbmeta.size", total_size) ||
981            !cmdline_append_hex(slot_data,
982                                "androidboot.vbmeta.digest",
983                                avb_sha512_final(&ctx),
984                                AVB_SHA512_DIGEST_SIZE)) {
985          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
986          goto fail;
987        }
988      } break;
989      case _AVB_ALGORITHM_NUM_TYPES:
990        avb_assert_not_reached();
991        break;
992    }
993
994    if (out_data != NULL) {
995      *out_data = slot_data;
996    } else {
997      avb_slot_verify_data_free(slot_data);
998    }
999  }
1000
1001  if (!allow_verification_error) {
1002    avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
1003  }
1004
1005  return ret;
1006
1007fail:
1008  if (slot_data != NULL) {
1009    avb_slot_verify_data_free(slot_data);
1010  }
1011  return ret;
1012}
1013
1014void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
1015  if (data->ab_suffix != NULL) {
1016    avb_free(data->ab_suffix);
1017  }
1018  if (data->cmdline != NULL) {
1019    avb_free(data->cmdline);
1020  }
1021  if (data->vbmeta_images != NULL) {
1022    size_t n;
1023    for (n = 0; n < data->num_vbmeta_images; n++) {
1024      AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
1025      if (vbmeta_image->partition_name != NULL) {
1026        avb_free(vbmeta_image->partition_name);
1027      }
1028      if (vbmeta_image->vbmeta_data != NULL) {
1029        avb_free(vbmeta_image->vbmeta_data);
1030      }
1031    }
1032    avb_free(data->vbmeta_images);
1033  }
1034  if (data->loaded_partitions != NULL) {
1035    size_t n;
1036    for (n = 0; n < data->num_loaded_partitions; n++) {
1037      AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
1038      if (loaded_partition->partition_name != NULL) {
1039        avb_free(loaded_partition->partition_name);
1040      }
1041      if (loaded_partition->data != NULL) {
1042        avb_free(loaded_partition->data);
1043      }
1044    }
1045    avb_free(data->loaded_partitions);
1046  }
1047  avb_free(data);
1048}
1049
1050const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
1051  const char* ret = NULL;
1052
1053  switch (result) {
1054    case AVB_SLOT_VERIFY_RESULT_OK:
1055      ret = "OK";
1056      break;
1057    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
1058      ret = "ERROR_OOM";
1059      break;
1060    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
1061      ret = "ERROR_IO";
1062      break;
1063    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
1064      ret = "ERROR_VERIFICATION";
1065      break;
1066    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
1067      ret = "ERROR_ROLLBACK_INDEX";
1068      break;
1069    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
1070      ret = "ERROR_PUBLIC_KEY_REJECTED";
1071      break;
1072    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
1073      ret = "ERROR_INVALID_METADATA";
1074      break;
1075      /* Do not add a 'default:' case here because of -Wswitch. */
1076  }
1077
1078  if (ret == NULL) {
1079    avb_error("Unknown AvbSlotVerifyResult value.\n");
1080    ret = "(unknown)";
1081  }
1082
1083  return ret;
1084}
1085