summaryrefslogtreecommitdiff
path: root/libavb_ab/avb_ab_flow.c (plain)
blob: 4750c2306d7989d23c70cde76e548a1c86ac3766
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#define LOG_TAG "control_avb"
25
26#include <log/log.h>
27#include "avb_ab_flow.h"
28#include <stdio.h>
29
30bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
31 /* Ensure magic is correct. */
32 if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
33 ALOGE("Magic is incorrect.\n");
34 return false;
35 }
36
37 avb_memcpy(dest, src, sizeof(AvbABData));
38 dest->crc32 = avb_be32toh(dest->crc32);
39
40 /* Ensure we don't attempt to access any fields if the major version
41 * is not supported.
42 */
43 if (dest->version_major > AVB_AB_MAJOR_VERSION) {
44 ALOGE("No support for given major version.\n");
45 return false;
46 }
47
48 /* Bail if CRC32 doesn't match. */
49 if (dest->crc32 !=
50 avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
51 ALOGE("CRC32 does not match.\n");
52 return false;
53 }
54
55 return true;
56}
57
58void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
59 AvbABData* dest) {
60 avb_memcpy(dest, src, sizeof(AvbABData));
61 dest->crc32 = avb_htobe32(
62 avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
63}
64
65void avb_ab_data_init(AvbABData* data) {
66 avb_memset(data, '\0', sizeof(AvbABData));
67 avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
68 data->version_major = AVB_AB_MAJOR_VERSION;
69 data->version_minor = AVB_AB_MINOR_VERSION;
70 data->slots[0].priority = AVB_AB_MAX_PRIORITY;
71 data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
72 data->slots[0].successful_boot = 0;
73 data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
74 data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
75 data->slots[1].successful_boot = 0;
76}
77
78/* The AvbABData struct is stored 2048 bytes into the 'misc' partition
79 * following the 'struct bootloader_message' field. The struct is
80 * compatible with the guidelines in bootable/recovery/bootloader.h -
81 * e.g. it is stored in the |slot_suffix| field, starts with a
82 * NUL-byte, and is 32 bytes long.
83 */
84#define AB_METADATA_MISC_PARTITION_OFFSET 2048
85
86AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
87 AvbOps* ops = ab_ops->ops;
88 AvbABData serialized;
89 AvbIOResult io_ret;
90 size_t num_bytes_read;
91
92 io_ret = ops->read_from_partition(ops,
93 "misc",
94 AB_METADATA_MISC_PARTITION_OFFSET,
95 sizeof(AvbABData),
96 &serialized,
97 &num_bytes_read);
98 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
99 return AVB_IO_RESULT_ERROR_OOM;
100 } else if (io_ret != AVB_IO_RESULT_OK ||
101 num_bytes_read != sizeof(AvbABData)) {
102 ALOGE("Error reading A/B metadata.\n");
103 return AVB_IO_RESULT_ERROR_IO;
104 }
105
106 if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
107 ALOGE(
108 "Error validating A/B metadata from disk. "
109 "Resetting and writing new A/B metadata to disk.\n");
110 avb_ab_data_init(data);
111 return avb_ab_data_write(ab_ops, data);
112 }
113
114 return AVB_IO_RESULT_OK;
115}
116
117AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) {
118 AvbOps* ops = ab_ops->ops;
119 AvbABData serialized;
120 AvbIOResult io_ret;
121
122 avb_ab_data_update_crc_and_byteswap(data, &serialized);
123 io_ret = ops->write_to_partition(ops,
124 "misc",
125 AB_METADATA_MISC_PARTITION_OFFSET,
126 sizeof(AvbABData),
127 &serialized);
128 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
129 return AVB_IO_RESULT_ERROR_OOM;
130 } else if (io_ret != AVB_IO_RESULT_OK) {
131 ALOGE("*******Error writing A/B metadata.\n");
132 return AVB_IO_RESULT_ERROR_IO;
133 }
134 return AVB_IO_RESULT_OK;
135}
136
137static bool slot_is_bootable(AvbABSlotData* slot) {
138 return slot->priority > 0 &&
139 (slot->successful_boot || (slot->tries_remaining > 0));
140}
141
142static void slot_set_unbootable(AvbABSlotData* slot) {
143 slot->priority = 0;
144 slot->tries_remaining = 0;
145 slot->successful_boot = 0;
146}
147
148/* Ensure all unbootable and/or illegal states are marked as the
149 * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
150 * and successful_boot=0.
151 */
152static void slot_normalize(AvbABSlotData* slot) {
153 if (slot->priority > 0) {
154 if (slot->tries_remaining == 0 && !slot->successful_boot) {
155 /* We've exhausted all tries -> unbootable. */
156 slot_set_unbootable(slot);
157 }
158 if (slot->tries_remaining > 0 && slot->successful_boot) {
159 /* Illegal state - avb_ab_mark_slot_successful() will clear
160 * tries_remaining when setting successful_boot.
161 */
162 slot_set_unbootable(slot);
163 }
164 } else {
165 slot_set_unbootable(slot);
166 }
167}
168
169static const char* slot_suffixes[2] = {"_a", "_b"};
170
171/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
172 * success, error code otherwise.
173 */
174static AvbIOResult load_metadata(AvbABOps* ab_ops,
175 AvbABData* ab_data,
176 AvbABData* ab_data_orig) {
177 AvbIOResult io_ret;
178
179 io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
180 if (io_ret != AVB_IO_RESULT_OK) {
181 ALOGE("I/O error while loading A/B metadata.\n");
182 return io_ret;
183 }
184 *ab_data_orig = *ab_data;
185
186 /* Ensure data is normalized, e.g. illegal states will be marked as
187 * unbootable and all unbootable states are represented with
188 * (priority=0, tries_remaining=0, successful_boot=0).
189 */
190 slot_normalize(&ab_data->slots[0]);
191 slot_normalize(&ab_data->slots[1]);
192 return AVB_IO_RESULT_OK;
193}
194
195/* Writes A/B metadata to disk only if it has changed - returns
196 * AVB_IO_RESULT_OK on success, error code otherwise.
197 */
198static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
199 AvbABData* ab_data,
200 AvbABData* ab_data_orig) {
201 if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
202 ALOGE("Writing A/B metadata to disk.\n");
203 return ab_ops->write_ab_metadata(ab_ops, ab_data);
204 }
205 return AVB_IO_RESULT_OK;
206}
207
208AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
209 const char* const* requested_partitions,
210 bool allow_verification_error,
211 AvbSlotVerifyData** out_data) {
212 AvbOps* ops = ab_ops->ops;
213 AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
214 AvbSlotVerifyData* data = NULL;
215 AvbABFlowResult ret;
216 AvbABData ab_data, ab_data_orig;
217 size_t slot_index_to_boot, n;
218 AvbIOResult io_ret;
219 bool saw_and_allowed_verification_error = false;
220
221 io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
222 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
223 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
224 goto out;
225 } else if (io_ret != AVB_IO_RESULT_OK) {
226 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
227 goto out;
228 }
229
230 /* Validate all bootable slots. */
231 for (n = 0; n < 2; n++) {
232 if (slot_is_bootable(&ab_data.slots[n])) {
233 AvbSlotVerifyResult verify_result;
234 bool set_slot_unbootable = false;
235
236 verify_result = avb_slot_verify(ops,
237 requested_partitions,
238 slot_suffixes[n],
239 allow_verification_error,
240 &slot_data[n]);
241 switch (verify_result) {
242 case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
243 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
244 goto out;
245
246 case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
247 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
248 goto out;
249
250 case AVB_SLOT_VERIFY_RESULT_OK:
251 break;
252
253 case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
254 case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
255 /* Even with |allow_verification_error| these mean game over. */
256 set_slot_unbootable = true;
257 break;
258
259 /* explicit fallthrough. */
260 case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
261 case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
262 case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
263 if (allow_verification_error) {
264 /* Do nothing since we allow this. */
265 avb_debugv("Allowing slot ",
266 slot_suffixes[n],
267 " which verified "
268 "with result ",
269 avb_slot_verify_result_to_string(verify_result),
270 " because |allow_verification_error| is true.\n",
271 NULL);
272 saw_and_allowed_verification_error = true;
273 } else {
274 set_slot_unbootable = true;
275 }
276 break;
277 }
278
279 if (set_slot_unbootable) {
280 ALOGE("Error verifying slot %s with result %s - setting unbootable.",
281 slot_suffixes[n], avb_slot_verify_result_to_string(verify_result));
282 slot_set_unbootable(&ab_data.slots[n]);
283 }
284 }
285 }
286
287 if (slot_is_bootable(&ab_data.slots[0]) &&
288 slot_is_bootable(&ab_data.slots[1])) {
289 if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
290 slot_index_to_boot = 1;
291 } else {
292 slot_index_to_boot = 0;
293 }
294 } else if (slot_is_bootable(&ab_data.slots[0])) {
295 slot_index_to_boot = 0;
296 } else if (slot_is_bootable(&ab_data.slots[1])) {
297 slot_index_to_boot = 1;
298 } else {
299 /* No bootable slots! */
300 ALOGE("No bootable slots found.\n");
301 ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
302 goto out;
303 }
304
305 /* Update stored rollback index such that the stored rollback index
306 * is the largest value supporting all currently bootable slots. Do
307 * this for every rollback index location.
308 */
309 for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
310 uint64_t rollback_index_value = 0;
311
312 if (slot_data[0] != NULL && slot_data[1] != NULL) {
313 uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
314 uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
315 rollback_index_value =
316 (a_rollback_index < b_rollback_index ? a_rollback_index
317 : b_rollback_index);
318 } else if (slot_data[0] != NULL) {
319 rollback_index_value = slot_data[0]->rollback_indexes[n];
320 } else if (slot_data[1] != NULL) {
321 rollback_index_value = slot_data[1]->rollback_indexes[n];
322 }
323
324 if (rollback_index_value != 0) {
325 uint64_t current_rollback_index_value;
326 io_ret = ops->read_rollback_index(ops, n, &current_rollback_index_value);
327 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
328 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
329 goto out;
330 } else if (io_ret != AVB_IO_RESULT_OK) {
331 ALOGE("Error getting rollback index for slot.\n");
332 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
333 goto out;
334 }
335 if (current_rollback_index_value != rollback_index_value) {
336 io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
337 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
338 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
339 goto out;
340 } else if (io_ret != AVB_IO_RESULT_OK) {
341 ALOGE("Error setting stored rollback index.\n");
342 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
343 goto out;
344 }
345 }
346 }
347 }
348
349 /* Finally, select this slot. */
350 avb_assert(slot_data[slot_index_to_boot] != NULL);
351 data = slot_data[slot_index_to_boot];
352 slot_data[slot_index_to_boot] = NULL;
353 if (saw_and_allowed_verification_error) {
354 avb_assert(allow_verification_error);
355 ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
356 } else {
357 ret = AVB_AB_FLOW_RESULT_OK;
358 }
359
360 /* ... and decrement tries remaining, if applicable. */
361 if (!ab_data.slots[slot_index_to_boot].successful_boot &&
362 ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
363 ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
364 }
365
366out:
367 io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
368 if (io_ret != AVB_IO_RESULT_OK) {
369 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
370 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
371 } else {
372 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
373 }
374 if (data != NULL) {
375 avb_slot_verify_data_free(data);
376 data = NULL;
377 }
378 }
379
380 for (n = 0; n < 2; n++) {
381 if (slot_data[n] != NULL) {
382 avb_slot_verify_data_free(slot_data[n]);
383 }
384 }
385
386 if (out_data != NULL) {
387 *out_data = data;
388 } else {
389 if (data != NULL) {
390 avb_slot_verify_data_free(data);
391 }
392 }
393
394 return ret;
395}
396
397AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
398 unsigned int slot_number) {
399 AvbABData ab_data, ab_data_orig;
400 unsigned int other_slot_number;
401 AvbIOResult ret;
402
403 ALOGE("*************come to avb_ab_mark_slot_active slot:%d", slot_number);
404
405 if (slot_number >= 2) {
406 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
407 }
408
409 ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
410 if (ret != AVB_IO_RESULT_OK) {
411 goto out;
412 }
413
414 ALOGE("ab_data.slots[0].priority: %d\n", ab_data.slots[0].priority);
415 ALOGE("ab_data.slots[0].tries_remaining: %d\n", ab_data.slots[0].tries_remaining);
416 ALOGE("ab_data.slots[0].successful_boot: %d\n", ab_data.slots[0].successful_boot);
417 ALOGE("ab_data.slots[1].priority: %d\n", ab_data.slots[1].priority);
418 ALOGE("ab_data.slots[1].tries_remaining: %d\n", ab_data.slots[1].tries_remaining);
419 ALOGE("ab_data.slots[1].successful_boot: %d\n", ab_data.slots[1].successful_boot);
420
421 /* Make requested slot top priority, unsuccessful, and with max tries. */
422 ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
423 ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
424 ab_data.slots[slot_number].successful_boot = 0;
425
426 /* Ensure other slot doesn't have as high a priority. */
427 other_slot_number = 1 - slot_number;
428
429 ALOGE("come to avb_ab_mark_slot_active other_slot_number: %d\n", other_slot_number);
430 ALOGE("ab_data.slots[other_slot_number].priority: %d\n", ab_data.slots[other_slot_number].priority);
431
432 if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
433 ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
434 }
435
436 ALOGE("ab_data.slots[other_slot_number].priority: %d\n", ab_data.slots[other_slot_number].priority);
437
438 ret = AVB_IO_RESULT_OK;
439out:
440 if (ret == AVB_IO_RESULT_OK) {
441 ALOGE("come to avb_ab_mark_slot_active 5\n");
442 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
443 }
444 return ret;
445}
446
447AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
448 unsigned int slot_number) {
449 AvbABData ab_data, ab_data_orig;
450 AvbIOResult ret;
451
452 if (slot_number >= 2) {
453 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
454 }
455
456 ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
457 if (ret != AVB_IO_RESULT_OK) {
458 goto out;
459 }
460
461 slot_set_unbootable(&ab_data.slots[slot_number]);
462
463 ret = AVB_IO_RESULT_OK;
464
465out:
466 if (ret == AVB_IO_RESULT_OK) {
467 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
468 }
469 return ret;
470}
471
472AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
473 unsigned int slot_number) {
474 AvbABData ab_data, ab_data_orig;
475 AvbIOResult ret;
476
477 if (slot_number >= 2) {
478 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
479 }
480
481 ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
482 if (ret != AVB_IO_RESULT_OK) {
483 goto out;
484 }
485
486 if (!slot_is_bootable(&ab_data.slots[slot_number])) {
487 ALOGE("Cannot mark unbootable slot as successful.\n");
488 ret = AVB_IO_RESULT_OK;
489 goto out;
490 }
491
492 ab_data.slots[slot_number].tries_remaining = 0;
493 ab_data.slots[slot_number].successful_boot = 1;
494
495 ret = AVB_IO_RESULT_OK;
496
497out:
498 if (ret == AVB_IO_RESULT_OK) {
499 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
500 }
501 return ret;
502}
503
504const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
505 const char* ret = NULL;
506
507 switch (result) {
508 case AVB_AB_FLOW_RESULT_OK:
509 ret = "OK";
510 break;
511
512 case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
513 ret = "OK_WITH_VERIFICATION_ERROR";
514 break;
515
516 case AVB_AB_FLOW_RESULT_ERROR_OOM:
517 ret = "ERROR_OOM";
518 break;
519
520 case AVB_AB_FLOW_RESULT_ERROR_IO:
521 ret = "ERROR_IO";
522 break;
523
524 case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
525 ret = "ERROR_NO_BOOTABLE_SLOTS";
526 break;
527 /* Do not add a 'default:' case here because of -Wswitch. */
528 }
529
530 if (ret == NULL) {
531 ALOGE("Unknown AvbABFlowResult value.\n");
532 ret = "(unknown)";
533 }
534
535 return ret;
536}
537