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
27bool 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
55void 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
62void 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
83AvbIOResult 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
114AvbIOResult 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
134static bool slot_is_bootable(AvbABSlotData* slot) {
135  return slot->priority > 0 &&
136         (slot->successful_boot || (slot->tries_remaining > 0));
137}
138
139static 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 */
149static 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
166static 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 */
171static 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 */
195static 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
205AvbABFlowResult 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
378out:
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
409AvbIOResult 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
435out:
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
442AvbIOResult 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
458out:
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
465AvbIOResult 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
488out:
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
495const 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