• 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_debug("Allowing slot ",
267                       slot_suffixes[n],
268                       " which verified with result ",
269                       avb_slot_verify_result_to_string(verify_result),
270                       " because AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR "
271                       "is set.\n");
272             saw_and_allowed_verification_error = true;
273           } else {
274             set_slot_unbootable = true;
275           }
276           break;
277 
278         case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
279           ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT;
280           goto out;
281           /* Do not add a 'default:' case here because of -Wswitch. */
282       }
283 
284       if (set_slot_unbootable) {
285         avb_error("Error verifying slot ",
286                   slot_suffixes[n],
287                   " with result ",
288                   avb_slot_verify_result_to_string(verify_result),
289                   " - setting unbootable.\n");
290         slot_set_unbootable(&ab_data.slots[n]);
291       }
292     }
293   }
294 
295   if (slot_is_bootable(&ab_data.slots[0]) &&
296       slot_is_bootable(&ab_data.slots[1])) {
297     if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
298       slot_index_to_boot = 1;
299     } else {
300       slot_index_to_boot = 0;
301     }
302   } else if (slot_is_bootable(&ab_data.slots[0])) {
303     slot_index_to_boot = 0;
304   } else if (slot_is_bootable(&ab_data.slots[1])) {
305     slot_index_to_boot = 1;
306   } else {
307     /* No bootable slots! */
308     avb_error("No bootable slots found.\n");
309     ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
310     goto out;
311   }
312 
313   /* Update stored rollback index such that the stored rollback index
314    * is the largest value supporting all currently bootable slots. Do
315    * this for every rollback index location.
316    */
317   for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
318     uint64_t rollback_index_value = 0;
319 
320     if (slot_data[0] != NULL && slot_data[1] != NULL) {
321       uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
322       uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
323       rollback_index_value =
324           (a_rollback_index < b_rollback_index ? a_rollback_index
325                                                : b_rollback_index);
326     } else if (slot_data[0] != NULL) {
327       rollback_index_value = slot_data[0]->rollback_indexes[n];
328     } else if (slot_data[1] != NULL) {
329       rollback_index_value = slot_data[1]->rollback_indexes[n];
330     }
331 
332     if (rollback_index_value != 0) {
333       uint64_t current_rollback_index_value;
334       io_ret = ops->read_rollback_index(ops, n, &current_rollback_index_value);
335       if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
336         ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
337         goto out;
338       } else if (io_ret != AVB_IO_RESULT_OK) {
339         avb_error("Error getting rollback index for slot.\n");
340         ret = AVB_AB_FLOW_RESULT_ERROR_IO;
341         goto out;
342       }
343       if (current_rollback_index_value != rollback_index_value) {
344         io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
345         if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
346           ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
347           goto out;
348         } else if (io_ret != AVB_IO_RESULT_OK) {
349           avb_error("Error setting stored rollback index.\n");
350           ret = AVB_AB_FLOW_RESULT_ERROR_IO;
351           goto out;
352         }
353       }
354     }
355   }
356 
357   /* Finally, select this slot. */
358   avb_assert(slot_data[slot_index_to_boot] != NULL);
359   data = slot_data[slot_index_to_boot];
360   slot_data[slot_index_to_boot] = NULL;
361   if (saw_and_allowed_verification_error) {
362     avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
363     ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
364   } else {
365     ret = AVB_AB_FLOW_RESULT_OK;
366   }
367 
368   /* ... and decrement tries remaining, if applicable. */
369   if (!ab_data.slots[slot_index_to_boot].successful_boot &&
370       ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
371     ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
372   }
373 
374 out:
375   io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
376   if (io_ret != AVB_IO_RESULT_OK) {
377     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
378       ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
379     } else {
380       ret = AVB_AB_FLOW_RESULT_ERROR_IO;
381     }
382     if (data != NULL) {
383       avb_slot_verify_data_free(data);
384       data = NULL;
385     }
386   }
387 
388   for (n = 0; n < 2; n++) {
389     if (slot_data[n] != NULL) {
390       avb_slot_verify_data_free(slot_data[n]);
391     }
392   }
393 
394   if (out_data != NULL) {
395     *out_data = data;
396   } else {
397     if (data != NULL) {
398       avb_slot_verify_data_free(data);
399     }
400   }
401 
402   return ret;
403 }
404 
avb_ab_mark_slot_active(AvbABOps * ab_ops,unsigned int slot_number)405 AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
406                                     unsigned int slot_number) {
407   AvbABData ab_data, ab_data_orig;
408   unsigned int other_slot_number;
409   AvbIOResult ret;
410 
411   avb_assert(slot_number < 2);
412 
413   ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
414   if (ret != AVB_IO_RESULT_OK) {
415     goto out;
416   }
417 
418   /* Make requested slot top priority, unsuccessful, and with max tries. */
419   ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
420   ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
421   ab_data.slots[slot_number].successful_boot = 0;
422 
423   /* Ensure other slot doesn't have as high a priority. */
424   other_slot_number = 1 - slot_number;
425   if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
426     ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
427   }
428 
429   ret = AVB_IO_RESULT_OK;
430 
431 out:
432   if (ret == AVB_IO_RESULT_OK) {
433     ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
434   }
435   return ret;
436 }
437 
avb_ab_mark_slot_unbootable(AvbABOps * ab_ops,unsigned int slot_number)438 AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
439                                         unsigned int slot_number) {
440   AvbABData ab_data, ab_data_orig;
441   AvbIOResult ret;
442 
443   avb_assert(slot_number < 2);
444 
445   ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
446   if (ret != AVB_IO_RESULT_OK) {
447     goto out;
448   }
449 
450   slot_set_unbootable(&ab_data.slots[slot_number]);
451 
452   ret = AVB_IO_RESULT_OK;
453 
454 out:
455   if (ret == AVB_IO_RESULT_OK) {
456     ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
457   }
458   return ret;
459 }
460 
avb_ab_mark_slot_successful(AvbABOps * ab_ops,unsigned int slot_number)461 AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
462                                         unsigned int slot_number) {
463   AvbABData ab_data, ab_data_orig;
464   AvbIOResult ret;
465 
466   avb_assert(slot_number < 2);
467 
468   ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
469   if (ret != AVB_IO_RESULT_OK) {
470     goto out;
471   }
472 
473   if (!slot_is_bootable(&ab_data.slots[slot_number])) {
474     avb_error("Cannot mark unbootable slot as successful.\n");
475     ret = AVB_IO_RESULT_OK;
476     goto out;
477   }
478 
479   ab_data.slots[slot_number].tries_remaining = 0;
480   ab_data.slots[slot_number].successful_boot = 1;
481 
482   ret = AVB_IO_RESULT_OK;
483 
484 out:
485   if (ret == AVB_IO_RESULT_OK) {
486     ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
487   }
488   return ret;
489 }
490 
avb_ab_flow_result_to_string(AvbABFlowResult result)491 const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
492   const char* ret = NULL;
493 
494   switch (result) {
495     case AVB_AB_FLOW_RESULT_OK:
496       ret = "OK";
497       break;
498 
499     case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
500       ret = "OK_WITH_VERIFICATION_ERROR";
501       break;
502 
503     case AVB_AB_FLOW_RESULT_ERROR_OOM:
504       ret = "ERROR_OOM";
505       break;
506 
507     case AVB_AB_FLOW_RESULT_ERROR_IO:
508       ret = "ERROR_IO";
509       break;
510 
511     case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
512       ret = "ERROR_NO_BOOTABLE_SLOTS";
513       break;
514 
515     case AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT:
516       ret = "ERROR_INVALID_ARGUMENT";
517       break;
518       /* Do not add a 'default:' case here because of -Wswitch. */
519   }
520 
521   if (ret == NULL) {
522     avb_error("Unknown AvbABFlowResult value.\n");
523     ret = "(unknown)";
524   }
525 
526   return ret;
527 }
528