blob: 7e11e2706077cd03a93a944a6543145f4cec7a86 [file] [log] [blame]
David Zeuthen8b6973b2016-09-20 12:39:49 -04001/*
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#include "avb_util.h"
27
28bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
29 /* Ensure magic is correct. */
30 if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
31 avb_error("Magic is incorrect.\n");
32 return false;
33 }
34
35 avb_memcpy(dest, src, sizeof(AvbABData));
36 dest->crc32 = avb_be32toh(dest->crc32);
37
38 /* Ensure we don't attempt to access any fields if the major version
39 * is not supported.
40 */
41 if (dest->version_major > AVB_AB_MAJOR_VERSION) {
42 avb_error("No support for given major version.\n");
43 return false;
44 }
45
46 /* Bail if CRC32 doesn't match. */
47 if (dest->crc32 !=
48 avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
49 avb_error("CRC32 does not match.\n");
50 return false;
51 }
52
53 return true;
54}
55
56void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
57 AvbABData* dest) {
58 avb_memcpy(dest, src, sizeof(AvbABData));
59 dest->crc32 = avb_htobe32(
60 avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
61}
62
63void avb_ab_data_init(AvbABData* data) {
64 avb_memset(data, '\0', sizeof(AvbABData));
65 avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
66 data->version_major = AVB_AB_MAJOR_VERSION;
67 data->version_minor = AVB_AB_MINOR_VERSION;
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
David Zeuthen507752b2016-09-29 16:31:18 -040084AvbIOResult avb_ab_data_read(AvbOps* ops, AvbABData* data) {
David Zeuthen8b6973b2016-09-20 12:39:49 -040085 AvbABData serialized;
David Zeuthen507752b2016-09-29 16:31:18 -040086 AvbIOResult io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -040087 size_t num_bytes_read;
88
David Zeuthen507752b2016-09-29 16:31:18 -040089 io_ret =
David Zeuthen8b6973b2016-09-20 12:39:49 -040090 ops->read_from_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET,
91 sizeof(AvbABData), &serialized, &num_bytes_read);
David Zeuthen507752b2016-09-29 16:31:18 -040092 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
93 return AVB_IO_RESULT_ERROR_OOM;
94 } else if (io_ret != AVB_IO_RESULT_OK ||
95 num_bytes_read != sizeof(AvbABData)) {
David Zeuthen8b6973b2016-09-20 12:39:49 -040096 avb_error("Error reading A/B metadata.\n");
David Zeuthen507752b2016-09-29 16:31:18 -040097 return AVB_IO_RESULT_ERROR_IO;
David Zeuthen8b6973b2016-09-20 12:39:49 -040098 }
99
100 if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
101 avb_error(
102 "Error validating A/B metadata from disk. "
103 "Resetting and writing new A/B metadata to disk.\n");
104 avb_ab_data_init(data);
105 return avb_ab_data_write(ops, data);
106 }
107
David Zeuthen507752b2016-09-29 16:31:18 -0400108 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400109}
110
David Zeuthen507752b2016-09-29 16:31:18 -0400111AvbIOResult avb_ab_data_write(AvbOps* ops, const AvbABData* data) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400112 AvbABData serialized;
David Zeuthen507752b2016-09-29 16:31:18 -0400113 AvbIOResult io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400114
115 avb_ab_data_update_crc_and_byteswap(data, &serialized);
David Zeuthen507752b2016-09-29 16:31:18 -0400116 io_ret =
David Zeuthen8b6973b2016-09-20 12:39:49 -0400117 ops->write_to_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET,
118 sizeof(AvbABData), &serialized);
David Zeuthen507752b2016-09-29 16:31:18 -0400119 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
120 return AVB_IO_RESULT_ERROR_OOM;
121 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400122 avb_error("Error writing A/B metadata.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400123 return AVB_IO_RESULT_ERROR_IO;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400124 }
David Zeuthen507752b2016-09-29 16:31:18 -0400125 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400126}
127
128static bool slot_is_bootable(AvbABSlotData* slot) {
129 return slot->priority > 0 &&
130 (slot->successful_boot || (slot->tries_remaining > 0));
131}
132
133static void slot_set_unbootable(AvbABSlotData* slot) {
134 slot->priority = 0;
135 slot->tries_remaining = 0;
136 slot->successful_boot = 0;
137}
138
139/* Ensure all unbootable and/or illegal states are marked as the
140 * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
141 * and successful_boot=0.
142 */
143static void slot_normalize(AvbABSlotData* slot) {
144 if (slot->priority > 0) {
145 if (slot->tries_remaining == 0 && !slot->successful_boot) {
146 /* We've exhausted all tries -> unbootable. */
147 slot_set_unbootable(slot);
148 }
149 if (slot->tries_remaining > 0 && slot->successful_boot) {
150 /* Illegal state - avb_ab_mark_slot_successful() will clear
151 * tries_remaining when setting successful_boot.
152 */
153 slot_set_unbootable(slot);
154 }
155 } else {
156 slot_set_unbootable(slot);
157 }
158}
159
160static const char* slot_suffixes[2] = {"_a", "_b"};
161
David Zeuthen507752b2016-09-29 16:31:18 -0400162/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
163 * success, error code otherwise.
164 */
165static AvbIOResult load_metadata(AvbOps* ops, AvbABData* ab_data,
166 AvbABData* ab_data_orig) {
167 AvbIOResult io_ret;
168
169 io_ret = avb_ab_data_read(ops, ab_data);
170 if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400171 avb_error("I/O error while loading A/B metadata.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400172 return io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400173 }
174 *ab_data_orig = *ab_data;
175
176 /* Ensure data is normalized, e.g. illegal states will be marked as
177 * unbootable and all unbootable states are represented with
178 * (priority=0, tries_remaining=0, successful_boot=0).
179 */
180 slot_normalize(&ab_data->slots[0]);
181 slot_normalize(&ab_data->slots[1]);
David Zeuthen507752b2016-09-29 16:31:18 -0400182 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400183}
184
David Zeuthen507752b2016-09-29 16:31:18 -0400185/* Writes A/B metadata to disk only if it has changed - returns
186 * AVB_IO_RESULT_OK on success, error code otherwise.
David Zeuthen8b6973b2016-09-20 12:39:49 -0400187 */
David Zeuthen507752b2016-09-29 16:31:18 -0400188static AvbIOResult save_metadata_if_changed(AvbOps* ops, AvbABData* ab_data,
189 AvbABData* ab_data_orig) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400190 if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
191 avb_debug("Writing A/B metadata to disk.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400192 return avb_ab_data_write(ops, ab_data);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400193 }
David Zeuthen507752b2016-09-29 16:31:18 -0400194 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400195}
196
197AvbABFlowResult avb_ab_flow(AvbOps* ops, AvbSlotVerifyData** out_data) {
198 AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
199 AvbSlotVerifyData* data = NULL;
200 AvbABFlowResult ret;
201 AvbABData ab_data, ab_data_orig;
202 size_t slot_index_to_boot, n;
David Zeuthen507752b2016-09-29 16:31:18 -0400203 AvbIOResult io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400204
David Zeuthen507752b2016-09-29 16:31:18 -0400205 io_ret = load_metadata(ops, &ab_data, &ab_data_orig);
206 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
207 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
208 goto out;
209 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400210 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
211 goto out;
212 }
213
214 /* Validate all bootable slots. */
215 for (n = 0; n < 2; n++) {
216 if (slot_is_bootable(&ab_data.slots[n])) {
217 AvbSlotVerifyResult verify_result;
218 verify_result = avb_slot_verify(ops, slot_suffixes[n], &slot_data[n]);
219 if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
David Zeuthen507752b2016-09-29 16:31:18 -0400220 if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_OOM) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400221 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
222 goto out;
223 }
David Zeuthen507752b2016-09-29 16:31:18 -0400224 if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_IO) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400225 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
226 goto out;
227 }
228 avb_errorv("Error verifying slot ", slot_suffixes[n], " with result ",
229 avb_slot_verify_result_to_string(verify_result),
230 " - setting unbootable.\n", NULL);
231 slot_set_unbootable(&ab_data.slots[n]);
232 }
233 }
234 }
235
236 if (slot_is_bootable(&ab_data.slots[0]) &&
237 slot_is_bootable(&ab_data.slots[1])) {
238 if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
239 slot_index_to_boot = 1;
240 } else {
241 slot_index_to_boot = 0;
242 }
243 } else if (slot_is_bootable(&ab_data.slots[0])) {
244 slot_index_to_boot = 0;
245 } else if (slot_is_bootable(&ab_data.slots[1])) {
246 slot_index_to_boot = 1;
247 } else {
248 /* No bootable slots! */
249 avb_error("No bootable slots found.\n");
250 ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
251 goto out;
252 }
253
254 /* Update stored rollback index such that the stored rollback index
255 * is the largest value supporting all currently bootable slots. Do
256 * this for every rollback index slot.
257 */
258 for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) {
259 uint64_t rollback_index_value = 0;
260
261 if (slot_data[0] != NULL && slot_data[1] != NULL) {
262 uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
263 uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
264 rollback_index_value =
265 (a_rollback_index < b_rollback_index ? a_rollback_index
266 : b_rollback_index);
267 } else if (slot_data[0] != NULL) {
268 rollback_index_value = slot_data[0]->rollback_indexes[n];
269 } else if (slot_data[1] != NULL) {
270 rollback_index_value = slot_data[1]->rollback_indexes[n];
271 }
272
273 if (rollback_index_value != 0) {
274 uint64_t current_rollback_index_value;
David Zeuthen507752b2016-09-29 16:31:18 -0400275 io_ret = ops->read_rollback_index(ops, n, &current_rollback_index_value);
276 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
277 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
278 goto out;
279 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400280 avb_error("Error getting rollback index for slot.\n");
281 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
282 goto out;
283 }
284 if (current_rollback_index_value != rollback_index_value) {
David Zeuthen507752b2016-09-29 16:31:18 -0400285 io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
286 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
287 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
288 goto out;
289 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400290 avb_error("Error setting stored rollback index.\n");
291 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
292 goto out;
293 }
294 }
295 }
296 }
297
298 /* Finally, select this slot. */
299 avb_assert(slot_data[slot_index_to_boot] != NULL);
300 data = slot_data[slot_index_to_boot];
301 slot_data[slot_index_to_boot] = NULL;
302 ret = AVB_AB_FLOW_RESULT_OK;
303
304 /* ... and decrement tries remaining, if applicable. */
305 if (!ab_data.slots[slot_index_to_boot].successful_boot &&
306 ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
307 ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
308 }
309
310out:
David Zeuthen507752b2016-09-29 16:31:18 -0400311 io_ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig);
312 if (io_ret != AVB_IO_RESULT_OK) {
313 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
314 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
315 } else {
316 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
317 }
David Zeuthen8b6973b2016-09-20 12:39:49 -0400318 if (data != NULL) {
319 avb_slot_verify_data_free(data);
320 data = NULL;
321 }
322 }
323
324 for (n = 0; n < 2; n++) {
325 if (slot_data[n] != NULL) {
326 avb_slot_verify_data_free(slot_data[n]);
327 }
328 }
329
330 if (out_data != NULL) {
331 *out_data = data;
332 } else {
333 if (data != NULL) {
334 avb_slot_verify_data_free(data);
335 }
336 }
337
338 return ret;
339}
340
David Zeuthen507752b2016-09-29 16:31:18 -0400341AvbIOResult avb_ab_mark_slot_active(AvbOps* ops, unsigned int slot_number) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400342 AvbABData ab_data, ab_data_orig;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400343 unsigned int other_slot_number;
David Zeuthen507752b2016-09-29 16:31:18 -0400344 AvbIOResult ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400345
346 avb_assert(slot_number < 2);
347
David Zeuthen507752b2016-09-29 16:31:18 -0400348 ret = load_metadata(ops, &ab_data, &ab_data_orig);
349 if (ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400350 goto out;
351 }
352
353 /* Make requested slot top priority, unsuccessful, and with max tries. */
354 ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
355 ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
356 ab_data.slots[slot_number].successful_boot = 0;
357
358 /* Ensure other slot doesn't have as high a priority. */
359 other_slot_number = 1 - slot_number;
360 if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
361 ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
362 }
363
David Zeuthen507752b2016-09-29 16:31:18 -0400364 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400365
366out:
David Zeuthen507752b2016-09-29 16:31:18 -0400367 if (ret == AVB_IO_RESULT_OK) {
368 ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400369 }
370 return ret;
371}
372
David Zeuthen507752b2016-09-29 16:31:18 -0400373AvbIOResult avb_ab_mark_slot_unbootable(AvbOps* ops, unsigned int slot_number) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400374 AvbABData ab_data, ab_data_orig;
David Zeuthen507752b2016-09-29 16:31:18 -0400375 AvbIOResult ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400376
377 avb_assert(slot_number < 2);
378
David Zeuthen507752b2016-09-29 16:31:18 -0400379 ret = load_metadata(ops, &ab_data, &ab_data_orig);
380 if (ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400381 goto out;
382 }
383
384 slot_set_unbootable(&ab_data.slots[slot_number]);
David Zeuthen507752b2016-09-29 16:31:18 -0400385
386 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400387
388out:
David Zeuthen507752b2016-09-29 16:31:18 -0400389 if (ret == AVB_IO_RESULT_OK) {
390 ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400391 }
392 return ret;
393}
394
David Zeuthen507752b2016-09-29 16:31:18 -0400395AvbIOResult avb_ab_mark_slot_successful(AvbOps* ops, unsigned int slot_number) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400396 AvbABData ab_data, ab_data_orig;
David Zeuthen507752b2016-09-29 16:31:18 -0400397 AvbIOResult ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400398
399 avb_assert(slot_number < 2);
400
David Zeuthen507752b2016-09-29 16:31:18 -0400401 ret = load_metadata(ops, &ab_data, &ab_data_orig);
402 if (ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400403 goto out;
404 }
405
406 if (!slot_is_bootable(&ab_data.slots[slot_number])) {
407 avb_error("Cannot mark unbootable slot as successful.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400408 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400409 goto out;
410 }
411
412 ab_data.slots[slot_number].tries_remaining = 0;
413 ab_data.slots[slot_number].successful_boot = 1;
414
David Zeuthen507752b2016-09-29 16:31:18 -0400415 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400416
417out:
David Zeuthen507752b2016-09-29 16:31:18 -0400418 if (ret == AVB_IO_RESULT_OK) {
419 ret = save_metadata_if_changed(ops, &ab_data, &ab_data_orig);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400420 }
421 return ret;
422}