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