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