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