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