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