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