summaryrefslogtreecommitdiff
path: root/lib/avb/libavb_ab/avb_ab_flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avb/libavb_ab/avb_ab_flow.c')
-rw-r--r--lib/avb/libavb_ab/avb_ab_flow.c145
1 files changed, 107 insertions, 38 deletions
diff --git a/lib/avb/libavb_ab/avb_ab_flow.c b/lib/avb/libavb_ab/avb_ab_flow.c
index c6a37a9..3adb927 100644
--- a/lib/avb/libavb_ab/avb_ab_flow.c
+++ b/lib/avb/libavb_ab/avb_ab_flow.c
@@ -81,14 +81,17 @@ void avb_ab_data_init(AvbABData* data) {
#define AB_METADATA_MISC_PARTITION_OFFSET 2048
AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
- AvbOps* ops = &(ab_ops->ops);
+ AvbOps* ops = ab_ops->ops;
AvbABData serialized;
AvbIOResult io_ret;
size_t num_bytes_read;
- io_ret =
- ops->read_from_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET,
- sizeof(AvbABData), &serialized, &num_bytes_read);
+ io_ret = ops->read_from_partition(ops,
+ "misc",
+ AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ &serialized,
+ &num_bytes_read);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
return AVB_IO_RESULT_ERROR_OOM;
} else if (io_ret != AVB_IO_RESULT_OK ||
@@ -109,14 +112,16 @@ AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
}
AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) {
- AvbOps* ops = &(ab_ops->ops);
+ AvbOps* ops = ab_ops->ops;
AvbABData serialized;
AvbIOResult io_ret;
avb_ab_data_update_crc_and_byteswap(data, &serialized);
- io_ret =
- ops->write_to_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET,
- sizeof(AvbABData), &serialized);
+ io_ret = ops->write_to_partition(ops,
+ "misc",
+ AB_METADATA_MISC_PARTITION_OFFSET,
+ sizeof(AvbABData),
+ &serialized);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
return AVB_IO_RESULT_ERROR_OOM;
} else if (io_ret != AVB_IO_RESULT_OK) {
@@ -163,7 +168,8 @@ static const char* slot_suffixes[2] = {"_a", "_b"};
/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
* success, error code otherwise.
*/
-static AvbIOResult load_metadata(AvbABOps* ab_ops, AvbABData* ab_data,
+static AvbIOResult load_metadata(AvbABOps* ab_ops,
+ AvbABData* ab_data,
AvbABData* ab_data_orig) {
AvbIOResult io_ret;
@@ -198,15 +204,16 @@ static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
const char* const* requested_partitions,
+ bool allow_verification_error,
AvbSlotVerifyData** out_data) {
- AvbOps* ops = &(ab_ops->ops);
+ AvbOps* ops = ab_ops->ops;
AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
AvbSlotVerifyData* data = NULL;
AvbABFlowResult ret;
AvbABData ab_data, ab_data_orig;
size_t slot_index_to_boot, n;
- bool is_device_unlocked;
AvbIOResult io_ret;
+ bool saw_and_allowed_verification_error = false;
io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
@@ -221,20 +228,58 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
for (n = 0; n < 2; n++) {
if (slot_is_bootable(&ab_data.slots[n])) {
AvbSlotVerifyResult verify_result;
- verify_result = avb_slot_verify(ops, requested_partitions,
- slot_suffixes[n], &slot_data[n]);
- if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
- if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_OOM) {
+ bool set_slot_unbootable = false;
+
+ verify_result = avb_slot_verify(ops,
+ requested_partitions,
+ slot_suffixes[n],
+ allow_verification_error,
+ &slot_data[n]);
+ switch (verify_result) {
+ case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
goto out;
- }
- if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_IO) {
+
+ case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
ret = AVB_AB_FLOW_RESULT_ERROR_IO;
goto out;
- }
- avb_errorv("Error verifying slot ", slot_suffixes[n], " with result ",
+
+ case AVB_SLOT_VERIFY_RESULT_OK:
+ break;
+
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+ /* Even with |allow_verification_error| these mean game over. */
+ set_slot_unbootable = true;
+ break;
+
+ /* explicit fallthrough. */
+ case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+ if (allow_verification_error) {
+ /* Do nothing since we allow this. */
+ avb_debugv("Allowing slot ",
+ slot_suffixes[n],
+ " which verified "
+ "with result ",
+ avb_slot_verify_result_to_string(verify_result),
+ " because |allow_verification_error| is true.\n",
+ NULL);
+ saw_and_allowed_verification_error = true;
+ } else {
+ set_slot_unbootable = true;
+ }
+ break;
+ }
+
+ if (set_slot_unbootable) {
+ avb_errorv("Error verifying slot ",
+ slot_suffixes[n],
+ " with result ",
avb_slot_verify_result_to_string(verify_result),
- " - setting unbootable.\n", NULL);
+ " - setting unbootable.\n",
+ NULL);
slot_set_unbootable(&ab_data.slots[n]);
}
}
@@ -260,9 +305,9 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
/* Update stored rollback index such that the stored rollback index
* is the largest value supporting all currently bootable slots. Do
- * this for every rollback index slot.
+ * this for every rollback index location.
*/
- for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) {
+ for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
uint64_t rollback_index_value = 0;
if (slot_data[0] != NULL && slot_data[1] != NULL) {
@@ -306,7 +351,12 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
avb_assert(slot_data[slot_index_to_boot] != NULL);
data = slot_data[slot_index_to_boot];
slot_data[slot_index_to_boot] = NULL;
- ret = AVB_AB_FLOW_RESULT_OK;
+ if (saw_and_allowed_verification_error) {
+ avb_assert(allow_verification_error);
+ ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
+ } else {
+ ret = AVB_AB_FLOW_RESULT_OK;
+ }
/* ... and decrement tries remaining, if applicable. */
if (!ab_data.slots[slot_index_to_boot].successful_boot &&
@@ -315,20 +365,6 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
}
out:
- /* do not touch metadata in UNLOCK state */
- io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
- if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
- ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
- goto fail;
- } else if (io_ret != AVB_IO_RESULT_OK) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
- avb_error("Error getting device state.\n");
- goto fail;
- }
- if (is_device_unlocked)
- goto ret;
-
-fail:
io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
if (io_ret != AVB_IO_RESULT_OK) {
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
@@ -342,7 +378,6 @@ fail:
}
}
-ret:
for (n = 0; n < 2; n++) {
if (slot_data[n] != NULL) {
avb_slot_verify_data_free(slot_data[n]);
@@ -445,3 +480,37 @@ out:
}
return ret;
}
+
+const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
+ const char* ret = NULL;
+
+ switch (result) {
+ case AVB_AB_FLOW_RESULT_OK:
+ ret = "OK";
+ break;
+
+ case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
+ ret = "OK_WITH_VERIFICATION_ERROR";
+ break;
+
+ case AVB_AB_FLOW_RESULT_ERROR_OOM:
+ ret = "ERROR_OOM";
+ break;
+
+ case AVB_AB_FLOW_RESULT_ERROR_IO:
+ ret = "ERROR_IO";
+ break;
+
+ case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
+ ret = "ERROR_NO_BOOTABLE_SLOTS";
+ break;
+ /* Do not add a 'default:' case here because of -Wswitch. */
+ }
+
+ if (ret == NULL) {
+ avb_error("Unknown AvbABFlowResult value.\n");
+ ret = "(unknown)";
+ }
+
+ return ret;
+}