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