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