Add example code for Android Things
Bug: 65385915
Test: Unit tests
Change-Id: I7cc24f02bd4df1b810f3d8b12a3251981fe504f6
diff --git a/Android.bp b/Android.bp
index e8ecaca..646a884 100644
--- a/Android.bp
+++ b/Android.bp
@@ -162,6 +162,13 @@
srcs: ["libavb/avb_sysdeps_posix.c"],
}
+cc_library_host_static {
+ name: "libavb_things_example",
+ defaults: ["avb_defaults"],
+ export_include_dirs: ["."],
+ srcs: ["examples/things/avb_atx_slot_verify.c"],
+}
+
cc_test_host {
name: "libavb_host_unittest",
defaults: ["avb_defaults"],
@@ -174,6 +181,7 @@
"libavb",
"libavb_ab_host",
"libavb_atx_host",
+ "libavb_things_example",
"libgmock_host",
"libgtest_host",
],
@@ -188,6 +196,7 @@
srcs: [
"test/avb_ab_flow_unittest.cc",
"test/avb_atx_validate_unittest.cc",
+ "test/avb_atx_slot_verify_unittest.cc",
"test/avb_slot_verify_unittest.cc",
"test/avb_unittest_util.cc",
"test/avb_util_unittest.cc",
diff --git a/README.md b/README.md
index c07ec7e..41c13be 100644
--- a/README.md
+++ b/README.md
@@ -209,6 +209,9 @@
* `examples/uefi/`
+ Contains the source-code for a UEFI-based boot-loader utilizing
`libavb/` and `libavb_ab/`.
+* `examples/things/`
+ + Contains the source-code for a slot verification suitable for Android
+ Things.
* `README.md`
+ This file.
* `docs/`
diff --git a/examples/things/README.md b/examples/things/README.md
new file mode 100644
index 0000000..45509af
--- /dev/null
+++ b/examples/things/README.md
@@ -0,0 +1,6 @@
+# Android Things Example
+---
+
+This directory contains example source code for an Android Things integration of
+lib_avb and lib_avb_atx. The implementation includes rollback index management
+and Verified Boot Hash (VBH) computation.
diff --git a/examples/things/avb_atx_slot_verify.c b/examples/things/avb_atx_slot_verify.c
new file mode 100644
index 0000000..3129d2e
--- /dev/null
+++ b/examples/things/avb_atx_slot_verify.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "avb_atx_slot_verify.h"
+
+#include <libavb/avb_sha.h>
+#include <libavb/libavb.h>
+#include <libavb_atx/libavb_atx.h>
+
+/* Chosen to be generous but still require a huge number of increase operations
+ * before exhausting the 64-bit space.
+ */
+static const uint64_t kRollbackIndexIncreaseThreshold = 1000000000;
+
+/* By convention, when a rollback index is not used the value remains zero. */
+static const uint64_t kRollbackIndexNotUsed = 0;
+
+typedef struct _AvbAtxOpsContext {
+ size_t key_version_location[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+ uint64_t key_version_value[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+ size_t next_key_version_slot;
+} AvbAtxOpsContext;
+
+typedef struct _AvbAtxOpsWithContext {
+ AvbAtxOps atx_ops;
+ AvbAtxOpsContext context;
+} AvbAtxOpsWithContext;
+
+/* Returns context associated with |atx_ops| returned by
+ * setup_ops_with_context().
+ */
+static AvbAtxOpsContext* get_ops_context(AvbAtxOps* atx_ops) {
+ return &((AvbAtxOpsWithContext*)atx_ops)->context;
+}
+
+/* An implementation of AvbAtxOps::set_key_version that saves the key version
+ * information to ops context data.
+ */
+static void save_key_version_to_context(AvbAtxOps* atx_ops,
+ size_t rollback_index_location,
+ uint64_t key_version) {
+ AvbAtxOpsContext* context = get_ops_context(atx_ops);
+ size_t offset = context->next_key_version_slot++;
+ if (offset < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+ context->key_version_location[offset] = rollback_index_location;
+ context->key_version_value[offset] = key_version;
+ }
+}
+
+/* Attaches context data to |existing_ops| and returns new ops. The
+ * |ops_with_context| will be used to store the new combined ops and context.
+ * The set_key_version function will be replaced in order to collect the key
+ * version information in the context.
+ */
+static AvbAtxOps* setup_ops_with_context(
+ const AvbAtxOps* existing_ops, AvbAtxOpsWithContext* ops_with_context) {
+ avb_memset(ops_with_context, 0, sizeof(AvbAtxOpsWithContext));
+ ops_with_context->atx_ops = *existing_ops;
+ // Close the loop on the circular reference.
+ ops_with_context->atx_ops.ops->atx_ops = &ops_with_context->atx_ops;
+ ops_with_context->atx_ops.set_key_version = save_key_version_to_context;
+ return &ops_with_context->atx_ops;
+}
+
+/* Updates the stored rollback index value for |location| to match |value|. */
+static AvbSlotVerifyResult update_rollback_index(AvbOps* ops,
+ size_t location,
+ uint64_t value) {
+ AvbIOResult io_result = AVB_IO_RESULT_OK;
+ uint64_t current_value;
+ io_result = ops->read_rollback_index(ops, location, ¤t_value);
+ if (io_result == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_result != AVB_IO_RESULT_OK) {
+ avb_error("Error getting rollback index for slot.\n");
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+ if (current_value == value) {
+ // No update necessary.
+ return AVB_SLOT_VERIFY_RESULT_OK;
+ }
+ // The difference between the new and current value must not exceed the
+ // increase threshold, and the value must not decrease.
+ if (value - current_value > kRollbackIndexIncreaseThreshold) {
+ avb_error("Rollback index value cannot increase beyond the threshold.\n");
+ return AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
+ }
+ // This should have been checked during verification, but check again here as
+ // a safeguard.
+ if (value < current_value) {
+ avb_error("Rollback index value cannot decrease.\n");
+ return AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
+ }
+ io_result = ops->write_rollback_index(ops, location, value);
+ if (io_result == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_result != AVB_IO_RESULT_OK) {
+ avb_error("Error setting stored rollback index.\n");
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+ return AVB_SLOT_VERIFY_RESULT_OK;
+}
+
+AvbSlotVerifyResult avb_atx_slot_verify(
+ AvbAtxOps* atx_ops,
+ const char* ab_suffix,
+ AvbAtxLockState lock_state,
+ AvbAtxSlotState slot_state,
+ AvbAtxOemDataState oem_data_state,
+ AvbSlotVerifyData** verify_data,
+ uint8_t vbh_extension[AVB_SHA256_DIGEST_SIZE]) {
+ const char* partitions_without_oem[] = {"boot", NULL};
+ const char* partitions_with_oem[] = {"boot", "oem_bootloader", NULL};
+ AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK;
+ AvbSHA256Ctx ctx;
+ size_t i = 0;
+ AvbAtxOpsWithContext ops_with_context;
+
+ atx_ops = setup_ops_with_context(atx_ops, &ops_with_context);
+
+ result = avb_slot_verify(atx_ops->ops,
+ (oem_data_state == AVB_ATX_OEM_DATA_NOT_USED)
+ ? partitions_without_oem
+ : partitions_with_oem,
+ ab_suffix,
+ (lock_state == AVB_ATX_UNLOCKED)
+ ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+ : AVB_SLOT_VERIFY_FLAGS_NONE,
+ AVB_HASHTREE_ERROR_MODE_EIO,
+ verify_data);
+
+ if (result != AVB_SLOT_VERIFY_RESULT_OK || lock_state == AVB_ATX_UNLOCKED) {
+ return result;
+ }
+
+ /* Compute the Android Things Verified Boot Hash (VBH) extension. */
+ avb_sha256_init(&ctx);
+ for (i = 0; i < (*verify_data)->num_vbmeta_images; i++) {
+ avb_sha256_update(&ctx,
+ (*verify_data)->vbmeta_images[i].vbmeta_data,
+ (*verify_data)->vbmeta_images[i].vbmeta_size);
+ }
+ avb_memcpy(vbh_extension, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE);
+
+ /* Increase rollback index values to match the verified slot. */
+ if (slot_state == AVB_ATX_SLOT_MARKED_SUCCESSFUL) {
+ for (i = 0; i < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; i++) {
+ uint64_t rollback_index_value = (*verify_data)->rollback_indexes[i];
+ if (rollback_index_value != kRollbackIndexNotUsed) {
+ result = update_rollback_index(atx_ops->ops, i, rollback_index_value);
+ if (result != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto out;
+ }
+ }
+ }
+
+ /* Also increase rollback index values for Android Things key version
+ * locations.
+ */
+ for (i = 0; i < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; i++) {
+ size_t rollback_index_location =
+ ops_with_context.context.key_version_location[i];
+ uint64_t rollback_index_value =
+ ops_with_context.context.key_version_value[i];
+ if (rollback_index_value != kRollbackIndexNotUsed) {
+ result = update_rollback_index(
+ atx_ops->ops, rollback_index_location, rollback_index_value);
+ if (result != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto out;
+ }
+ }
+ }
+ }
+
+out:
+ if (result != AVB_SLOT_VERIFY_RESULT_OK) {
+ avb_slot_verify_data_free(*verify_data);
+ *verify_data = NULL;
+ }
+ return result;
+}
diff --git a/examples/things/avb_atx_slot_verify.h b/examples/things/avb_atx_slot_verify.h
new file mode 100644
index 0000000..517b097
--- /dev/null
+++ b/examples/things/avb_atx_slot_verify.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef AVB_ATX_SLOT_VERIFY_H_
+#define AVB_ATX_SLOT_VERIFY_H_
+
+#include <libavb_atx/libavb_atx.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ AVB_ATX_LOCKED,
+ AVB_ATX_UNLOCKED,
+} AvbAtxLockState;
+
+typedef enum {
+ AVB_ATX_SLOT_MARKED_SUCCESSFUL,
+ AVB_ATX_SLOT_NOT_MARKED_SUCCESSFUL,
+} AvbAtxSlotState;
+
+typedef enum {
+ AVB_ATX_OEM_DATA_USED,
+ AVB_ATX_OEM_DATA_NOT_USED,
+} AvbAtxOemDataState;
+
+/* Performs a full verification of the slot identified by |ab_suffix|. If
+ * |lock_state| indicates verified boot is unlocked then verification errors
+ * will be allowed (see AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR for more
+ * details.
+ *
+ * If |slot_state| indicates the slot identified by |ab_suffix| has been marked
+ * successful then minimum rollback index values will be bumped to match the
+ * values in the verified slot (on success).
+ *
+ * If |oem_data_state| indicates that OEM-specific data is not being used, then
+ * verification of the 'oem_bootloader' partition will be skipped and it will
+ * not be represented in |out_data|.
+ *
+ * The semantics of |out_data| are the same as for avb_slot_verify().
+ *
+ * On success, an Android Things |vbh_extension| is populated. This value must
+ * be extended into the Verified Boot Hash value accumulated from earlier boot
+ * stages.
+ *
+ * All of the function pointers in |ops| must be valid except for
+ * set_key_version, which will be ignored and may be NULL.
+ */
+AvbSlotVerifyResult avb_atx_slot_verify(
+ AvbAtxOps* ops,
+ const char* ab_suffix,
+ AvbAtxLockState lock_state,
+ AvbAtxSlotState slot_state,
+ AvbAtxOemDataState oem_data_state,
+ AvbSlotVerifyData** verify_data,
+ uint8_t vbh_extension[AVB_SHA256_DIGEST_SIZE]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SLOT_VERIFY_H_ */
diff --git a/test/avb_atx_slot_verify_unittest.cc b/test/avb_atx_slot_verify_unittest.cc
new file mode 100644
index 0000000..79c1cfd
--- /dev/null
+++ b/test/avb_atx_slot_verify_unittest.cc
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <base/files/file_util.h>
+#include <gtest/gtest.h>
+#include <openssl/sha.h>
+
+#include "avb_unittest_util.h"
+#include "examples/things/avb_atx_slot_verify.h"
+#include "fake_avb_ops.h"
+
+namespace {
+
+const char kMetadataPath[] = "test/data/atx_metadata.bin";
+const char kPermanentAttributesPath[] =
+ "test/data/atx_permanent_attributes.bin";
+const uint64_t kNewRollbackValue = 42;
+
+} /* namespace */
+
+namespace avb {
+
+// A fixture for testing avb_atx_slot_verify() with ATX. This test is
+// parameterized on the initial stored rollback index (same value used in all
+// relevant locations).
+class AvbAtxSlotVerifyExampleTest
+ : public BaseAvbToolTest,
+ public FakeAvbOpsDelegate,
+ public ::testing::WithParamInterface<uint64_t> {
+ public:
+ ~AvbAtxSlotVerifyExampleTest() override = default;
+
+ void SetUp() override {
+ BaseAvbToolTest::SetUp();
+ ReadAtxDefaultData();
+ ops_.set_partition_dir(testdir_);
+ ops_.set_delegate(this);
+ ops_.set_permanent_attributes(attributes_);
+ ops_.set_stored_is_device_unlocked(false);
+ }
+
+ // FakeAvbOpsDelegate methods. All forward to FakeAvbOps default except for
+ // validate_vbmeta_public_key().
+ AvbIOResult read_from_partition(const char* partition,
+ int64_t offset,
+ size_t num_bytes,
+ void* buffer,
+ size_t* out_num_read) override {
+ return ops_.read_from_partition(
+ partition, offset, num_bytes, buffer, out_num_read);
+ }
+
+ AvbIOResult get_preloaded_partition(
+ const char* partition,
+ size_t num_bytes,
+ uint8_t** out_pointer,
+ size_t* out_num_bytes_preloaded) override {
+ return ops_.get_preloaded_partition(
+ partition, num_bytes, out_pointer, out_num_bytes_preloaded);
+ }
+
+ AvbIOResult write_to_partition(const char* partition,
+ int64_t offset,
+ size_t num_bytes,
+ const void* buffer) override {
+ return ops_.write_to_partition(partition, offset, num_bytes, buffer);
+ }
+
+ AvbIOResult validate_vbmeta_public_key(AvbOps* ops,
+ const uint8_t* public_key_data,
+ size_t public_key_length,
+ const uint8_t* public_key_metadata,
+ size_t public_key_metadata_length,
+ bool* out_key_is_trusted) override {
+ // Send to ATX implementation.
+ ++num_atx_calls_;
+ return avb_atx_validate_vbmeta_public_key(ops,
+ public_key_data,
+ public_key_length,
+ public_key_metadata,
+ public_key_metadata_length,
+ out_key_is_trusted);
+ }
+
+ AvbIOResult read_rollback_index(AvbOps* ops,
+ size_t rollback_index_slot,
+ uint64_t* out_rollback_index) override {
+ return ops_.read_rollback_index(
+ ops, rollback_index_slot, out_rollback_index);
+ }
+
+ AvbIOResult write_rollback_index(AvbOps* ops,
+ size_t rollback_index_slot,
+ uint64_t rollback_index) override {
+ num_write_rollback_calls_++;
+ return ops_.write_rollback_index(ops, rollback_index_slot, rollback_index);
+ }
+
+ AvbIOResult read_is_device_unlocked(AvbOps* ops,
+ bool* out_is_device_unlocked) override {
+ return ops_.read_is_device_unlocked(ops, out_is_device_unlocked);
+ }
+
+ AvbIOResult get_unique_guid_for_partition(AvbOps* ops,
+ const char* partition,
+ char* guid_buf,
+ size_t guid_buf_size) override {
+ return ops_.get_unique_guid_for_partition(
+ ops, partition, guid_buf, guid_buf_size);
+ }
+
+ AvbIOResult get_size_of_partition(AvbOps* ops,
+ const char* partition,
+ uint64_t* out_size) override {
+ return ops_.get_size_of_partition(ops, partition, out_size);
+ }
+
+ AvbIOResult read_permanent_attributes(
+ AvbAtxPermanentAttributes* attributes) override {
+ return ops_.read_permanent_attributes(attributes);
+ }
+
+ AvbIOResult read_permanent_attributes_hash(
+ uint8_t hash[AVB_SHA256_DIGEST_SIZE]) override {
+ return ops_.read_permanent_attributes_hash(hash);
+ }
+
+ void set_key_version(size_t rollback_index_location,
+ uint64_t key_version) override {
+ num_key_version_calls_++;
+ return ops_.set_key_version(rollback_index_location, key_version);
+ }
+
+ void RunSlotVerify() {
+ ops_.set_stored_rollback_indexes(
+ {{0, initial_rollback_value_},
+ {AVB_ATX_PIK_VERSION_LOCATION, initial_rollback_value_},
+ {AVB_ATX_PSK_VERSION_LOCATION, initial_rollback_value_}});
+ std::string metadata_option = "--public_key_metadata=";
+ metadata_option += kMetadataPath;
+ GenerateVBMetaImage("vbmeta_a.img",
+ "SHA512_RSA4096",
+ kNewRollbackValue,
+ base::FilePath("test/data/testkey_atx_psk.pem"),
+ metadata_option);
+ SHA256(vbmeta_image_.data(), vbmeta_image_.size(), expected_vbh_extension_);
+
+ ops_.set_expected_public_key(
+ PublicKeyAVB(base::FilePath("test/data/testkey_atx_psk.pem")));
+
+ AvbSlotVerifyData* slot_data = NULL;
+ EXPECT_EQ(expected_result_,
+ avb_atx_slot_verify(ops_.avb_atx_ops(),
+ "_a",
+ lock_state_,
+ slot_state_,
+ oem_data_state_,
+ &slot_data,
+ actual_vbh_extension_));
+ if (expected_result_ == AVB_SLOT_VERIFY_RESULT_OK) {
+ EXPECT_NE(nullptr, slot_data);
+ avb_slot_verify_data_free(slot_data);
+ // Make sure ATX is being run.
+ EXPECT_EQ(1, num_atx_calls_);
+ // Make sure we're hooking set_key_version.
+ EXPECT_EQ(0, num_key_version_calls_);
+ }
+ }
+
+ void CheckVBH() {
+ if (expected_result_ != AVB_SLOT_VERIFY_RESULT_OK ||
+ lock_state_ == AVB_ATX_UNLOCKED) {
+ memset(&expected_vbh_extension_, 0, AVB_SHA256_DIGEST_SIZE);
+ }
+ // Check that the VBH was correctly calculated.
+ EXPECT_EQ(0,
+ memcmp(actual_vbh_extension_,
+ expected_vbh_extension_,
+ AVB_SHA256_DIGEST_SIZE));
+ }
+
+ void CheckNewRollbackState() {
+ uint64_t expected_rollback_value = kNewRollbackValue;
+ if (expected_result_ != AVB_SLOT_VERIFY_RESULT_OK ||
+ lock_state_ == AVB_ATX_UNLOCKED ||
+ slot_state_ != AVB_ATX_SLOT_MARKED_SUCCESSFUL) {
+ // Check that rollback indexes were unmodified.
+ expected_rollback_value = initial_rollback_value_;
+ }
+ // Check that all rollback indexes have the expected value.
+ std::map<size_t, uint64_t> stored_rollback_indexes =
+ ops_.get_stored_rollback_indexes();
+ EXPECT_EQ(expected_rollback_value, stored_rollback_indexes[0]);
+ EXPECT_EQ(expected_rollback_value,
+ stored_rollback_indexes[AVB_ATX_PIK_VERSION_LOCATION]);
+ EXPECT_EQ(expected_rollback_value,
+ stored_rollback_indexes[AVB_ATX_PSK_VERSION_LOCATION]);
+ // Check that if the rollback did not need to change, there were no writes.
+ if (initial_rollback_value_ == kNewRollbackValue ||
+ initial_rollback_value_ == expected_rollback_value) {
+ EXPECT_EQ(0, num_write_rollback_calls_);
+ } else {
+ EXPECT_NE(0, num_write_rollback_calls_);
+ }
+ }
+
+ protected:
+ FakeAvbOps ops_;
+ AvbAtxPermanentAttributes attributes_;
+ int num_atx_calls_ = 0;
+ int num_key_version_calls_ = 0;
+ int num_write_rollback_calls_ = 0;
+ AvbSlotVerifyResult expected_result_ = AVB_SLOT_VERIFY_RESULT_OK;
+ uint64_t initial_rollback_value_ = 0;
+ AvbAtxLockState lock_state_ = AVB_ATX_LOCKED;
+ AvbAtxSlotState slot_state_ = AVB_ATX_SLOT_MARKED_SUCCESSFUL;
+ AvbAtxOemDataState oem_data_state_ = AVB_ATX_OEM_DATA_NOT_USED;
+ uint8_t expected_vbh_extension_[AVB_SHA256_DIGEST_SIZE] = {};
+ uint8_t actual_vbh_extension_[AVB_SHA256_DIGEST_SIZE] = {};
+
+ private:
+ void ReadAtxDefaultData() {
+ std::string tmp;
+ ASSERT_TRUE(
+ base::ReadFileToString(base::FilePath(kPermanentAttributesPath), &tmp));
+ ASSERT_EQ(tmp.size(), sizeof(AvbAtxPermanentAttributes));
+ memcpy(&attributes_, tmp.data(), tmp.size());
+ }
+};
+
+TEST_P(AvbAtxSlotVerifyExampleTest, RunWithStartingIndex) {
+ initial_rollback_value_ = GetParam();
+ RunSlotVerify();
+ CheckVBH();
+ CheckNewRollbackState();
+}
+
+INSTANTIATE_TEST_CASE_P(P,
+ AvbAtxSlotVerifyExampleTest,
+ ::testing::Values(0,
+ 1,
+ kNewRollbackValue / 2,
+ kNewRollbackValue - 1,
+ kNewRollbackValue));
+
+TEST_F(AvbAtxSlotVerifyExampleTest, RunUnlocked) {
+ lock_state_ = AVB_ATX_UNLOCKED;
+ RunSlotVerify();
+ CheckVBH();
+ CheckNewRollbackState();
+}
+
+TEST_F(AvbAtxSlotVerifyExampleTest, RunWithSlotNotMarkedSuccessful) {
+ slot_state_ = AVB_ATX_SLOT_NOT_MARKED_SUCCESSFUL;
+ RunSlotVerify();
+ CheckVBH();
+ CheckNewRollbackState();
+}
+
+TEST_F(AvbAtxSlotVerifyExampleTest, RunWithOemData) {
+ oem_data_state_ = AVB_ATX_OEM_DATA_USED;
+ RunSlotVerify();
+ CheckVBH();
+ CheckNewRollbackState();
+}
+
+} // namespace avb