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