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