blob: 5d4910f9e7da6cdc5bde681824ca422d89228092 [file] [log] [blame]
David Zeuthen21e95262016-07-27 17:58:40 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
David Zeuthenc612e2e2016-09-16 16:44:08 -04004 * 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:
David Zeuthen21e95262016-07-27 17:58:40 -040011 *
David Zeuthenc612e2e2016-09-16 16:44:08 -040012 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
David Zeuthen21e95262016-07-27 17:58:40 -040014 *
David Zeuthenc612e2e2016-09-16 16:44:08 -040015 * 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.
David Zeuthen21e95262016-07-27 17:58:40 -040023 */
24
25#include "avb_slot_verify.h"
26#include "avb_chain_partition_descriptor.h"
27#include "avb_footer.h"
28#include "avb_hash_descriptor.h"
29#include "avb_kernel_cmdline_descriptor.h"
30#include "avb_sha.h"
31#include "avb_util.h"
32#include "avb_vbmeta_image.h"
33
34/* Maximum allow length (in bytes) of a partition name, including
35 * ab_suffix.
36 */
37#define PART_NAME_MAX_SIZE 32
38
39/* Maximum size of a vbmeta image - 64 KiB. */
40#define VBMETA_MAX_SIZE (64 * 1024)
41
42static AvbSlotVerifyResult load_and_verify_hash_partition(
43 AvbOps* ops, const char* ab_suffix, const AvbDescriptor* descriptor,
44 AvbSlotVerifyData* slot_data) {
45 AvbHashDescriptor hash_desc;
46 const uint8_t* desc_partition_name;
47 const uint8_t* desc_salt;
48 const uint8_t* desc_digest;
49 char part_name[PART_NAME_MAX_SIZE];
50 AvbSlotVerifyResult ret;
51 AvbIOResult io_ret;
52 uint8_t* image_buf = NULL;
53 size_t part_num_read;
54 uint8_t* digest;
55 size_t digest_len;
56
57 if (!avb_hash_descriptor_validate_and_byteswap(
58 (const AvbHashDescriptor*)descriptor, &hash_desc)) {
59 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
60 goto out;
61 }
62
63 desc_partition_name =
64 ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
65 desc_salt = desc_partition_name + hash_desc.partition_name_len;
66 desc_digest = desc_salt + hash_desc.salt_len;
67
68 if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
69 avb_error("Partition name is not valid UTF-8.\n");
70 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
71 goto out;
72 }
73
74 if (!avb_str_concat(
75 part_name, sizeof part_name, (const char*)desc_partition_name,
76 hash_desc.partition_name_len, ab_suffix, avb_strlen(ab_suffix))) {
77 avb_error("Partition name and suffix does not fit.\n");
78 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
79 goto out;
80 }
81
82 image_buf = avb_malloc(hash_desc.image_size);
83 if (image_buf == NULL) {
84 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
85 goto out;
86 }
87
88 io_ret =
89 ops->read_from_partition(ops, part_name, 0 /* offset */,
90 hash_desc.image_size, image_buf, &part_num_read);
91 if (io_ret != AVB_IO_RESULT_OK) {
92 avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
93 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
94 goto out;
95 }
96 if (part_num_read != hash_desc.image_size) {
97 avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
98 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
99 goto out;
100 }
101
102 if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
103 AvbSHA256Ctx sha256_ctx;
104 avb_sha256_init(&sha256_ctx);
105 avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
106 avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
107 digest = avb_sha256_final(&sha256_ctx);
108 digest_len = AVB_SHA256_DIGEST_SIZE;
109 } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
110 AvbSHA512Ctx sha512_ctx;
111 avb_sha512_init(&sha512_ctx);
112 avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
113 avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
114 digest = avb_sha512_final(&sha512_ctx);
115 digest_len = AVB_SHA512_DIGEST_SIZE;
116 } else {
117 avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
118 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
119 goto out;
120 }
121
122 if (digest_len != hash_desc.digest_len) {
123 avb_errorv(part_name, ": Digest in descriptor not of expected size.\n",
124 NULL);
125 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
126 goto out;
127 }
128
129 if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) {
130 avb_errorv(part_name,
131 ": Hash of data does not match digest in descriptor.\n", NULL);
132 ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
133 goto out;
134 }
135
136 ret = AVB_SLOT_VERIFY_RESULT_OK;
137
138 /* If this is the boot partition, copy to slot_data. */
139 if (hash_desc.partition_name_len == 4 &&
140 avb_memcmp(desc_partition_name, "boot", 4) == 0) {
141 if (slot_data->boot_data != NULL) {
142 avb_free(slot_data->boot_data);
143 }
144 slot_data->boot_size = hash_desc.image_size;
145 slot_data->boot_data = image_buf;
146 image_buf = NULL;
147 }
148
149out:
150 if (image_buf != NULL) {
151 avb_free(image_buf);
152 }
153 return ret;
154}
155
156static AvbSlotVerifyResult load_and_verify_vbmeta(
157 AvbOps* ops, const char* ab_suffix, int rollback_index_slot,
158 const char* partition_name, size_t partition_name_len,
159 const uint8_t* expected_public_key, size_t expected_public_key_length,
160 AvbSlotVerifyData* slot_data, AvbAlgorithmType* out_algorithm_type) {
161 char full_partition_name[PART_NAME_MAX_SIZE];
162 AvbSlotVerifyResult ret;
163 AvbIOResult io_ret;
164 size_t vbmeta_offset;
165 size_t vbmeta_size;
166 uint8_t* vbmeta_buf = NULL;
167 size_t vbmeta_num_read;
168 AvbVBMetaVerifyResult vbmeta_ret;
169 const uint8_t* pk_data;
170 size_t pk_len;
171 AvbVBMetaImageHeader vbmeta_header;
172 uint64_t stored_rollback_index;
173 const AvbDescriptor** descriptors = NULL;
174 size_t num_descriptors;
175 size_t n;
176 int is_main_vbmeta;
177
178 avb_assert(slot_data != NULL);
179
180 is_main_vbmeta = (avb_strcmp(partition_name, "vbmeta") == 0);
181
182 if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
183 avb_error("Partition name is not valid UTF-8.\n");
184 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
185 goto out;
186 }
187
188 /* Construct full partition name. */
189 if (!avb_str_concat(full_partition_name, sizeof full_partition_name,
190 partition_name, partition_name_len, ab_suffix,
191 avb_strlen(ab_suffix))) {
192 avb_error("Partition name and suffix does not fit.\n");
193 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
194 goto out;
195 }
196
197 avb_debugv("Loading vbmeta struct from partition '", full_partition_name,
198 "'.\n", NULL);
199
200 /* If we're loading from the main vbmeta partition, the vbmeta
201 * struct is in the beginning. Otherwise we have to locate it via a
202 * footer.
203 */
204 if (is_main_vbmeta) {
205 vbmeta_offset = 0;
206 vbmeta_size = VBMETA_MAX_SIZE;
207 } else {
208 uint8_t footer_buf[AVB_FOOTER_SIZE];
209 size_t footer_num_read;
210 AvbFooter footer;
211
212 io_ret =
213 ops->read_from_partition(ops, full_partition_name, -AVB_FOOTER_SIZE,
214 AVB_FOOTER_SIZE, footer_buf, &footer_num_read);
215 if (io_ret != AVB_IO_RESULT_OK) {
216 avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
217 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
218 goto out;
219 }
220 avb_assert(footer_num_read == AVB_FOOTER_SIZE);
221
222 if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
223 &footer)) {
224 avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
225 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
226 goto out;
227 }
228
229 /* Basic footer sanity check since the data is untrusted. */
230 if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
231 avb_errorv(full_partition_name, ": Invalid vbmeta size in footer.\n",
232 NULL);
233 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
234 goto out;
235 }
236
237 vbmeta_offset = footer.vbmeta_offset;
238 vbmeta_size = footer.vbmeta_size;
239 }
240
241 vbmeta_buf = avb_malloc(vbmeta_size);
242 if (vbmeta_buf == NULL) {
243 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
244 goto out;
245 }
246
247 io_ret = ops->read_from_partition(ops, full_partition_name, vbmeta_offset,
248 vbmeta_size, vbmeta_buf, &vbmeta_num_read);
249 if (io_ret != AVB_IO_RESULT_OK) {
250 avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
251 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
252 goto out;
253 }
254 avb_assert(vbmeta_num_read <= vbmeta_size);
255
256 /* Check if the image is properly signed and get the public key used
257 * to sign the image.
258 */
259 vbmeta_ret =
260 avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
261 if (vbmeta_ret != AVB_VBMETA_VERIFY_RESULT_OK) {
262 avb_errorv(full_partition_name, ": Error verifying vbmeta image.\n", NULL);
263 ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
264 goto out;
265 }
266
267 /* Check if key used to make signature matches what is expected. */
268 if (expected_public_key != NULL) {
269 avb_assert(!is_main_vbmeta);
270 if (expected_public_key_length != pk_len ||
271 avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
272 avb_errorv(full_partition_name,
273 ": Public key used to sign data does not match key in chain "
274 "partition descriptor.\n",
275 NULL);
276 ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
277 goto out;
278 }
279 } else {
280 avb_assert(is_main_vbmeta);
281 if (!ops->validate_vbmeta_public_key(ops, pk_data, pk_len)) {
282 avb_errorv(full_partition_name,
283 ": Public key used to sign data rejected.\n", NULL);
284 ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
285 goto out;
286 }
287 }
288
289 avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
290 &vbmeta_header);
291
292 /* Check rollback index. */
293 if (!ops->read_rollback_index(ops, rollback_index_slot,
294 &stored_rollback_index)) {
295 avb_errorv(full_partition_name,
296 ": Error getting rollback index for slot.\n", NULL);
297 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
298 goto out;
299 }
300 if (vbmeta_header.rollback_index < stored_rollback_index) {
301 avb_errorv(
302 full_partition_name,
303 ": Image rollback index is less than the stored rollback index.\n",
304 NULL);
305 ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
306 goto out;
307 }
308
309 /* Now go through all descriptors and take the appropriate action:
310 *
311 * - hash descriptor: Load data from partition, calculate hash, and
312 * checks that it matches what's in the hash descriptor.
313 *
314 * - hashtree descriptor: Do nothing since verification happens
315 * on-the-fly from within the OS.
316 *
317 * - chained partition descriptor: Load the footer, load the vbmeta
318 * image, verify vbmeta image (includes rollback checks, hash
319 * checks, bail on chained partitions).
320 */
321 descriptors =
322 avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
323 for (n = 0; n < num_descriptors; n++) {
324 AvbDescriptor desc;
325
326 if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
327 avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
328 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
329 goto out;
330 }
331
332 switch (desc.tag) {
333 case AVB_DESCRIPTOR_TAG_HASH: {
334 AvbSlotVerifyResult sub_ret;
335 sub_ret = load_and_verify_hash_partition(ops, ab_suffix, descriptors[n],
336 slot_data);
337 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
338 ret = sub_ret;
339 goto out;
340 }
341 } break;
342
343 case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
344 AvbSlotVerifyResult sub_ret;
345 AvbChainPartitionDescriptor chain_desc;
346 const uint8_t* chain_partition_name;
347 const uint8_t* chain_public_key;
348
349 /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
350 if (!is_main_vbmeta) {
351 avb_errorv(full_partition_name,
352 ": Encountered chain descriptor not in main image.\n",
353 NULL);
354 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
355 goto out;
356 }
357
358 if (!avb_chain_partition_descriptor_validate_and_byteswap(
359 (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
360 avb_errorv(full_partition_name,
361 ": Chain partition descriptor is invalid.\n", NULL);
362 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
363 goto out;
364 }
365
366 chain_partition_name = ((const uint8_t*)descriptors[n]) +
367 sizeof(AvbChainPartitionDescriptor);
368 chain_public_key = chain_partition_name + chain_desc.partition_name_len;
369
370 sub_ret = load_and_verify_vbmeta(
371 ops, ab_suffix, chain_desc.rollback_index_slot,
372 (const char*)chain_partition_name, chain_desc.partition_name_len,
373 chain_public_key, chain_desc.public_key_len, slot_data,
374 NULL /* out_algorithm_type */);
375 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
376 ret = sub_ret;
377 goto out;
378 }
379 } break;
380
381 case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
382 const uint8_t* kernel_cmdline;
383 AvbKernelCmdlineDescriptor kernel_cmdline_desc;
384
385 if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
386 (AvbKernelCmdlineDescriptor*)descriptors[n],
387 &kernel_cmdline_desc)) {
388 avb_errorv(full_partition_name,
389 ": Kernel cmdline descriptor is invalid.\n", NULL);
390 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
391 goto out;
392 }
393
394 kernel_cmdline = ((const uint8_t*)descriptors[n]) +
395 sizeof(AvbKernelCmdlineDescriptor);
396
397 if (!avb_validate_utf8(kernel_cmdline,
398 kernel_cmdline_desc.kernel_cmdline_length)) {
399 avb_errorv(full_partition_name,
400 ": Kernel cmdline is not valid UTF-8.\n", NULL);
401 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
402 goto out;
403 }
404
405 if (slot_data->cmdline == NULL) {
406 slot_data->cmdline =
407 avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
408 if (slot_data->cmdline == NULL) {
409 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
410 goto out;
411 }
412 avb_memcpy(slot_data->cmdline, kernel_cmdline,
413 kernel_cmdline_desc.kernel_cmdline_length);
414 } else {
415 /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
416 size_t orig_size = avb_strlen(slot_data->cmdline);
417 size_t new_size =
418 orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
419 char* new_cmdline = avb_calloc(new_size);
420 if (new_cmdline == NULL) {
421 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
422 goto out;
423 }
424 avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
425 new_cmdline[orig_size] = ' ';
426 avb_memcpy(new_cmdline + orig_size + 1, kernel_cmdline,
427 kernel_cmdline_desc.kernel_cmdline_length);
428 avb_free(slot_data->cmdline);
429 slot_data->cmdline = new_cmdline;
430 }
431 } break;
432
433 /* Explicit fall-through */
434 case AVB_DESCRIPTOR_TAG_PROPERTY:
435 case AVB_DESCRIPTOR_TAG_HASHTREE:
436 /* Do nothing. */
437 break;
438 }
439 }
440
441 ret = AVB_SLOT_VERIFY_RESULT_OK;
442
443 /* So far, so good. Copy needed data to user, if requested. */
444 if (is_main_vbmeta) {
445 if (slot_data->vbmeta_data != NULL) {
446 avb_free(slot_data->vbmeta_data);
447 }
448 /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
449 * and this includes data past the end of the image. Pass the
450 * actual size of the vbmeta image. Also, no need to use
451 * avb_safe_add() since the header has already been verified.
452 */
453 slot_data->vbmeta_size = sizeof(AvbVBMetaImageHeader) +
454 vbmeta_header.authentication_data_block_size +
455 vbmeta_header.auxiliary_data_block_size;
456 slot_data->vbmeta_data = vbmeta_buf;
457 vbmeta_buf = NULL;
458 }
459
460 if (rollback_index_slot >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS) {
461 avb_errorv(full_partition_name, ": Invalid rollback_index_slot.\n", NULL);
462 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
463 goto out;
464 }
465
466 slot_data->rollback_indexes[rollback_index_slot] =
467 vbmeta_header.rollback_index;
468
469 if (out_algorithm_type != NULL) {
470 *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
471 }
472
473out:
474 if (vbmeta_buf != NULL) {
475 avb_free(vbmeta_buf);
476 }
477 if (descriptors != NULL) {
478 avb_free(descriptors);
479 }
480 return ret;
481}
482
483/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
484 * values. Returns NULL on OOM, otherwise the cmdline with values
485 * replaced.
486 */
487static char* sub_cmdline(AvbOps* ops, const char* cmdline,
488 const char* ab_suffix) {
489 const int NUM_GUIDS = 2;
490 const char* part_name_str[NUM_GUIDS] = {"system", "boot"};
491 const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
492 "$(ANDROID_BOOT_PARTUUID)"};
493 char* ret = NULL;
494
495 /* Replace unique partition GUIDs */
496 for (size_t n = 0; n < NUM_GUIDS; n++) {
497 char part_name[PART_NAME_MAX_SIZE];
498 char guid_buf[37];
499 char* new_ret;
500
501 if (!avb_str_concat(part_name, sizeof part_name, part_name_str[n],
502 avb_strlen(part_name_str[n]), ab_suffix,
503 avb_strlen(ab_suffix))) {
504 avb_error("Partition name and suffix does not fit.\n");
505 goto fail;
506 }
507
508 if (!ops->get_unique_guid_for_partition(ops, part_name, guid_buf,
509 sizeof guid_buf)) {
510 avb_error("Error getting unique GUID for partition.\n");
511 goto fail;
512 }
513
514 if (ret == NULL) {
515 new_ret = avb_replace(cmdline, replace_str[n], guid_buf);
516 } else {
517 new_ret = avb_replace(ret, replace_str[n], guid_buf);
518 }
519 if (new_ret == NULL) {
520 goto fail;
521 }
522 ret = new_ret;
523 }
524
525 return ret;
526
527fail:
528 if (ret != NULL) {
529 avb_free(ret);
530 }
531 return NULL;
532}
533
534static int cmdline_append_option(AvbSlotVerifyData* slot_data, const char* key,
535 const char* value) {
536 size_t offset, key_len, value_len;
537 char* new_cmdline;
538
539 key_len = avb_strlen(key);
540 value_len = avb_strlen(value);
541
542 offset = 0;
543 if (slot_data->cmdline != NULL) {
544 offset = avb_strlen(slot_data->cmdline);
545 if (offset > 0) {
546 offset += 1;
547 }
548 }
549
550 new_cmdline = avb_calloc(offset + key_len + value_len + 2);
551 if (new_cmdline == NULL) {
552 return 0;
553 }
554 if (offset > 0) {
555 avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
556 new_cmdline[offset - 1] = ' ';
557 }
558 avb_memcpy(new_cmdline + offset, key, key_len);
559 new_cmdline[offset + key_len] = '=';
560 avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
561 if (slot_data->cmdline != NULL) {
562 avb_free(slot_data->cmdline);
563 }
564 slot_data->cmdline = new_cmdline;
565
566 return 1;
567}
568
569static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
570 const char* key, uint64_t value) {
571 const int MAX_DIGITS = 32;
572 char rev_digits[MAX_DIGITS];
573 char digits[MAX_DIGITS];
574 size_t n, num_digits;
575
576 for (num_digits = 0; num_digits < MAX_DIGITS - 1;) {
577 rev_digits[num_digits++] = (value % 10) + '0';
578 value /= 10;
579 if (value == 0) {
580 break;
581 }
582 }
583
584 for (n = 0; n < num_digits; n++) {
585 digits[n] = rev_digits[num_digits - 1 - n];
586 }
587 digits[n] = '\0';
588
589 return cmdline_append_option(slot_data, key, digits);
590}
591
592static int cmdline_append_hex(AvbSlotVerifyData* slot_data, const char* key,
593 const uint8_t* data, size_t data_len) {
594 char hex_digits[17] = "0123456789abcdef";
595 char* hex_data;
596 int ret;
597 size_t n;
598
599 hex_data = avb_malloc(data_len * 2 + 1);
600 if (hex_data == NULL) return 0;
601
602 for (n = 0; n < data_len; n++) {
603 hex_data[n * 2] = hex_digits[data[n] >> 4];
604 hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
605 }
606 hex_data[n] = '\0';
607
608 ret = cmdline_append_option(slot_data, key, hex_data);
609 avb_free(hex_data);
610 return ret;
611}
612
613AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, const char* ab_suffix,
614 AvbSlotVerifyData** out_data) {
615 AvbSlotVerifyResult ret;
616 AvbSlotVerifyData* slot_data = NULL;
617 AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
618
619 if (out_data != NULL) {
620 *out_data = NULL;
621 }
622
623 slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
624 if (slot_data == NULL) {
625 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
626 goto fail;
627 }
628
629 ret = load_and_verify_vbmeta(
630 ops, ab_suffix, 0 /* rollback_index_slot */, "vbmeta",
631 avb_strlen("vbmeta"), NULL /* expected_public_key */,
632 0 /* expected_public_key_length */, slot_data, &algorithm_type);
633
634 /* If things check out, mangle the kernel command-line as needed. */
635 if (ret == AVB_SLOT_VERIFY_RESULT_OK) {
636 /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
637 if (slot_data->cmdline != NULL) {
638 char* new_cmdline = sub_cmdline(ops, slot_data->cmdline, ab_suffix);
639 if (new_cmdline == NULL) {
640 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
641 goto fail;
642 }
643 avb_free(slot_data->cmdline);
644 slot_data->cmdline = new_cmdline;
645 }
646
647 /* Add androidboot.slot_suffix, if applicable. */
648 if (avb_strlen(ab_suffix) > 0) {
649 if (!cmdline_append_option(slot_data, "androidboot.slot_suffix",
650 ab_suffix)) {
651 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
652 goto fail;
653 }
654 }
655
656 /* Set androidboot.avb.device_state to "locked" or "unlocked". */
657 bool is_device_unlocked;
658 if (!ops->read_is_device_unlocked(ops, &is_device_unlocked)) {
659 avb_error("Error getting device state.\n");
660 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
661 goto fail;
662 }
663 if (!cmdline_append_option(slot_data, "androidboot.vbmeta.device_state",
664 is_device_unlocked ? "unlocked" : "locked")) {
665 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
666 goto fail;
667 }
668
669 /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
670 * function as is used to sign vbmeta.
671 */
672 switch (algorithm_type) {
673 /* Explicit fallthrough. */
674 case AVB_ALGORITHM_TYPE_NONE:
675 case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
676 case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
677 case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
678 AvbSHA256Ctx ctx;
679 avb_sha256_init(&ctx);
680 avb_sha256_update(&ctx, slot_data->vbmeta_data, slot_data->vbmeta_size);
681 if (!cmdline_append_option(slot_data, "androidboot.vbmeta.hash_alg",
682 "sha256") ||
683 !cmdline_append_uint64_base10(slot_data, "androidboot.vbmeta.size",
684 slot_data->vbmeta_size) ||
685 !cmdline_append_hex(slot_data, "androidboot.vbmeta.digest",
686 avb_sha256_final(&ctx),
687 AVB_SHA256_DIGEST_SIZE)) {
688 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
689 goto fail;
690 }
691 } break;
692 /* Explicit fallthrough. */
693 case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
694 case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
695 case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
696 AvbSHA512Ctx ctx;
697 avb_sha512_init(&ctx);
698 avb_sha512_update(&ctx, slot_data->vbmeta_data, slot_data->vbmeta_size);
699 if (!cmdline_append_option(slot_data, "androidboot.vbmeta.hash_alg",
700 "sha512") ||
701 !cmdline_append_uint64_base10(slot_data, "androidboot.vbmeta.size",
702 slot_data->vbmeta_size) ||
703 !cmdline_append_hex(slot_data, "androidboot.vbmeta.digest",
704 avb_sha512_final(&ctx),
705 AVB_SHA512_DIGEST_SIZE)) {
706 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
707 goto fail;
708 }
709 } break;
710 case _AVB_ALGORITHM_NUM_TYPES:
711 avb_assert_not_reached();
712 break;
713 }
714
715 if (out_data != NULL) {
716 *out_data = slot_data;
717 } else {
718 avb_slot_verify_data_free(slot_data);
719 }
720 }
721
722 return ret;
723
724fail:
725 if (slot_data != NULL) {
726 avb_slot_verify_data_free(slot_data);
727 }
728 return ret;
729}
730
731void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
732 if (data->boot_data != NULL) {
733 avb_free(data->boot_data);
734 }
735 if (data->cmdline != NULL) {
736 avb_free(data->cmdline);
737 }
738 avb_free(data);
739}