Extend SMM Variable function support
Extends base SMM Variable functions to support EDK2 specific
functions for setting and getting variable check properties and
for getting the maximum payload size. Includes the checking
of constraints specified by variable check properties. Component
and service level tests are extended to cover the new
functionality.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I9a48908caf2b72d490270a32e2e7ad618b7b6707
diff --git a/components/service/smm_variable/backend/component.cmake b/components/service/smm_variable/backend/component.cmake
index 7573a81..8a857b9 100644
--- a/components/service/smm_variable/backend/component.cmake
+++ b/components/service/smm_variable/backend/component.cmake
@@ -12,4 +12,5 @@
"${CMAKE_CURRENT_LIST_DIR}/uefi_variable_store.c"
"${CMAKE_CURRENT_LIST_DIR}/variable_index.c"
"${CMAKE_CURRENT_LIST_DIR}/variable_index_iterator.c"
+ "${CMAKE_CURRENT_LIST_DIR}/variable_checker.c"
)
diff --git a/components/service/smm_variable/backend/test/variable_index_tests.cpp b/components/service/smm_variable/backend/test/variable_index_tests.cpp
index ef55ef7..9671e6e 100644
--- a/components/service/smm_variable/backend/test/variable_index_tests.cpp
+++ b/components/service/smm_variable/backend/test/variable_index_tests.cpp
@@ -71,7 +71,7 @@
{
const struct variable_info *info = NULL;
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid_1,
name_1.size() * sizeof(int16_t),
@@ -80,7 +80,7 @@
CHECK_TRUE(info);
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid_2,
name_2.size() * sizeof(int16_t),
@@ -89,7 +89,7 @@
CHECK_TRUE(info);
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid_1,
name_3.size() * sizeof(int16_t),
@@ -130,7 +130,7 @@
POINTERS_EQUAL(NULL, info);
/* Remove should silently return */
- variable_index_remove(
+ variable_index_remove_variable(
&m_variable_index,
info);
}
@@ -142,7 +142,7 @@
name = to_variable_name(L"a long variable name that exceeds the length limit");
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid_1,
name.size() * sizeof(int16_t),
@@ -154,7 +154,7 @@
name = to_variable_name(L"a long variable name that fits!");
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid_1,
name.size() * sizeof(int16_t),
@@ -173,7 +173,7 @@
/* Expect to be able to fill the index */
for (size_t i = 0; i < MAX_VARIABLES; ++i) {
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid,
name_1.size() * sizeof(int16_t),
@@ -187,7 +187,7 @@
}
/* Variable index should now be full */
- info = variable_index_add(
+ info = variable_index_add_variable(
&m_variable_index,
&guid,
name_1.size() * sizeof(int16_t),
@@ -211,41 +211,41 @@
null_name.size() * sizeof(int16_t),
null_name.data());
CHECK_TRUE(info);
- LONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->attributes);
- MEMCMP_EQUAL(&guid_1, &info->guid, sizeof(EFI_GUID));
- MEMCMP_EQUAL(name_1.data(), info->name, name_1.size());
+ LONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
+ MEMCMP_EQUAL(&guid_1, &info->metadata.guid, sizeof(EFI_GUID));
+ MEMCMP_EQUAL(name_1.data(), info->metadata.name, name_1.size());
info = variable_index_find_next(
&m_variable_index,
- &info->guid,
- info->name_size,
- info->name);
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
CHECK_TRUE(info);
- LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, info->attributes);
- MEMCMP_EQUAL(&guid_2, &info->guid, sizeof(EFI_GUID));
- MEMCMP_EQUAL(name_2.data(), info->name, name_2.size());
+ LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
+ MEMCMP_EQUAL(&guid_2, &info->metadata.guid, sizeof(EFI_GUID));
+ MEMCMP_EQUAL(name_2.data(), info->metadata.name, name_2.size());
info = variable_index_find_next(
&m_variable_index,
- &info->guid,
- info->name_size,
- info->name);
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
CHECK_TRUE(info);
- LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS, info->attributes);
- MEMCMP_EQUAL(&guid_1, &info->guid, sizeof(EFI_GUID));
- MEMCMP_EQUAL(name_3.data(), info->name, name_3.size());
+ LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS, info->metadata.attributes);
+ MEMCMP_EQUAL(&guid_1, &info->metadata.guid, sizeof(EFI_GUID));
+ MEMCMP_EQUAL(name_3.data(), info->metadata.name, name_3.size());
info = variable_index_find_next(
&m_variable_index,
- &info->guid,
- info->name_size,
- info->name);
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
POINTERS_EQUAL(NULL, info);
}
TEST(UefiVariableIndexTests, dumpLoadRoadtrip)
{
- uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_info)];
+ uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_metadata)];
create_variables();
@@ -254,14 +254,14 @@
bool is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
CHECK_TRUE(is_dirty);
- UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 2), dump_len);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 2), dump_len);
/* Expect no records to be dirty when the dump is repeated */
dump_len = 0;
is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
CHECK_FALSE(is_dirty);
- UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 2), dump_len);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 2), dump_len);
/* Tear down and reinitialize to simulate a reboot */
variable_index_deinit(&m_variable_index);
@@ -283,28 +283,28 @@
null_name.data());
CHECK_TRUE(info);
UNSIGNED_LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- info->attributes);
+ info->metadata.attributes);
info = variable_index_find_next(
&m_variable_index,
- &info->guid,
- info->name_size,
- info->name);
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
CHECK_TRUE(info);
UNSIGNED_LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS,
- info->attributes);
+ info->metadata.attributes);
info = variable_index_find_next(
&m_variable_index,
- &info->guid,
- info->name_size,
- info->name);
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
POINTERS_EQUAL(NULL, info);
}
TEST(UefiVariableIndexTests, dumpBufferTooSmall)
{
- uint8_t buffer[1 * sizeof(struct variable_info) + 1];
+ uint8_t buffer[1 * sizeof(struct variable_metadata) + 1];
create_variables();
@@ -316,13 +316,13 @@
bool is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
CHECK_TRUE(is_dirty);
- UNSIGNED_LONGS_EQUAL(sizeof(struct variable_info) * 1, dump_len);
+ UNSIGNED_LONGS_EQUAL(sizeof(struct variable_metadata) * 1, dump_len);
}
TEST(UefiVariableIndexTests, removeVariable)
{
- uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_info)];
+ uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_metadata)];
const struct variable_info *info = NULL;
create_variables();
@@ -334,7 +334,7 @@
name_2.size() * sizeof(int16_t),
name_2.data());
- variable_index_remove(
+ variable_index_remove_variable(
&m_variable_index,
info);
@@ -343,7 +343,7 @@
bool is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
CHECK_TRUE(is_dirty);
- UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 1), dump_len);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 1), dump_len);
/* Remove the volatile variable */
info = variable_index_find(
@@ -352,7 +352,7 @@
name_1.size() * sizeof(int16_t),
name_1.data());
- variable_index_remove(
+ variable_index_remove_variable(
&m_variable_index,
info);
@@ -361,7 +361,7 @@
is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
CHECK_FALSE(is_dirty);
- UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 1), dump_len);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 1), dump_len);
/* Remove the remaining NV variable */
info = variable_index_find(
@@ -370,7 +370,7 @@
name_3.size() * sizeof(int16_t),
name_3.data());
- variable_index_remove(
+ variable_index_remove_variable(
&m_variable_index,
info);
@@ -379,14 +379,7 @@
is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
CHECK_TRUE(is_dirty);
- UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 0), dump_len);
-
- /* Repeat the remove on an empty index. This should have no effect on the empty state
- * of the index.
- */
- variable_index_remove(
- &m_variable_index,
- info);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_metadata) * 0), dump_len);
/* Enumerate and now expect an empty index */
info = NULL;
@@ -414,8 +407,8 @@
/* Check first entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->name_size);
- MEMCMP_EQUAL(name_1.data(), info->name, info->name_size);
+ UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
variable_index_iterator_next(&iter);
CHECK_FALSE(variable_index_iterator_is_done(&iter));
@@ -423,8 +416,8 @@
/* Check next is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_2.size() * sizeof(int16_t), info->name_size);
- MEMCMP_EQUAL(name_2.data(), info->name, info->name_size);
+ UNSIGNED_LONGS_EQUAL(name_2.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
const struct variable_info *info_to_remove = info;
@@ -434,15 +427,15 @@
/* Check next is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->name_size);
- MEMCMP_EQUAL(name_3.data(), info->name, info->name_size);
+ UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
/* Expect iterating to be done */
variable_index_iterator_next(&iter);
CHECK_TRUE(variable_index_iterator_is_done(&iter));
/* Now remove the middle entry */
- variable_index_remove(&m_variable_index, info_to_remove);
+ variable_index_remove_variable(&m_variable_index, info_to_remove);
/* Iterate again but this time there should only be two entries */
variable_index_iterator_first(&iter, &m_variable_index);
@@ -451,8 +444,8 @@
/* Check first entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->name_size);
- MEMCMP_EQUAL(name_1.data(), info->name, info->name_size);
+ UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
variable_index_iterator_next(&iter);
CHECK_FALSE(variable_index_iterator_is_done(&iter));
@@ -460,10 +453,171 @@
/* Check next entry is as expected */
info = variable_index_iterator_current(&iter);
CHECK_TRUE(info);
- UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->name_size);
- MEMCMP_EQUAL(name_3.data(), info->name, info->name_size);
+ UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
/* Expect iterating to be done */
variable_index_iterator_next(&iter);
CHECK_TRUE(variable_index_iterator_is_done(&iter));
}
+
+TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
+{
+ /* Variable check constraints are set using an independent SMM
+ * function from setting a variable. A client may set constraints
+ * for an existing variable or a non-existing one. This test case
+ * covers setting check constraints for an existing variable.
+ */
+ create_variables();
+
+ struct variable_constraints constraints;
+ constraints.revision = 10;
+ constraints.property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ constraints.attributes = 0;
+ constraints.min_size = 1;
+ constraints.max_size = 100;
+
+ /* Set check constraints on one of the variables */
+ const struct variable_info *info = variable_index_find(
+ &m_variable_index,
+ &guid_2,
+ name_2.size() * sizeof(int16_t),
+ name_2.data());
+
+ CHECK_TRUE(info);
+ CHECK_TRUE(info->is_variable_set);
+ CHECK_FALSE(info->is_constraints_set);
+
+ variable_index_update_constraints(info, &constraints);
+
+ CHECK_TRUE(info->is_constraints_set);
+ CHECK_TRUE(info->is_variable_set);
+
+ /* Remove the variable but still expect the variable to be indexed
+ * because of the set constraints.
+ */
+ variable_index_remove_variable(
+ &m_variable_index,
+ info);
+
+ info = variable_index_find(
+ &m_variable_index,
+ &guid_2,
+ name_2.size() * sizeof(int16_t),
+ name_2.data());
+
+ CHECK_TRUE(info);
+ CHECK_FALSE(info->is_variable_set);
+ CHECK_TRUE(info->is_constraints_set);
+
+ /* Enumerate over variables, only expecting to find the two remaining 'set' variables. */
+ info = NULL;
+ std::vector<int16_t> null_name = to_variable_name(L"");
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &guid_1,
+ null_name.size() * sizeof(int16_t),
+ null_name.data());
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS,
+ info->metadata.attributes);
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->metadata.guid,
+ info->metadata.name_size,
+ info->metadata.name);
+ CHECK_FALSE(info);
+
+ /* Iterating over the index should still return all three because the set constraints
+ * for variable 2 still persist.
+ */
+ struct variable_index_iterator iter;
+
+ variable_index_iterator_first(&iter, &m_variable_index);
+ CHECK_FALSE(variable_index_iterator_is_done(&iter));
+
+ /* Check first entry is as expected */
+ info = variable_index_iterator_current(&iter);
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(name_1.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
+
+ variable_index_iterator_next(&iter);
+ CHECK_FALSE(variable_index_iterator_is_done(&iter));
+
+ /* Check next is as expected */
+ info = variable_index_iterator_current(&iter);
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(name_2.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
+
+ variable_index_iterator_next(&iter);
+ CHECK_FALSE(variable_index_iterator_is_done(&iter));
+
+ /* Check next is as expected */
+ info = variable_index_iterator_current(&iter);
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(name_3.size() * sizeof(int16_t), info->metadata.name_size);
+ MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
+
+ /* Expect iterating to be done */
+ variable_index_iterator_next(&iter);
+ CHECK_TRUE(variable_index_iterator_is_done(&iter));
+}
+
+TEST(UefiVariableIndexTests, setCheckConstraintsNonExistingVar)
+{
+ /* This test case covers setting check constraints for a variable
+ * that hasn't been set yet.
+ */
+ struct variable_constraints constraints;
+ constraints.revision = 10;
+ constraints.property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ constraints.attributes = 0;
+ constraints.min_size = 1;
+ constraints.max_size = 100;
+
+ /* Initially expect no variable_info */
+ const struct variable_info *info = variable_index_find(
+ &m_variable_index,
+ &guid_2,
+ name_2.size() * sizeof(int16_t),
+ name_2.data());
+
+ CHECK_FALSE(info);
+
+ /* Adding the check constraints should result in an entry being added */
+ info = variable_index_add_constraints(
+ &m_variable_index,
+ &guid_2,
+ name_2.size() * sizeof(int16_t),
+ name_2.data(),
+ &constraints);
+
+ CHECK_TRUE(info);
+ CHECK_FALSE(info->is_variable_set);
+ CHECK_TRUE(info->is_constraints_set);
+
+ /* Updating the variable should cause the variable to be marked as set */
+ variable_index_update_variable(info, EFI_VARIABLE_RUNTIME_ACCESS);
+
+ CHECK_TRUE(info->is_variable_set);
+ CHECK_TRUE(info->is_constraints_set);
+
+ /* Check the constraints are as expected */
+ UNSIGNED_LONGS_EQUAL(constraints.revision, info->check_constraints.revision);
+ UNSIGNED_LONGS_EQUAL(constraints.property, info->check_constraints.property);
+ UNSIGNED_LONGS_EQUAL(constraints.attributes, info->check_constraints.attributes);
+ UNSIGNED_LONGS_EQUAL(constraints.min_size, info->check_constraints.min_size);
+ UNSIGNED_LONGS_EQUAL(constraints.max_size, info->check_constraints.max_size);
+}
diff --git a/components/service/smm_variable/backend/test/variable_store_tests.cpp b/components/service/smm_variable/backend/test/variable_store_tests.cpp
index b306415..07b6846 100644
--- a/components/service/smm_variable/backend/test/variable_store_tests.cpp
+++ b/components/service/smm_variable/backend/test/variable_store_tests.cpp
@@ -152,6 +152,30 @@
return status;
}
+ efi_status_t set_check_var_property(
+ const std::wstring &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property)
+ {
+ std::vector<int16_t> var_name = to_variable_name(name);
+ size_t name_size = var_name.size() * sizeof(int16_t);
+ uint8_t msg_buffer[SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY_SIZE(name_size)];
+
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *check_var =
+ (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY*)msg_buffer;
+
+ check_var->Guid = m_common_guid;
+ check_var->NameSize = name_size;
+ memcpy(check_var->Name, var_name.data(), name_size);
+
+ check_var->VariableProperty = check_property;
+
+ efi_status_t status = uefi_variable_store_set_var_check_property(
+ &m_uefi_variable_store,
+ check_var);
+
+ return status;
+ }
+
void zap_stored_variable(
const std::wstring &name)
{
@@ -169,14 +193,14 @@
name_size,
var_name.data());
- if (info && (info->attributes & EFI_VARIABLE_NON_VOLATILE)) {
+ if (info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
struct storage_backend *storage_backend = m_uefi_variable_store.persistent_store;
storage_backend->interface->remove(
storage_backend->context,
OWNER_ID,
- info->uid);
+ info->metadata.uid);
}
}
@@ -528,3 +552,81 @@
&total_len);
UNSIGNED_LONGS_EQUAL(EFI_NOT_FOUND, status);
}
+
+TEST(UefiVariableStoreTests, readOnlycheck)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name_1 = L"test_variable_1";
+ std::string input_data = "blah blah";
+
+ /* Add a variable */
+ status = set_variable(
+ var_name_1,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Apply a check to constrain to Read Only */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ check_property.MinSize = 0;
+ check_property.MaxSize = 100;
+
+ status = set_check_var_property(var_name_1, check_property);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Subsequent set operations should fail */
+ status = set_variable(
+ var_name_1,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_WRITE_PROTECTED, status);
+}
+
+TEST(UefiVariableStoreTests, noRemoveCheck)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name_1 = L"test_variable_1";
+ std::string input_data = "blah blah";
+
+ /* Add a variable */
+ status = set_variable(
+ var_name_1,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Apply a check to constrain size to > 0. This should prevent removal */
+ VAR_CHECK_VARIABLE_PROPERTY check_property;
+ check_property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ check_property.Attributes = 0;
+ check_property.Property = 0;
+ check_property.MinSize = 1;
+ check_property.MaxSize = 10;
+
+ status = set_check_var_property(var_name_1, check_property);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Try and remove by setting with zero length data */
+ status = set_variable(
+ var_name_1,
+ std::string(),
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_INVALID_PARAMETER, status);
+
+ /* Setting with non zero data should work */
+ status = set_variable(
+ var_name_1,
+ std::string("Good"),
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* But with data that exceeds the MaxSize */
+ status = set_variable(
+ var_name_1,
+ std::string("A data value that exceeds the MaxSize"),
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_INVALID_PARAMETER, status);
+}
diff --git a/components/service/smm_variable/backend/uefi_variable_store.c b/components/service/smm_variable/backend/uefi_variable_store.c
index 7d700f9..bb28f5d 100644
--- a/components/service/smm_variable/backend/uefi_variable_store.c
+++ b/components/service/smm_variable/backend/uefi_variable_store.c
@@ -10,6 +10,7 @@
#include <string.h>
#include "uefi_variable_store.h"
#include "variable_index_iterator.h"
+#include "variable_checker.h"
/* Private functions */
static void load_variable_index(
@@ -22,6 +23,11 @@
const struct uefi_variable_store *context,
const struct variable_info *info);
+static efi_status_t check_access_permitted_on_set(
+ const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
+
static efi_status_t store_variable_data(
struct uefi_variable_store *context,
const struct variable_info *info,
@@ -118,18 +124,19 @@
if (info) {
- /* Variable already exists */
- status = check_access_permitted(context, info);
+ /* Variable info already exists */
+ status = check_access_permitted_on_set(context, info, var);
if (status == EFI_SUCCESS) {
- should_sync_index = (info->attributes & EFI_VARIABLE_NON_VOLATILE);
+ should_sync_index =
+ (var->Attributes & EFI_VARIABLE_NON_VOLATILE) ||
+ (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE));
if (var->DataSize) {
- /* It's an update to an existing variable */
- variable_index_update_attributes(
- &context->variable_index,
+ /* It's a set rather than a remove operation */
+ variable_index_update_variable(
info,
var->Attributes);
}
@@ -142,7 +149,7 @@
* the storage backend without a corresponding index entry.
*/
remove_variable_data(context, info);
- variable_index_remove(&context->variable_index, info);
+ variable_index_remove_variable(&context->variable_index, info);
/* Variable info no longer valid */
info = NULL;
@@ -157,14 +164,15 @@
else if (var->DataSize) {
/* It's a new variable */
- info = variable_index_add(
+ info = variable_index_add_variable(
&context->variable_index,
&var->Guid,
var->NameSize,
var->Name,
var->Attributes);
- should_sync_index = info && (info->attributes & EFI_VARIABLE_NON_VOLATILE);
+ if (!info) status = EFI_OUT_OF_RESOURCES;
+ should_sync_index = info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
}
/* The order of these operations is important. For an update
@@ -207,7 +215,7 @@
var->NameSize,
var->Name);
- if (info) {
+ if (info && info->is_variable_set) {
/* Variable already exists */
status = check_access_permitted(context, info);
@@ -215,7 +223,7 @@
if (status == EFI_SUCCESS) {
status = load_variable_data(context, info, var, max_data_len);
- var->Attributes = info->attributes;
+ var->Attributes = info->metadata.attributes;
*total_length = SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(var);
}
}
@@ -241,11 +249,11 @@
cur->NameSize,
cur->Name);
- if (info && (info->name_size <= max_name_len)) {
+ if (info && (info->metadata.name_size <= max_name_len)) {
- cur->Guid = info->guid;
- cur->NameSize = info->name_size;
- memcpy(cur->Name, info->name, info->name_size);
+ cur->Guid = info->metadata.guid;
+ cur->NameSize = info->metadata.name_size;
+ memcpy(cur->Name, info->metadata.name, info->metadata.name_size);
*total_length = SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(cur);
@@ -272,6 +280,91 @@
return EFI_SUCCESS;
}
+efi_status_t uefi_variable_store_set_var_check_property(
+ struct uefi_variable_store *context,
+ const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property)
+{
+ efi_status_t status = check_name_terminator(property->Name, property->NameSize);
+ if (status != EFI_SUCCESS) return status;
+
+ /* Find in index */
+ const struct variable_info *info = variable_index_find(
+ &context->variable_index,
+ &property->Guid,
+ property->NameSize,
+ property->Name);
+
+ if (info) {
+
+ /* Applying check constraints to an existing variable that may have
+ * constraints already set. These could constrain the setting of
+ * the constraints.
+ */
+ struct variable_constraints constraints = info->check_constraints;
+
+ status = variable_checker_set_constraints(
+ &constraints,
+ info->is_constraints_set,
+ &property->VariableProperty);
+
+ if (status == EFI_SUCCESS) {
+
+ variable_index_update_constraints(info, &constraints);
+ }
+ }
+ else {
+
+ /* Applying check constraints for a new variable */
+ struct variable_constraints constraints;
+
+ status = variable_checker_set_constraints(
+ &constraints,
+ false,
+ &property->VariableProperty);
+
+ if (status == EFI_SUCCESS) {
+
+ info = variable_index_add_constraints(
+ &context->variable_index,
+ &property->Guid,
+ property->NameSize,
+ property->Name,
+ &constraints);
+
+ if (!info) status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return status;
+}
+
+efi_status_t uefi_variable_store_get_var_check_property(
+ struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property)
+{
+ efi_status_t status = check_name_terminator(property->Name, property->NameSize);
+ if (status != EFI_SUCCESS) return status;
+
+ status = EFI_NOT_FOUND;
+
+ const struct variable_info *info = variable_index_find(
+ &context->variable_index,
+ &property->Guid,
+ property->NameSize,
+ property->Name);
+
+ if (info && info->is_constraints_set) {
+
+ variable_checker_get_constraints(
+ &info->check_constraints,
+ &property->VariableProperty);
+
+ status = EFI_SUCCESS;
+ }
+
+ return status;
+}
+
static void load_variable_index(
struct uefi_variable_store *context)
{
@@ -338,13 +431,35 @@
{
efi_status_t status = EFI_SUCCESS;
- if (info->attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
+ if (info->is_variable_set) {
- if (!context->is_boot_service) status = EFI_ACCESS_DENIED;
+ if (info->metadata.attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
+
+ if (!context->is_boot_service) status = EFI_ACCESS_DENIED;
+ }
+ else if (info->metadata.attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
+
+ if (context->is_boot_service) status = EFI_ACCESS_DENIED;
+ }
}
- else if (info->attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
- if (context->is_boot_service) status = EFI_ACCESS_DENIED;
+ return status;
+}
+
+static efi_status_t check_access_permitted_on_set(
+ const struct uefi_variable_store *context,
+ const struct variable_info *info,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+{
+ efi_status_t status = check_access_permitted(context, info);
+
+ if ((status == EFI_SUCCESS) && info->is_constraints_set) {
+
+ /* Apply check constraints */
+ status = variable_checker_check_on_set(
+ &info->check_constraints,
+ var->Attributes,
+ var->DataSize);
}
return status;
@@ -360,7 +475,7 @@
const uint8_t *data = (const uint8_t*)var +
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
- bool is_nv = (info->attributes & EFI_VARIABLE_NON_VOLATILE);
+ bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
struct storage_backend *storage_backend = (is_nv) ?
context->persistent_store :
@@ -371,7 +486,7 @@
psa_status = storage_backend->interface->set(
storage_backend->context,
context->owner_id,
- info->uid,
+ info->metadata.uid,
data_len,
data,
PSA_STORAGE_FLAG_NONE);
@@ -393,18 +508,22 @@
const struct variable_info *info)
{
psa_status_t psa_status = PSA_SUCCESS;
- bool is_nv = (info->attributes & EFI_VARIABLE_NON_VOLATILE);
- struct storage_backend *storage_backend = (is_nv) ?
- context->persistent_store :
- context->volatile_store;
+ if (info->is_variable_set) {
- if (storage_backend) {
+ bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
- psa_status = storage_backend->interface->remove(
- storage_backend->context,
- context->owner_id,
- info->uid);
+ struct storage_backend *storage_backend = (is_nv) ?
+ context->persistent_store :
+ context->volatile_store;
+
+ if (storage_backend) {
+
+ psa_status = storage_backend->interface->remove(
+ storage_backend->context,
+ context->owner_id,
+ info->metadata.uid);
+ }
}
return psa_to_efi_storage_status(psa_status);
@@ -421,7 +540,7 @@
uint8_t *data = (uint8_t*)var +
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
- bool is_nv = (info->attributes & EFI_VARIABLE_NON_VOLATILE);
+ bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
struct storage_backend *storage_backend = (is_nv) ?
context->persistent_store :
@@ -432,7 +551,7 @@
psa_status = storage_backend->interface->get(
storage_backend->context,
context->owner_id,
- info->uid,
+ info->metadata.uid,
0,
max_data_len,
data,
@@ -453,14 +572,14 @@
/* Iterate over variable index looking for any entries for NV
* variables where there is no corresponding object in the
- * persistent store. This condition could arrise due to
+ * persistent store. This condition could arise due to
* a power failure before an object is stored.
*/
while (!variable_index_iterator_is_done(&iter)) {
const struct variable_info *info = variable_index_iterator_current(&iter);
- if (info->attributes & EFI_VARIABLE_NON_VOLATILE) {
+ if (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
struct psa_storage_info_t storage_info;
struct storage_backend *storage_backend = context->persistent_store;
@@ -468,13 +587,13 @@
psa_status_t psa_status = storage_backend->interface->get_info(
storage_backend->context,
context->owner_id,
- info->uid,
+ info->metadata.uid,
&storage_info);
if (psa_status != PSA_SUCCESS) {
/* Detected a mismatch between the index and storage */
- variable_index_remove(&context->variable_index, info);
+ variable_index_remove_variable(&context->variable_index, info);
any_orphans = true;
}
}
diff --git a/components/service/smm_variable/backend/uefi_variable_store.h b/components/service/smm_variable/backend/uefi_variable_store.h
index ea25918..fe0f24a 100644
--- a/components/service/smm_variable/backend/uefi_variable_store.h
+++ b/components/service/smm_variable/backend/uefi_variable_store.h
@@ -144,6 +144,34 @@
efi_status_t uefi_variable_store_exit_boot_service(
struct uefi_variable_store *context);
+/**
+ * @brief Set variable check property
+ *
+ * Corresponds to the SetVarCheckProperty EDK2 operation
+ *
+ * @param[in] context uefi_variable_store instance
+ * @param[in] property The variable check property
+ *
+ * @return EFI_SUCCESS if succesful
+ */
+efi_status_t uefi_variable_store_set_var_check_property(
+ struct uefi_variable_store *context,
+ const SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property);
+
+/**
+ * @brief Get variable check property
+ *
+ * Corresponds to the GetVarCheckProperty EDK2 operation
+ *
+ * @param[in] context uefi_variable_store instance
+ * @param[out] property The variable check property
+ *
+ * @return EFI_SUCCESS if succesful
+ */
+efi_status_t uefi_variable_store_get_var_check_property(
+ struct uefi_variable_store *context,
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *property);
+
#ifdef __cplusplus
}
#endif
diff --git a/components/service/smm_variable/backend/variable_checker.c b/components/service/smm_variable/backend/variable_checker.c
new file mode 100644
index 0000000..81a41d0
--- /dev/null
+++ b/components/service/smm_variable/backend/variable_checker.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "variable_checker.h"
+
+efi_status_t variable_checker_set_constraints(
+ struct variable_constraints *constraints,
+ bool is_update,
+ const VAR_CHECK_VARIABLE_PROPERTY *check_var_property)
+{
+ /* Sanity check input parameters */
+ if (check_var_property->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION)
+ return EFI_INVALID_PARAMETER;
+
+ if (check_var_property->MinSize > check_var_property->MaxSize)
+ return EFI_INVALID_PARAMETER;
+
+ /* Check for an attempt to undo previously set access constraints */
+ if (is_update) {
+
+ if ((constraints->property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) &&
+ !(check_var_property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY))
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* New check constraints accepted */
+ constraints->revision = check_var_property->Revision;
+ constraints->attributes = check_var_property->Attributes;
+ constraints->property = check_var_property->Property;
+ constraints->min_size = check_var_property->MinSize;
+ constraints->max_size = check_var_property->MaxSize;
+
+ return EFI_SUCCESS;
+}
+
+void variable_checker_get_constraints(
+ const struct variable_constraints *constraints,
+ VAR_CHECK_VARIABLE_PROPERTY *check_var_property)
+{
+ check_var_property->Revision = constraints->revision;
+ check_var_property->Attributes = constraints->attributes;
+ check_var_property->Property = constraints->property;
+ check_var_property->MinSize = constraints->min_size;
+ check_var_property->MaxSize = constraints->max_size;
+}
+
+efi_status_t variable_checker_check_on_set(
+ const struct variable_constraints *constraints,
+ uint32_t attributes,
+ size_t data_size)
+{
+ if (constraints->property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
+ return EFI_WRITE_PROTECTED;
+
+ if (data_size < constraints->min_size)
+ return EFI_INVALID_PARAMETER;
+
+ if (data_size > constraints->max_size)
+ return EFI_INVALID_PARAMETER;
+
+ return EFI_SUCCESS;
+}
diff --git a/components/service/smm_variable/backend/variable_checker.h b/components/service/smm_variable/backend/variable_checker.h
new file mode 100644
index 0000000..cd623a3
--- /dev/null
+++ b/components/service/smm_variable/backend/variable_checker.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef VARIABLE_CHECKER_H
+#define VARIABLE_CHECKER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <protocols/common/efi/efi_status.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief variable_constraints structure definition
+ *
+ * Defines constraints used for checking variable set operations
+ * based on policy driven constraints, set using:
+ * SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET.
+ */
+struct variable_constraints
+{
+ uint16_t revision;
+ uint16_t property;
+ uint32_t attributes;
+ size_t min_size;
+ size_t max_size;
+};
+
+/**
+ * @brief Set variable check constraints
+ *
+ * @param[in] constraints Variable constraints to set
+ * @param[in] is_update True if updating previously set constraints
+ * @param[in] check_var_property The incoming check variable properties
+ *
+ * @return EFI_SUCCESS if check constraints set successfully
+ */
+efi_status_t variable_checker_set_constraints(
+ struct variable_constraints *constraints,
+ bool is_update,
+ const VAR_CHECK_VARIABLE_PROPERTY *check_var_property);
+
+/**
+ * @brief Get variable check constraints
+ *
+ * @param[in] constraints Variable constraints to get
+ * @param[out] check_var_property The result
+ */
+void variable_checker_get_constraints(
+ const struct variable_constraints *constraints,
+ VAR_CHECK_VARIABLE_PROPERTY *check_var_property);
+
+/**
+ * @brief Check if set operations is allowed
+ *
+ * @param[in] constraints Check constraints corresponding to variable
+ * @param[in] attributes The attributes to set
+ * @param[in] data_size The data size
+ *
+ * @return EFI_SUCCESS if set is allowed
+ */
+efi_status_t variable_checker_check_on_set(
+ const struct variable_constraints *constraints,
+ uint32_t attributes,
+ size_t data_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VARIABLE_CHECKER_H */
diff --git a/components/service/smm_variable/backend/variable_index.c b/components/service/smm_variable/backend/variable_index.c
index 2dc486f..99d7c97 100644
--- a/components/service/smm_variable/backend/variable_index.c
+++ b/components/service/smm_variable/backend/variable_index.c
@@ -64,7 +64,7 @@
for (int pos = 0; pos < context->max_variables; pos++) {
if ((context->entries[pos].in_use) &&
- (uid == context->entries[pos].info.uid)) {
+ (uid == context->entries[pos].info.metadata.uid)) {
found_pos = pos;
break;
@@ -93,7 +93,7 @@
static void mark_dirty(struct variable_entry *entry)
{
- if (entry->info.attributes & EFI_VARIABLE_NON_VOLATILE)
+ if (entry->info.metadata.attributes & EFI_VARIABLE_NON_VOLATILE)
entry->dirty = true;
}
@@ -129,7 +129,7 @@
size_t variable_index_max_dump_size(
struct variable_index *context)
{
- return sizeof(struct variable_info) * context->max_variables;
+ return sizeof(struct variable_metadata) * context->max_variables;
}
const struct variable_info *variable_index_find(
@@ -174,7 +174,8 @@
++pos;
while (pos < context->max_variables) {
- if (context->entries[pos].in_use) {
+ if (context->entries[pos].in_use &&
+ context->entries[pos].info.is_variable_set) {
result = &context->entries[pos].info;
break;
@@ -191,7 +192,8 @@
while (pos < context->max_variables) {
- if (context->entries[pos].in_use) {
+ if (context->entries[pos].in_use &&
+ context->entries[pos].info.is_variable_set) {
result = &context->entries[pos].info;
break;
@@ -219,22 +221,21 @@
for (size_t i = 0; i < name_size; i++) {
++trimmed_size;
- info->name[i] = name[i];
+ info->metadata.name[i] = name[i];
if (!name[i]) break;
}
- info->name_size = trimmed_size * sizeof(int16_t);
+ info->metadata.name_size = trimmed_size * sizeof(int16_t);
}
-const struct variable_info *variable_index_add(
+static struct variable_entry *add_entry(
struct variable_index *context,
const EFI_GUID *guid,
size_t name_size,
- const int16_t *name,
- uint32_t attributes)
+ const int16_t *name)
{
- struct variable_info *info = NULL;
+ struct variable_entry *entry = NULL;
if (name_size <= (VARIABLE_INDEX_MAX_NAME_SIZE * sizeof(int16_t))) {
@@ -242,23 +243,71 @@
if (pos >= 0) {
- struct variable_entry *entry = &context->entries[pos];
+ entry = &context->entries[pos];
- info = &entry->info;
- info->uid = generate_uid(context, guid, name_size, name);
- info->guid = *guid;
- info->attributes = attributes;
+ struct variable_info *info = &entry->info;
+
+ /* Initialize metadata */
+ info->metadata.uid = generate_uid(context, guid, name_size, name);
+ info->metadata.guid = *guid;
+ info->metadata.attributes = 0;
set_variable_name(info, name_size, name);
- mark_dirty(entry);
+ info->is_constraints_set = false;
+ info->is_variable_set = false;
+
entry->in_use = true;
}
}
+ return entry;
+}
+
+const struct variable_info *variable_index_add_variable(
+ struct variable_index *context,
+ const EFI_GUID *guid,
+ size_t name_size,
+ const int16_t *name,
+ uint32_t attributes)
+{
+ struct variable_info *info = NULL;
+ struct variable_entry *entry = add_entry(context, guid, name_size, name);
+
+ if (entry) {
+
+ info = &entry->info;
+
+ info->metadata.attributes = attributes;
+ info->is_variable_set = true;
+
+ mark_dirty(entry);
+ }
+
return info;
}
-void variable_index_remove(
+const struct variable_info *variable_index_add_constraints(
+ struct variable_index *context,
+ const EFI_GUID *guid,
+ size_t name_size,
+ const int16_t *name,
+ const struct variable_constraints *constraints)
+{
+ struct variable_info *info = NULL;
+ struct variable_entry *entry = add_entry(context, guid, name_size, name);
+
+ if (entry) {
+
+ info = &entry->info;
+
+ info->check_constraints = *constraints;
+ info->is_constraints_set = true;
+ }
+
+ return info;
+}
+
+void variable_index_remove_variable(
struct variable_index *context,
const struct variable_info *info)
{
@@ -266,14 +315,22 @@
struct variable_entry *entry = containing_entry(info);
mark_dirty(entry);
- entry->in_use = false;
- memset(&entry->info, 0, sizeof(struct variable_info));
+ /* Mark variable as no longer set */
+ entry->info.is_variable_set = false;
+
+ /* Entry may still be needed if check constraints were set */
+ entry->in_use = info->is_constraints_set;
+
+ if (!entry->in_use) {
+
+ /* Entry not needed so wipe */
+ memset(&entry->info, 0, sizeof(struct variable_info));
+ }
}
}
-void variable_index_update_attributes(
- struct variable_index *context,
+void variable_index_update_variable(
const struct variable_info *info,
uint32_t attributes)
{
@@ -282,14 +339,30 @@
struct variable_info *modified_info = (struct variable_info*)info;
struct variable_entry *entry = containing_entry(modified_info);
- if (attributes != modified_info->attributes) {
+ if (!modified_info->is_variable_set ||
+ (attributes != modified_info->metadata.attributes)) {
- modified_info->attributes = attributes;
+ /* The update changes the variable_info state */
+ modified_info->is_variable_set = true;
+ modified_info->metadata.attributes = attributes;
mark_dirty(entry);
}
}
}
+void variable_index_update_constraints(
+ const struct variable_info *info,
+ const struct variable_constraints *constraints)
+{
+ if (info) {
+
+ struct variable_info *modified_info = (struct variable_info*)info;
+
+ modified_info->check_constraints = *constraints;
+ modified_info->is_constraints_set = true;
+ }
+}
+
bool variable_index_dump(
struct variable_index *context,
size_t buffer_size,
@@ -303,15 +376,16 @@
for (int pos = 0; pos < context->max_variables; pos++) {
struct variable_entry *entry = &context->entries[pos];
- struct variable_info *info = &entry->info;
+ struct variable_metadata *metadata = &entry->info.metadata;
if (entry->in_use &&
- (info->attributes & EFI_VARIABLE_NON_VOLATILE) &&
- ((bytes_dumped + sizeof(struct variable_info)) <= buffer_size)) {
+ entry->info.is_variable_set &&
+ (metadata->attributes & EFI_VARIABLE_NON_VOLATILE) &&
+ ((bytes_dumped + sizeof(struct variable_metadata)) <= buffer_size)) {
- memcpy(dump_pos, info, sizeof(struct variable_info));
- bytes_dumped += sizeof(struct variable_info);
- dump_pos += sizeof(struct variable_info);
+ memcpy(dump_pos, metadata, sizeof(struct variable_metadata));
+ bytes_dumped += sizeof(struct variable_metadata);
+ dump_pos += sizeof(struct variable_metadata);
}
any_dirty |= entry->dirty;
@@ -334,23 +408,24 @@
while (bytes_loaded < data_len) {
- if ((data_len - bytes_loaded) >= sizeof(struct variable_info)) {
+ if ((data_len - bytes_loaded) >= sizeof(struct variable_metadata)) {
struct variable_entry *entry = &context->entries[pos];
- struct variable_info *info = &entry->info;
+ struct variable_metadata *metadata = &entry->info.metadata;
- memcpy(info, load_pos, sizeof(struct variable_info));
+ memcpy(metadata, load_pos, sizeof(struct variable_metadata));
+ entry->info.is_variable_set = true;
entry->in_use = true;
- bytes_loaded += sizeof(struct variable_info);
- load_pos += sizeof(struct variable_info);
+ bytes_loaded += sizeof(struct variable_metadata);
+ load_pos += sizeof(struct variable_metadata);
++pos;
}
else {
- /* Not a whole number of variable_info structs! */
+ /* Not a whole number of variable_metadata structs! */
break;
}
}
diff --git a/components/service/smm_variable/backend/variable_index.h b/components/service/smm_variable/backend/variable_index.h
index 80c5e5f..e109d0d 100644
--- a/components/service/smm_variable/backend/variable_index.h
+++ b/components/service/smm_variable/backend/variable_index.h
@@ -13,6 +13,7 @@
#include <stdint.h>
#include <protocols/common/efi/efi_status.h>
#include <protocols/service/smm_variable/smm_variable_proto.h>
+#include "variable_checker.h"
#ifdef __cplusplus
extern "C" {
@@ -24,11 +25,11 @@
#define VARIABLE_INDEX_MAX_NAME_SIZE (32)
/**
- * \brief variable_info structure definition
+ * \brief variable_metadata structure definition
*
- * Holds information about a stored variable.
+ * Holds metadata associated with stored variable.
*/
-struct variable_info
+struct variable_metadata
{
EFI_GUID guid;
size_t name_size;
@@ -38,6 +39,20 @@
};
/**
+ * \brief variable_info structure definition
+ *
+ * Holds information about a stored variable.
+ */
+struct variable_info
+{
+ struct variable_metadata metadata;
+ struct variable_constraints check_constraints;
+
+ bool is_variable_set;
+ bool is_constraints_set;
+};
+
+/**
* \brief An entry in the index
*
* Represents a store variable in the variable index.
@@ -137,7 +152,7 @@
*
* @return Pointer to variable_info or NULL
*/
-const struct variable_info *variable_index_add(
+const struct variable_info *variable_index_add_variable(
struct variable_index *context,
const EFI_GUID *guid,
size_t name_size,
@@ -152,23 +167,49 @@
* @param[in] context variable_index
* @param[in] info The variable info corresponding to the entry to remove
*/
-void variable_index_remove(
+void variable_index_remove_variable(
struct variable_index *context,
const struct variable_info *info);
/**
- * @brief Update variable attributes
+ * @brief Update a variable that's already in the index
*
- * @param[in] context variable_index
* @param[in] info variable info
* @param[in] attributes The variable's attributes
*/
-void variable_index_update_attributes(
- struct variable_index *context,
+void variable_index_update_variable(
const struct variable_info *info,
uint32_t attributes);
/**
+ * @brief Add a new check constraints object to the index
+ *
+ * @param[in] context variable_index
+ * @param[in] guid The variable's guid
+ * @param[in] name_size The name parameter's size
+ * @param[in] name The variable's name
+ * @param[in] constraints The check constraints
+ *
+ * @return Pointer to variable_info or NULL
+ */
+const struct variable_info *variable_index_add_constraints(
+ struct variable_index *context,
+ const EFI_GUID *guid,
+ size_t name_size,
+ const int16_t *name,
+ const struct variable_constraints *constraints);
+
+/**
+ * @brief Update variable constraints that are already in the index
+ *
+ * @param[in] info variable info
+ * @param[in] constraints The check constraints
+ */
+void variable_index_update_constraints(
+ const struct variable_info *info,
+ const struct variable_constraints *constraints);
+
+/**
* @brief Dump the serialized index contents for persistent backup
*
* @param[in] context variable_index