From 2c9eebcf6ddd198c5ba49d784c4536d05023c28b Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 22 Jul 2021 15:45:23 -0400 Subject: tests: add a mock implementation of {Get,Set}Variable and tests for it Some tests will need variables, and so we need a mock implementation of the various calls relating to them. This patch adds implementations for the EFI Runtime Services calls GetVariable(), SetVariable(), GetNextVariableName(), and QueryVariableInfo(). Additionally, it enforces tunable limits on storage for variables, and (with only a little work) the limits can be different for SetVariable() vs what is returned by QueryVariableInfo(). That is, it can lie to you like real systems do. Signed-off-by: Peter Jones --- mock-variables.c | 1022 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1022 insertions(+) create mode 100644 mock-variables.c (limited to 'mock-variables.c') diff --git a/mock-variables.c b/mock-variables.c new file mode 100644 index 00000000..d8342d59 --- /dev/null +++ b/mock-variables.c @@ -0,0 +1,1022 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * mock-variables.c - a mock GetVariable/SetVariable/GNVN/etc + * implementation for testing. + * Copyright Peter Jones + */ +#include "shim.h" +#include "mock-variables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" + +list_t mock_default_variable_limits; +list_t *mock_qvi_limits = &mock_default_variable_limits; +list_t *mock_sv_limits = &mock_default_variable_limits; + +list_t mock_variables = LIST_HEAD_INIT(mock_variables); + +mock_sort_policy_t mock_variable_sort_policy = MOCK_SORT_APPEND; + +static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c"); + +static int +variable_limits_cmp(const struct mock_variable_limits * const v0, + const struct mock_variable_limits * const v1) +{ + UINT32 mask = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + + return (v0->attrs & mask) - (v1->attrs & mask); +} + +static INT64 +variable_cmp(const struct mock_variable * const v0, + const struct mock_variable * const v1) +{ + INT64 ret; + if (v0 == NULL || v1 == NULL) + return (uintptr_t)v0 - (uintptr_t)v1; + + ret = CompareGuid(&v0->guid, &v1->guid); + ret <<= 8ul; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): "GUID_FMT" %s "GUID_FMT" (0x%011"PRIx64" %"PRId64")\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(v0->guid), + ret < 0 ? "<" : (ret > 0 ? ">" : "="), + GUID_ARGS(v1->guid), + (UINT64)ret & 0x1fffffffffful, + ret); +#endif + if (ret != 0) { + return ret; + } + + ret = StrCmp(v0->name, v1->name); +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): \"%s\" %s \"%s\" (0x%02hhx (%d)\n", + __FILE__, __LINE__-1, __func__, + Str2str(v0->name), + ret < 0 ? "<" : (ret > 0 ? ">" : "=="), + Str2str(v1->name), + ret, ret); +#endif + return ret; +} + +static char * +list2var(list_t *pos) +{ + static char buf0[1024]; + static char buf1[1024]; + char *out; + static int n; + struct mock_variable *var; + + out = n++ % 2 ? buf0 : buf1; + if (n > 1) + n -= 2; + SetMem(out, 1024, 0); + if (pos == &mock_variables) { + strcpy(out, "list tail"); + return out; + } + var = list_entry(pos, struct mock_variable, list); + snprintf(out, 1023, GUID_FMT"-%s", + GUID_ARGS(var->guid), + Str2str(var->name)); + return out; +} + +EFI_STATUS EFIAPI +mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, + VOID *data) +{ + list_t *pos = NULL; + struct mock_variable goal = { + .name = name, + .guid = *guid, + }; + struct mock_variable *result = NULL; + EFI_STATUS status; + + if (name == NULL || guid == NULL || size == NULL) { + status = EFI_INVALID_PARAMETER; + return status; + } + + list_for_each(pos, &mock_variables) { + struct mock_variable *var; + + var = list_entry(pos, struct mock_variable, list); +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(goal.guid), Str2str(goal.name), + GUID_ARGS(var->guid), Str2str(var->name)); +#endif + if (variable_cmp(&goal, var) == 0) { + if (attrs != NULL) + *attrs = var->attrs; + if (var->size > *size) { + *size = var->size; + status = EFI_BUFFER_TOO_SMALL; + return status; + } + if (data == NULL) { + status = EFI_INVALID_PARAMETER; + return status; + } + *size = var->size; + memcpy(data, var->data, var->size); + status = EFI_SUCCESS; + return status; + } + } + + status = EFI_NOT_FOUND; + return status; +} + +static EFI_STATUS +mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid, + struct mock_variable *result) +{ + EFI_STATUS status; + + if (*size < StrSize(result->name)) { + *size = StrSize(result->name); + status = EFI_BUFFER_TOO_SMALL; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): returning %lx\n", + __FILE__, __LINE__-1, __func__, status); +#endif + return status; + } + + *size = StrLen(result->name) + 1; + StrCpy(name, result->name); + memcpy(guid, &result->guid, sizeof(EFI_GUID)); + + status = EFI_SUCCESS; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): returning %lx\n", + __FILE__, __LINE__-1, __func__, status); +#endif + return status; +} + +EFI_STATUS EFIAPI +mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) +{ + list_t *pos = NULL; + struct mock_variable goal = { + .name = name, + .guid = *guid, + }; + struct mock_variable *result = NULL; + bool found = false; + EFI_STATUS status; + + if (size == NULL || name == NULL || guid == NULL) { + status = EFI_INVALID_PARAMETER; + return status; + } + + for (size_t i = 0; i < *size; i++) { + if (name[i] == 0) { + found = true; + break; + } + } + + if (found == false) { + status = EFI_INVALID_PARAMETER; + return status; + } + + found = false; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():searching for "GUID_FMT"%s%s\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(*guid), + name[0] == 0 ? "" : "-", + name[0] == 0 ? "" : Str2str(name)); +#endif + list_for_each(pos, &mock_variables) { + struct mock_variable *var; + + var = list_entry(pos, struct mock_variable, list); +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): candidate var:%p &var->guid:%p &var->list:%p\n", + __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list); +#endif + if (name[0] == 0) { + if (CompareGuid(&var->guid, guid) == 0) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): found\n", + __FILE__, __LINE__-1, __func__); +#endif + result = var; + found = true; + break; + } + } else { + if (found) { + if (CompareGuid(&var->guid, guid) == 0) { + result = var; + break; + } + continue; + } + +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(goal.guid), Str2str(goal.name), + GUID_ARGS(var->guid), Str2str(var->name)); +#endif + if (variable_cmp(&goal, var) == 0) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): found\n", + __FILE__, __LINE__-1, __func__); +#endif + found = true; + } + } + } +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + if (result) { + printf("%s:%d:%s(): found:%d result:%p &result->guid:%p &result->list:%p\n" + __FILE__, __LINE__-1, __func__, found, result, + &result->guid, &result->list); + printf("%s:%d:%s(): "GUID_FMT"-%s\n", + __FILE__, __LINE__-1, __func__, GUID_ARGS(result->guid), + Str2str(result->name)); + } else { + printf("%s:%d:%s(): not found\n", + __FILE__, __LINE__-1, __func__); + } +#endif + + if (!found) { + if (name[0] == 0) + status = EFI_NOT_FOUND; + else + status = EFI_INVALID_PARAMETER; + return status; + } + + if (!result) { + status = EFI_NOT_FOUND; + return status; + } + + return mock_gnvn_set_result(size, name, guid, result); +} + +static void +free_var(struct mock_variable *var) +{ + if (!var) + return; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): var:%p &var->guid:%p ", + __FILE__, __LINE__-1, __func__, + var, var ? &var->guid : NULL); + if (var) + printf(GUID_FMT"-%s", GUID_ARGS(var->guid), + var->name ? Str2str(var->name) : ""); + printf("\n"); +#endif + list_del(&var->list); + if (var->size && var->data) + free(var->data); + SetMem(var, sizeof(*var), 0); + free(var); +} + +static bool +mock_sv_attrs_match(UINT32 old, UINT32 new) +{ + UINT32 mask = ~EFI_VARIABLE_APPEND_WRITE; + + return (old & mask) == (new & mask); +} + +static EFI_STATUS +mock_sv_adjust_usage_data(UINT32 attrs, size_t size, ssize_t change) +{ + const UINT32 bs = EFI_VARIABLE_BOOTSERVICE_ACCESS; + const UINT32 bs_nv = bs | EFI_VARIABLE_NON_VOLATILE; + const UINT32 bs_rt = bs | EFI_VARIABLE_RUNTIME_ACCESS; + const UINT32 bs_rt_nv = bs_nv | bs_rt; + struct mock_variable_limits goal = { + .attrs = attrs & bs_rt_nv, + }; + struct mock_variable_limits *qvi_limits = NULL; + struct mock_variable_limits *sv_limits = NULL; + list_t var, *pos = NULL; + UINT64 remaining; + + list_for_each(pos, mock_qvi_limits) { + struct mock_variable_limits *candidate; + + candidate = list_entry(pos, struct mock_variable_limits, list); + if (variable_limits_cmp(&goal, candidate) == 0) { + qvi_limits = candidate; + break; + } + } + + list_for_each(pos, mock_sv_limits) { + struct mock_variable_limits *candidate; + + candidate = list_entry(pos, struct mock_variable_limits, list); + if (variable_limits_cmp(&goal, candidate) == 0) { + sv_limits = candidate; + break; + } + } + if (!sv_limits) { + return EFI_UNSUPPORTED; + } + + if (sv_limits->status != EFI_SUCCESS) + return sv_limits->status; + + if (*sv_limits->max_var_size < size) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():*sv_limits->max_var_size:%zu size:%zu\n", + __FILE__, __LINE__, __func__, + *sv_limits->max_var_size, size); +#endif + return EFI_OUT_OF_RESOURCES; + } + + if (change > 0 && (UINT64)change > *sv_limits->remaining_var_storage) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():*sv_limits->remaining_var_storage:%zu change:%zd\n", + __FILE__, __LINE__, __func__, + *sv_limits->remaining_var_storage, change); +#endif + return EFI_OUT_OF_RESOURCES; + } + + *sv_limits->remaining_var_storage += change; + + if (qvi_limits) { + /* + * If the adjustment here is wrong, we don't want to not do + * the set variable, we also don't want to not account + * for it, and of course we can't have any integer UB. So + * just limit it safely and move on, even though that may + * result in wrong checks against QueryVariableInfo() later. + * + * As if there are correct checks against QueryVariableInfo()... + */ + if (qvi_limits->remaining_var_storage == sv_limits->remaining_var_storage) + ; + else if (change < 0 && (UINT64)-change > *qvi_limits->remaining_var_storage) + *qvi_limits->remaining_var_storage = 0; + else if (change > 0 && UINT64_MAX - *qvi_limits->remaining_var_storage < (UINT64)change) + *qvi_limits->remaining_var_storage = UINT64_MAX; + else + *qvi_limits->remaining_var_storage += change; + } + return EFI_SUCCESS; +} + +static EFI_STATUS +mock_delete_variable(struct mock_variable *var) +{ + EFI_STATUS status; + + status = mock_sv_adjust_usage_data(var->attrs, 0, - var->size); + if (EFI_ERROR(status)) { + printf("%s:%d:%s(): status:0x%lx\n", + __FILE__, __LINE__ - 1, __func__, status); + return status; + } + + status = EFI_SUCCESS; + free_var(var); + return status; +} + +static EFI_STATUS +mock_replace_variable(struct mock_variable *var, VOID *data, UINTN size) +{ + EFI_STATUS status; + VOID *new; + + status = mock_sv_adjust_usage_data(var->attrs, size, + - var->size + size); + if (EFI_ERROR(status)) { + return status; + } + + new = calloc(1, size); + if (!new) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():calloc(1, %zu) failed\n", + __FILE__, __LINE__, __func__, + size); +#endif + status = EFI_OUT_OF_RESOURCES; + return status; + } + memcpy(new, data, size); + free(var->data); + var->data = new; + var->size = size; + + status = EFI_SUCCESS; + return status; +} + +static EFI_STATUS +mock_sv_extend(struct mock_variable *var, VOID *data, UINTN size) +{ + EFI_STATUS status; + uint8_t *new; + + if (size == 0) { + status = EFI_SUCCESS; + return status; + } + + status = mock_sv_adjust_usage_data(var->attrs, var->size + size, size); + if (EFI_ERROR(status)) { + return status; + } + + new = realloc(var->data, var->size + size); + if (!new) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():realloc(%zu) failed\n", + __FILE__, __LINE__, __func__, + var->size + size); +#endif + status = EFI_OUT_OF_RESOURCES; + return status; + } + + memcpy(&new[var->size], data, size); + var->data = (void *)new; + var->size += size; + + status = EFI_SUCCESS; + return status; +} + +void +mock_print_var_list(list_t *head) +{ + list_t *pos = NULL; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():variables so far:\n", __FILE__, __LINE__, __func__); +#endif + list_for_each(pos, head) { + struct mock_variable *var = NULL; + + var = list_entry(pos, struct mock_variable, list); +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): "GUID_FMT"-%s (%lu bytes)\n", + __FILE__, __LINE__ - 1, __func__, + GUID_ARGS(var->guid), Str2str(var->name), var->size); +#endif + } +} + +static EFI_STATUS +mock_new_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, + VOID *data, struct mock_variable **out) +{ + EFI_STATUS status; + struct mock_variable *var; + uint8_t *buf; + + if (size == 0) { + status = EFI_INVALID_PARAMETER; + return status; + } + + status = EFI_OUT_OF_RESOURCES; + buf = calloc(1, sizeof(struct mock_variable) + StrSize(name)); + if (!buf) { +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): calloc(1, %zu) failed\n", + __FILE__, __LINE__, __func__, + sizeof(struct mock_variable) + StrSize(name)); +#endif + goto err; + } + var = (struct mock_variable *)buf; + +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): var:%p &var->guid:%p &var->list:%p\n", + __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list); +#endif + + var->data = malloc(size); + if (!var->data) + goto err_free; + + var->name = (CHAR16 *)&buf[sizeof(*var)]; + StrCpy(var->name, name); + memcpy(&var->guid, guid, sizeof(EFI_GUID)); + memcpy(var->data, data, size); + var->size = size; + var->attrs = attrs; + INIT_LIST_HEAD(&var->list); + +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): var: "GUID_FMT"-%s\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(var->guid), Str2str(var->name)); +#endif + + *out = var; + status = EFI_SUCCESS; +err_free: + if (EFI_ERROR(status)) + free_var(var); +err: + return status; +} + +EFI_STATUS EFIAPI +mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, + VOID *data) +{ + list_t *pos = NULL, *tmp = NULL, *var_list = NULL; + struct mock_variable goal = { + .name = name, + .guid = *guid, + }; + struct mock_variable *var = NULL; + bool found = false; + bool add_tail = true; + EFI_STATUS status; + long cmp = -1; + + if (!name || name[0] == 0 || !guid) { + status = EFI_INVALID_PARAMETER; + return status; + } + + if ((attrs & EFI_VARIABLE_RUNTIME_ACCESS) && + !(attrs & EFI_VARIABLE_BOOTSERVICE_ACCESS)) { + status = EFI_INVALID_PARAMETER; + return status; + } + +#if 0 + /* + * We don't ever operate after ExitBootServices(), so I'm not + * checking for the missing EFI_VARIABLE_RUNTIME_ACCESS case + */ + if (has_exited_boot_services() && !(attrs & EFI_VARIABLE_RUNTIME_ACCESS)) { + status = EFI_INVALID_PARAMETER; + return status; + } +#endif + +#if 0 + /* + * For now, we're ignoring that we don't support these. + */ + if (attrs & (EFI_VARIABLE_HARDWARE_ERROR_RECORD | + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | + EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)) { + status = EFI_UNSUPPORTED; + return status; + } +#endif + +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():Setting "GUID_FMT"-%s\n", + __FILE__, __LINE__ - 1, __func__, + GUID_ARGS(*guid), Str2str(name)); +#endif + switch (mock_variable_sort_policy) { + case MOCK_SORT_PREPEND: + var_list = &mock_variables; + add_tail = false; + break; + case MOCK_SORT_APPEND: + var_list = &mock_variables; + add_tail = true; + break; + case MOCK_SORT_DESCENDING: + add_tail = true; + break; + case MOCK_SORT_ASCENDING: + add_tail = true; + break; + default: + break; + } + + pos = &mock_variables; + list_for_each_safe(pos, tmp, &mock_variables) { + found = false; + var = list_entry(pos, struct mock_variable, list); +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(goal.guid), Str2str(goal.name), + GUID_ARGS(var->guid), Str2str(var->name)); +#endif + cmp = variable_cmp(&goal, var); + cmp = cmp < 0 ? -1 : (cmp > 0 ? 1 : 0); + + switch (mock_variable_sort_policy) { + case MOCK_SORT_DESCENDING: + if (cmp >= 0) { + var_list = pos; + found = true; + } + break; + case MOCK_SORT_ASCENDING: + if (cmp <= 0) { + var_list = pos; + found = true; + } + break; + default: + if (cmp == 0) { + var_list = pos; + found = true; + } + break; + } + if (found) + break; + } +#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 + printf("%s:%d:%s():var_list:%p &mock_variables:%p cmp:%ld\n", + __FILE__, __LINE__ - 1, __func__, + var_list, &mock_variables, cmp); +#endif + if (cmp != 0 || (cmp == 0 && var_list == &mock_variables)) { + size_t totalsz = size + StrSize(name); +#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 + printf("%s:%d:%s():var:%p attrs:0x%lx\n", + __FILE__, __LINE__ - 1, __func__, var, attrs); +#endif + status = mock_new_variable(name, guid, attrs, size, data, &var); + if (EFI_ERROR(status)) { + return status; + } + mock_sv_adjust_usage_data(attrs, size, totalsz); + if (EFI_ERROR(status)) { + mock_sv_adjust_usage_data(attrs, 0, -totalsz); + return status; + } + +#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 + printf("%s:%d:%s(): Adding "GUID_FMT"-%s %s %s\n", + __FILE__, __LINE__ - 1, __func__, + GUID_ARGS(var->guid), Str2str(var->name), + add_tail ? "after" : "before", + list2var(pos)); +#endif + if (add_tail) + list_add_tail(&var->list, pos); + else + list_add(&var->list, pos); + return status; + } + + var = list_entry(var_list, struct mock_variable, list); +#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 + printf("%s:%d:%s():var:%p attrs:%s cmp:%ld size:%ld\n", + __FILE__, __LINE__ - 1, __func__, + var, format_var_attrs(var->attrs), cmp, size); +#endif + if (!mock_sv_attrs_match(var->attrs, attrs) && !(attrs == 0 && size == 0)) { + status = EFI_INVALID_PARAMETER; + return status; + } + + if (attrs & EFI_VARIABLE_APPEND_WRITE) + return mock_sv_extend(var, data, size); + + if (size == 0) { + UINT32 mask = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + | EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS; + /* + * We can't process deletes on these correctly unless we + * parse the header. + */ + if (attrs & mask) { + return EFI_INVALID_PARAMETER; + } + + return mock_delete_variable(var); + } + + return mock_replace_variable(var, data, size); +} + +EFI_STATUS EFIAPI +mock_query_variable_info(UINT32 attrs, UINT64 *max_var_storage, + UINT64 *remaining_var_storage, UINT64 *max_var_size) +{ + list_t mvl, *pos = NULL; + struct mock_variable_limits goal = { + .attrs = attrs, + }; + struct mock_variable_limits *limits = NULL; + EFI_STATUS status; + + if (max_var_storage == NULL || + remaining_var_storage == NULL || + max_var_size == NULL) { + status = EFI_INVALID_PARAMETER; + return status; + } + + list_for_each(pos, mock_qvi_limits) { + limits = list_entry(pos, struct mock_variable_limits, list); + if (variable_limits_cmp(&goal, limits) == 0) { + *max_var_storage = *limits->max_var_storage; + *remaining_var_storage = *limits->remaining_var_storage; + *max_var_size = *limits->max_var_size; + status = EFI_SUCCESS; + return status; + } + } + + status = EFI_UNSUPPORTED; + return status; +} + +static UINT64 default_max_var_storage; +static UINT64 default_remaining_var_storage; +static UINT64 default_max_var_size; + +static struct mock_variable_limits default_limits[] = { + {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS, + .max_var_storage = &default_max_var_storage, + .remaining_var_storage = &default_remaining_var_storage, + .max_var_size = &default_max_var_size, + .status = EFI_SUCCESS, + }, + {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + .max_var_storage = &default_max_var_storage, + .remaining_var_storage = &default_remaining_var_storage, + .max_var_size = &default_max_var_size, + .status = EFI_SUCCESS, + }, + {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + .max_var_storage = &default_max_var_storage, + .remaining_var_storage = &default_remaining_var_storage, + .max_var_size = &default_max_var_size, + .status = EFI_SUCCESS, + }, + {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + .max_var_storage = &default_max_var_storage, + .remaining_var_storage = &default_remaining_var_storage, + .max_var_size = &default_max_var_size, + .status = EFI_SUCCESS, + }, + {.attrs = 0, } +}; + +void +mock_set_default_usage_limits(void) +{ + default_max_var_storage = 65536; + default_remaining_var_storage = 65536; + default_max_var_size = 32768; + + INIT_LIST_HEAD(&mock_default_variable_limits); + for (size_t i = 0; default_limits[i].attrs != 0; i++) { + INIT_LIST_HEAD(&default_limits[i].list); + list_add_tail(&default_limits[i].list, + &mock_default_variable_limits); + } +} + +void +mock_load_one_variable(int dfd, const char * const dirname, char * const name) +{ + int fd; + FILE *f; + int rc; + struct stat statbuf; + size_t guidlen, namelen; + efi_guid_t guid; + size_t sz; + ssize_t offset = 0; + EFI_STATUS status; + UINT32 attrs; + + rc = fstatat(dfd, name, &statbuf, 0); + if (rc < 0) + err(2, "Could not stat \"%s/%s\"", dirname, name); + + if (!(S_ISREG(statbuf.st_mode))) + return; + + if (statbuf.st_size < 5) + errx(2, "Test data variable \"%s/%s\" is too small (%ld bytes)", + dirname, name, statbuf.st_size); + +#if 0 + mock_print_var_list(&mock_variables); +#endif + + uint8_t buf[statbuf.st_size]; + + fd = openat(dfd, name, O_RDONLY); + if (fd < 0) + err(2, "Could not open \"%s/%s\"", dirname, name); + + f = fdopen(fd, "r"); + if (!f) + err(2, "Could not open \"%s/%s\"", dirname, name); + + while (offset != statbuf.st_size) { + sz = fread(buf + offset, 1, statbuf.st_size - offset, f); + if (sz == 0) { + if (ferror(f)) + err(2, "Could not read from \"%s/%s\"", + dirname, name); + if (feof(f)) + errx(2, "Unexpected end of file reading \"%s/%s\"", + dirname, name); + } + + offset += sz; + } + + guidlen = strlen("8be4df61-93ca-11d2-aa0d-00e098032b8c"); + namelen = strlen(name) - guidlen; + + if (namelen < 2) + errx(2, "namelen for \"%s\" is %zu!?!", name, namelen); + + CHAR16 namebuf[namelen]; + + name[namelen-1] = 0; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("loading %s-%s\n", &name[namelen], name); +#endif + for (size_t i = 0; i < namelen; i++) + namebuf[i] = name[i]; + + rc = efi_str_to_guid(&name[namelen], &guid); + if (rc < 0) + err(2, "Could not parse \"%s\" as EFI GUID", &name[namelen]); + + memcpy(&attrs, (UINT32 *)buf, sizeof(UINT32)); + + status = RT->SetVariable(namebuf, (EFI_GUID *)&guid, attrs, + statbuf.st_size - sizeof(attrs), + &buf[sizeof(attrs)]); + if (EFI_ERROR(status)) + errx(2, "%s:%d:%s(): Could not set variable: 0x%llx", + __FILE__, __LINE__ - 1, __func__, + (unsigned long long)status); + + fclose(f); +} + +void +mock_load_variables(const char *const dirname, const char *filters[], + bool filter_out) +{ + int dfd; + DIR *d; + struct dirent *entry; + + d = opendir(dirname); + if (!d) + err(1, "Could not open directory \"%s\"", dirname); + + dfd = dirfd(d); + if (dfd < 0) + err(1, "Could not get directory file descriptor for \"%s\"", + dirname); + + while ((entry = readdir(d)) != NULL) { + size_t len = strlen(entry->d_name); + bool found = false; + if (filters && len > guidstr_size + 1) { + char spacebuf[len]; + + len -= guidstr_size; + SetMem(spacebuf, sizeof(spacebuf)-1, ' '); + spacebuf[len] = '\0'; + for (size_t i = 0; filters[i]; i++) { + if (strlen(filters[i]) > len) + continue; + if (!strncmp(entry->d_name, filters[i], len)) { + found = true; + break; + } + } + } + if ((found == false && filter_out == true) || + (found == true && filter_out == false)) { + mock_load_one_variable(dfd, dirname, entry->d_name); + } + } + + closedir(d); +#if 0 + mock_print_var_list(&mock_variables); +#endif +} + +static bool qvi_installed = false; + +void +mock_install_query_variable_info(void) +{ + qvi_installed = true; + RT->Hdr.Revision = 2ul << 16ul; + RT->QueryVariableInfo = mock_query_variable_info; +} + +void +mock_uninstall_query_variable_info(void) +{ + qvi_installed = false; + RT->Hdr.Revision = EFI_1_10_SYSTEM_TABLE_REVISION; + RT->QueryVariableInfo = mock_efi_unsupported; +} + +void CONSTRUCTOR +mock_reset_variables(void) +{ + list_t *pos = NULL, *tmp = NULL; + static bool once = true; + + init_efi_system_table(); + + if (once) { + INIT_LIST_HEAD(&mock_variables); + once = false; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():mock_variables = {%p,%p};\n", + __FILE__, __LINE__-1, __func__, + mock_variables.next, + mock_variables.prev); + printf("%s:%d:%s():list_empty(&mock_variables):%d\n", + __FILE__, __LINE__-1, __func__, list_empty(&mock_variables)); + printf("%s:%d:%s():list_size(&mock_variables):%d\n", + __FILE__, __LINE__-1, __func__, list_size(&mock_variables)); +#endif + } + + list_for_each_safe(pos, tmp, &mock_variables) { + struct mock_variable *var = NULL; + var = list_entry(pos, struct mock_variable, list); + +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():var:"GUID_FMT"-%s\n", + __FILE__, __LINE__-1, __func__, + GUID_ARGS(var->guid), Str2str(var->name)); +#endif + mock_delete_variable(var); + } + INIT_LIST_HEAD(&mock_variables); + mock_set_default_usage_limits(); + + RT->GetVariable = mock_get_variable; + RT->GetNextVariableName = mock_get_next_variable_name; + RT->SetVariable = mock_set_variable; + if (qvi_installed) + mock_install_query_variable_info(); + else + mock_uninstall_query_variable_info(); +} + +void DESTRUCTOR +mock_finalize_vars(void) +{ + mock_reset_variables(); +} + +// vim:fenc=utf-8:tw=75:noet -- cgit v1.2.3 From 54bc72cf0abd306d96782cdfa6db7c71ff72e056 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 3 Aug 2021 13:11:14 -0400 Subject: tests: model different behaviors for deleting variables Signed-off-by: Peter Jones --- include/mock-variables.h | 5 +++++ mock-variables.c | 22 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'mock-variables.c') diff --git a/include/mock-variables.h b/include/mock-variables.h index 7ba00847..fc276ce7 100644 --- a/include/mock-variables.h +++ b/include/mock-variables.h @@ -41,6 +41,11 @@ typedef enum { extern mock_sort_policy_t mock_variable_sort_policy; +#define MOCK_VAR_DELETE_ATTR_ALLOW_ZERO 0x01 +#define MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH 0x02 + +extern UINT32 mock_variable_delete_attr_policy; + extern list_t mock_default_variable_limits; extern list_t *mock_qvi_limits; extern list_t *mock_sv_limits; diff --git a/mock-variables.c b/mock-variables.c index d8342d59..e02febec 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -27,6 +27,8 @@ list_t mock_variables = LIST_HEAD_INIT(mock_variables); mock_sort_policy_t mock_variable_sort_policy = MOCK_SORT_APPEND; +UINT32 mock_variable_delete_attr_policy; + static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c"); static int @@ -708,9 +710,23 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, __FILE__, __LINE__ - 1, __func__, var, format_var_attrs(var->attrs), cmp, size); #endif - if (!mock_sv_attrs_match(var->attrs, attrs) && !(attrs == 0 && size == 0)) { + if (!mock_sv_attrs_match(var->attrs, attrs)) { status = EFI_INVALID_PARAMETER; - return status; + if (size == 0 && !(attrs & EFI_VARIABLE_APPEND_WRITE)) { + if ((mock_variable_delete_attr_policy & MOCK_VAR_DELETE_ATTR_ALLOW_ZERO) + && attrs == 0) { + status = EFI_SUCCESS; + } else if (mock_variable_delete_attr_policy & MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH) { + status = EFI_SUCCESS; + } + } + if (EFI_ERROR(status)) { + printf("%s:%d:%s(): var->attrs:%s attrs:%s\n", + __FILE__, __LINE__ - 1, __func__, + format_var_attrs(var->attrs), + format_var_attrs(attrs)); + return status; + } } if (attrs & EFI_VARIABLE_APPEND_WRITE) @@ -1004,6 +1020,8 @@ mock_reset_variables(void) INIT_LIST_HEAD(&mock_variables); mock_set_default_usage_limits(); + mock_variable_delete_attr_policy = MOCK_VAR_DELETE_ATTR_ALLOW_ZERO; + RT->GetVariable = mock_get_variable; RT->GetNextVariableName = mock_get_next_variable_name; RT->SetVariable = mock_set_variable; -- cgit v1.2.3 From 3386d4f5b7cf63fba4b1ba9b1c2878617b141b23 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 22 Jul 2021 16:23:49 -0400 Subject: tests: add pre and post hooks to the mock variable store For testing of the mok mirroring behavior, we have to be able to account for what variable calls happened and in what order. In order to support that, this patch adds 8 callbacks: mock_set_variable_pre_hook() mock_set_variable_post_hook() mock_get_variable_pre_hook() mock_get_variable_post_hook() mock_get_next_variable_name_pre_hook() mock_get_next_variable_name_post_hook() mock_query_variable_info_pre_hook() mock_query_variable_info_post_hook() The pre hooks each take the same arguments as their mocked namesake, and they fire before any input validation. The post hooks take an additional EFI_STATUS argument. The post hook fires immediately before any return from the mocked namesake function. For SetVariable(), the arguments when the post hook fires are the current contents of the variable if status is EFI_SUCCESS, and whatever arguments were passed in if status is any other value. For everything else, the arguments are the correct results on EFI_SUCCESS, and whatever was passed in if status is any other value. Signed-off-by: Peter Jones --- mock-variables.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) (limited to 'mock-variables.c') diff --git a/mock-variables.c b/mock-variables.c index e02febec..6a9a9dea 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -29,6 +29,116 @@ mock_sort_policy_t mock_variable_sort_policy = MOCK_SORT_APPEND; UINT32 mock_variable_delete_attr_policy; +mock_set_variable_pre_hook_t *mock_set_variable_pre_hook = NULL; +mock_set_variable_post_hook_t *mock_set_variable_post_hook = NULL; +mock_get_variable_pre_hook_t *mock_get_variable_pre_hook = NULL; +mock_get_variable_post_hook_t *mock_get_variable_post_hook = NULL; +mock_get_next_variable_name_pre_hook_t *mock_get_next_variable_name_pre_hook = NULL; +mock_get_next_variable_name_post_hook_t *mock_get_next_variable_name_post_hook = NULL; +mock_query_variable_info_pre_hook_t *mock_query_variable_info_pre_hook = NULL; +mock_query_variable_info_post_hook_t *mock_query_variable_info_post_hook = NULL; + +static EFI_STATUS +mock_sv_pre_hook(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, + VOID *data) +{ + EFI_STATUS status = EFI_SUCCESS; + if (mock_set_variable_pre_hook) + status = mock_set_variable_pre_hook(name, guid, + attrs, size, data); + return status; +} + +static void +mock_sv_post_hook_(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, + VOID *data, EFI_STATUS *status, mock_variable_op_t op, + const char * const file, const int line, + const char * const func) +{ + if (mock_set_variable_post_hook) + mock_set_variable_post_hook(name, guid, attrs, size, + data, status, op, file, line, func); +} +#define mock_sv_post_hook(name, guid, attrs, size, data, status, op) \ + mock_sv_post_hook_(name, guid, attrs, size, data, status, op,\ + __FILE__, __LINE__, __func__) + +static EFI_STATUS +mock_gv_pre_hook(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, + VOID *data) +{ + EFI_STATUS status = EFI_SUCCESS; + if (mock_get_variable_pre_hook) + status = mock_get_variable_pre_hook(name, guid, + attrs, size, data); + return status; +} + +static void +mock_gv_post_hook_(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, + VOID *data, EFI_STATUS *status, const char * const file, + const int line, const char * const func) +{ + if (mock_get_variable_post_hook) + mock_get_variable_post_hook(name, guid, attrs, size, data, + status, file, line, func); +} +#define mock_gv_post_hook(name, guid, attrs, size, data, status) \ + mock_gv_post_hook_(name, guid, attrs, size, data, status,\ + __FILE__, __LINE__, __func__) + +static EFI_STATUS +mock_gnvn_pre_hook(UINTN *size, CHAR16 *name, EFI_GUID *guid) +{ + EFI_STATUS status = EFI_SUCCESS; + if (mock_get_next_variable_name_pre_hook) + status = mock_get_next_variable_name_pre_hook(size, name, guid); + return status; +} + +static void +mock_gnvn_post_hook_(UINTN *size, CHAR16 *name, EFI_GUID *guid, + EFI_STATUS *status, const char * const file, + const int line, const char * const func) +{ + if (mock_get_next_variable_name_post_hook) + mock_get_next_variable_name_post_hook(size, name, guid, status, + file, line, func); +} +#define mock_gnvn_post_hook(size, name, guid, status) \ + mock_gnvn_post_hook_(size, name, guid, status,\ + __FILE__, __LINE__, __func__) + +static EFI_STATUS +mock_qvi_pre_hook(UINT32 attrs, UINT64 *max_var_storage, + UINT64 *remaining_var_storage, UINT64 *max_var_size) +{ + EFI_STATUS status = EFI_SUCCESS; + if (mock_query_variable_info_pre_hook) + status = mock_query_variable_info_pre_hook( + attrs, max_var_storage, + remaining_var_storage, max_var_size); + return status; +} + +static void +mock_qvi_post_hook_(UINT32 attrs, UINT64 *max_var_storage, + UINT64 *remaining_var_storage, UINT64 *max_var_size, + EFI_STATUS *status, const char * const file, + const int line, const char * const func) +{ + if (mock_query_variable_info_post_hook) + mock_query_variable_info_post_hook(attrs, max_var_storage, + remaining_var_storage, + max_var_size, status, + file, line, func); +} +#define mock_qvi_post_hook(attrs, max_var_storage, remaining_var_storage,\ + max_var_size, status) \ + mock_qvi_post_hook_(attrs, max_var_storage, remaining_var_storage,\ + max_var_size, status, \ + __FILE__, __LINE__, __func__) + static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c"); static int @@ -113,8 +223,13 @@ mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, struct mock_variable *result = NULL; EFI_STATUS status; + status = mock_gv_pre_hook(name, guid, attrs, size, data); + if (EFI_ERROR(status)) + return status; + if (name == NULL || guid == NULL || size == NULL) { status = EFI_INVALID_PARAMETER; + mock_gv_post_hook(name, guid, attrs, size, data, &status); return status; } @@ -134,20 +249,27 @@ mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, if (var->size > *size) { *size = var->size; status = EFI_BUFFER_TOO_SMALL; + mock_gv_post_hook(name, guid, attrs, size, data, + &status); return status; } if (data == NULL) { status = EFI_INVALID_PARAMETER; + mock_gv_post_hook(name, guid, attrs, size, data, + &status); return status; } *size = var->size; memcpy(data, var->data, var->size); status = EFI_SUCCESS; + mock_gv_post_hook(name, guid, attrs, size, data, + &status); return status; } } status = EFI_NOT_FOUND; + mock_gv_post_hook(name, guid, attrs, size, data, &status); return status; } @@ -160,6 +282,7 @@ mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid, if (*size < StrSize(result->name)) { *size = StrSize(result->name); status = EFI_BUFFER_TOO_SMALL; + mock_gnvn_post_hook(size, name, guid, &status); #if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) printf("%s:%d:%s(): returning %lx\n", __FILE__, __LINE__-1, __func__, status); @@ -172,6 +295,7 @@ mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid, memcpy(guid, &result->guid, sizeof(EFI_GUID)); status = EFI_SUCCESS; + mock_gnvn_post_hook(size, name, guid, &status); #if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) printf("%s:%d:%s(): returning %lx\n", __FILE__, __LINE__-1, __func__, status); @@ -191,8 +315,13 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) bool found = false; EFI_STATUS status; + status = mock_gnvn_pre_hook(size, name, guid); + if (EFI_ERROR(status)) + return status; + if (size == NULL || name == NULL || guid == NULL) { status = EFI_INVALID_PARAMETER; + mock_gnvn_post_hook(size, name, guid, &status); return status; } @@ -205,6 +334,7 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) if (found == false) { status = EFI_INVALID_PARAMETER; + mock_gnvn_post_hook(size, name, guid, &status); return status; } @@ -277,11 +407,13 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) status = EFI_NOT_FOUND; else status = EFI_INVALID_PARAMETER; + mock_gnvn_post_hook(size, name, guid, &status); return status; } if (!result) { status = EFI_NOT_FOUND; + mock_gnvn_post_hook(size, name, guid, &status); return status; } @@ -409,10 +541,14 @@ mock_delete_variable(struct mock_variable *var) if (EFI_ERROR(status)) { printf("%s:%d:%s(): status:0x%lx\n", __FILE__, __LINE__ - 1, __func__, status); + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, DELETE); return status; } status = EFI_SUCCESS; + mock_sv_post_hook(var->name, &var->guid, var->attrs, 0, 0, &status, + DELETE); free_var(var); return status; } @@ -426,6 +562,8 @@ mock_replace_variable(struct mock_variable *var, VOID *data, UINTN size) status = mock_sv_adjust_usage_data(var->attrs, size, - var->size + size); if (EFI_ERROR(status)) { + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, REPLACE); return status; } @@ -437,6 +575,8 @@ mock_replace_variable(struct mock_variable *var, VOID *data, UINTN size) size); #endif status = EFI_OUT_OF_RESOURCES; + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, REPLACE); return status; } memcpy(new, data, size); @@ -445,6 +585,8 @@ mock_replace_variable(struct mock_variable *var, VOID *data, UINTN size) var->size = size; status = EFI_SUCCESS; + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, REPLACE); return status; } @@ -456,11 +598,15 @@ mock_sv_extend(struct mock_variable *var, VOID *data, UINTN size) if (size == 0) { status = EFI_SUCCESS; + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, APPEND); return status; } status = mock_sv_adjust_usage_data(var->attrs, var->size + size, size); if (EFI_ERROR(status)) { + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, APPEND); return status; } @@ -472,6 +618,8 @@ mock_sv_extend(struct mock_variable *var, VOID *data, UINTN size) var->size + size); #endif status = EFI_OUT_OF_RESOURCES; + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, APPEND); return status; } @@ -480,6 +628,8 @@ mock_sv_extend(struct mock_variable *var, VOID *data, UINTN size) var->size += size; status = EFI_SUCCESS; + mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size, + var->data, &status, APPEND); return status; } @@ -574,14 +724,22 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, EFI_STATUS status; long cmp = -1; + status = mock_sv_pre_hook(name, guid, attrs, size, data); + if (EFI_ERROR(status)) + return status; + if (!name || name[0] == 0 || !guid) { status = EFI_INVALID_PARAMETER; + mock_sv_post_hook(name, guid, attrs, size, data, &status, + CREATE); return status; } if ((attrs & EFI_VARIABLE_RUNTIME_ACCESS) && !(attrs & EFI_VARIABLE_BOOTSERVICE_ACCESS)) { status = EFI_INVALID_PARAMETER; + mock_sv_post_hook(name, guid, attrs, size, data, &status, + CREATE); return status; } @@ -592,6 +750,8 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, */ if (has_exited_boot_services() && !(attrs & EFI_VARIABLE_RUNTIME_ACCESS)) { status = EFI_INVALID_PARAMETER; + mock_sv_post_hook(name, guid, attrs, size, data, &status, + CREATE); return status; } #endif @@ -605,6 +765,8 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)) { status = EFI_UNSUPPORTED; + mock_sv_post_hook(name, guid, attrs, size, data, &status, + CREATE); return status; } #endif @@ -682,9 +844,13 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, #endif status = mock_new_variable(name, guid, attrs, size, data, &var); if (EFI_ERROR(status)) { + mock_sv_post_hook(name, guid, attrs, size, data, + &status, CREATE); return status; } mock_sv_adjust_usage_data(attrs, size, totalsz); + mock_sv_post_hook(name, guid, attrs, size, data, + &status, CREATE); if (EFI_ERROR(status)) { mock_sv_adjust_usage_data(attrs, 0, -totalsz); return status; @@ -725,6 +891,8 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, __FILE__, __LINE__ - 1, __func__, format_var_attrs(var->attrs), format_var_attrs(attrs)); + mock_sv_post_hook(name, guid, attrs, size, data, + &status, REPLACE); return status; } } @@ -760,10 +928,18 @@ mock_query_variable_info(UINT32 attrs, UINT64 *max_var_storage, struct mock_variable_limits *limits = NULL; EFI_STATUS status; + status = mock_qvi_pre_hook(attrs, max_var_storage, + remaining_var_storage, max_var_size); + if (EFI_ERROR(status)) + return status; + if (max_var_storage == NULL || remaining_var_storage == NULL || max_var_size == NULL) { status = EFI_INVALID_PARAMETER; + mock_qvi_post_hook(attrs, max_var_storage, + remaining_var_storage, max_var_size, + &status); return status; } @@ -773,12 +949,18 @@ mock_query_variable_info(UINT32 attrs, UINT64 *max_var_storage, *max_var_storage = *limits->max_var_storage; *remaining_var_storage = *limits->remaining_var_storage; *max_var_size = *limits->max_var_size; + status = EFI_SUCCESS; + mock_qvi_post_hook(attrs, max_var_storage, + remaining_var_storage, max_var_size, + &status); return status; } } status = EFI_UNSUPPORTED; + mock_qvi_post_hook(attrs, max_var_storage, remaining_var_storage, + max_var_size, &status); return status; } @@ -991,6 +1173,15 @@ mock_reset_variables(void) init_efi_system_table(); + mock_set_variable_pre_hook = NULL; + mock_set_variable_post_hook = NULL; + mock_get_variable_pre_hook = NULL; + mock_get_variable_post_hook = NULL; + mock_get_next_variable_name_pre_hook = NULL; + mock_get_next_variable_name_post_hook = NULL; + mock_query_variable_info_pre_hook = NULL; + mock_query_variable_info_post_hook = NULL; + if (once) { INIT_LIST_HEAD(&mock_variables); once = false; -- cgit v1.2.3 From 63a5ae1f7c9383f43e4431316eb0c77bcb079b98 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 26 Jul 2021 17:29:15 -0400 Subject: tests: Add config table support This adds a simple implementation of ST->ConfigurationTable, ST->NumberOfTableEntries, and BS->InstallConfigurationTable to our test harness. Currently it is limited at 1024 entries, but that should be well more than enough for any tests we've currently considered. Signed-off-by: Peter Jones --- include/mock-variables.h | 9 +- mock-variables.c | 171 ++++++++++++++++++- test-mock-variables.c | 421 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 599 insertions(+), 2 deletions(-) (limited to 'mock-variables.c') diff --git a/include/mock-variables.h b/include/mock-variables.h index fc276ce7..759fd1f0 100644 --- a/include/mock-variables.h +++ b/include/mock-variables.h @@ -21,6 +21,8 @@ EFI_STATUS EFIAPI mock_query_variable_info(UINT32 attrs, UINT64 *remaining_var_storage, UINT64 *max_var_size); +EFI_STATUS EFIAPI mock_install_configuration_table(EFI_GUID *guid, VOID *table); + struct mock_variable_limits { UINT32 attrs; UINT64 *max_var_storage; @@ -40,6 +42,7 @@ typedef enum { } mock_sort_policy_t; extern mock_sort_policy_t mock_variable_sort_policy; +extern mock_sort_policy_t mock_config_table_sort_policy; #define MOCK_VAR_DELETE_ATTR_ALLOW_ZERO 0x01 #define MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH 0x02 @@ -110,7 +113,8 @@ void mock_load_variables(const char *const dirname, const char *filters[], void mock_install_query_variable_info(void); void mock_uninstall_query_variable_info(void); void mock_reset_variables(void); -void mock_finalize_vars(void); +void mock_reset_config_table(void); +void mock_finalize_vars_and_configs(void); typedef enum { NONE = 0, @@ -171,5 +175,8 @@ typedef void (mock_query_variable_info_post_hook_t)( const int line, const char * const func); extern mock_query_variable_info_post_hook_t *mock_query_variable_info_post_hook; +#define MOCK_CONFIG_TABLE_ENTRIES 1024 +extern EFI_CONFIGURATION_TABLE mock_config_table[MOCK_CONFIG_TABLE_ENTRIES]; + #endif /* !SHIM_MOCK_VARIABLES_H_ */ // vim:fenc=utf-8:tw=75:noet diff --git a/mock-variables.c b/mock-variables.c index 6a9a9dea..e9bce544 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -26,6 +26,7 @@ list_t *mock_sv_limits = &mock_default_variable_limits; list_t mock_variables = LIST_HEAD_INIT(mock_variables); mock_sort_policy_t mock_variable_sort_policy = MOCK_SORT_APPEND; +mock_sort_policy_t mock_config_table_sort_policy = MOCK_SORT_APPEND; UINT32 mock_variable_delete_attr_policy; @@ -1165,6 +1166,140 @@ mock_uninstall_query_variable_info(void) RT->QueryVariableInfo = mock_efi_unsupported; } +EFI_CONFIGURATION_TABLE mock_config_table[MOCK_CONFIG_TABLE_ENTRIES] = { + { + .VendorGuid = { 0, }, + .VendorTable = NULL + }, +}; + +int +mock_config_table_cmp(const void *p0, const void *p1) +{ + EFI_CONFIGURATION_TABLE *entry0, *entry1; + long cmp; + + if (!p0 || !p1) { + cmp = (int)((intptr_t)p0 - (intptr_t)p1); + } else { + entry0 = (EFI_CONFIGURATION_TABLE *)p0; + entry1 = (EFI_CONFIGURATION_TABLE *)p1; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("comparing %p to %p\n", p0, p1); +#endif + cmp = CompareGuid(&entry0->VendorGuid, &entry1->VendorGuid); + } + + if (mock_config_table_sort_policy == MOCK_SORT_DESCENDING) { + cmp = -cmp; + } + + return cmp; +} + +EFI_STATUS EFIAPI +mock_install_configuration_table(EFI_GUID *guid, VOID *table) +{ + bool found = false; + EFI_CONFIGURATION_TABLE *entry; + int idx = 0; + size_t sz; + + if (!guid) + return EFI_INVALID_PARAMETER; + + for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) { + EFI_CONFIGURATION_TABLE *entry = &ST->ConfigurationTable[i]; + + if (CompareGuid(guid, &entry->VendorGuid) == 0) { + found = true; + if (table) { + // replace it + entry->VendorTable = table; + } else { + // delete it + ST->NumberOfTableEntries -= 1; + sz = ST->NumberOfTableEntries - i; + sz *= sizeof(*entry); + memmove(&entry[0], &entry[1], sz); + } + return EFI_SUCCESS; + } + } + if (!found && table == NULL) + return EFI_NOT_FOUND; + if (ST->NumberOfTableEntries == MOCK_CONFIG_TABLE_ENTRIES - 1) { + /* + * If necessary, we could allocate another table and copy + * the data, but I'm lazy and we probably don't need to. + */ + return EFI_OUT_OF_RESOURCES; + } + + switch (mock_config_table_sort_policy) { + case MOCK_SORT_DESCENDING: + case MOCK_SORT_ASCENDING: + case MOCK_SORT_APPEND: + idx = ST->NumberOfTableEntries; + break; + case MOCK_SORT_PREPEND: + sz = ST->NumberOfTableEntries ? ST->NumberOfTableEntries : 0; + sz *= sizeof(ST->ConfigurationTable[0]); + memmove(&ST->ConfigurationTable[1], &ST->ConfigurationTable[0], sz); + idx = 0; + break; + default: + break; + } + + entry = &ST->ConfigurationTable[idx]; + memcpy(&entry->VendorGuid, guid, sizeof(EFI_GUID)); + entry->VendorTable = table; +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): installing entry %p={%p,%p} as entry %d\n", + __FILE__, __LINE__, __func__, + entry, &entry->VendorGuid, entry->VendorTable, idx); +#endif + ST->NumberOfTableEntries += 1; + +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s():ST->ConfigurationTable:%p\n" + "\t[%d]:%p\n" + "\t[%d]:%p\n", + __FILE__, __LINE__, __func__, ST->ConfigurationTable, + 0, &ST->ConfigurationTable[0], + 1, &ST->ConfigurationTable[1]); +#endif + switch (mock_config_table_sort_policy) { + case MOCK_SORT_DESCENDING: + case MOCK_SORT_ASCENDING: +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): entries before sorting:\n", __FILE__, __LINE__, __func__); + for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) { + printf("\t[%d] = %p = {", i, &ST->ConfigurationTable[i]); + printf(".VendorGuid=" GUID_FMT, GUID_ARGS(ST->ConfigurationTable[i].VendorGuid)); + printf(".VendorTable=%p}\n", ST->ConfigurationTable[i].VendorTable); + } +#endif + qsort(&ST->ConfigurationTable[0], ST->NumberOfTableEntries, + sizeof(ST->ConfigurationTable[0]), + mock_config_table_cmp); + break; + default: + break; + } +#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) + printf("%s:%d:%s(): entries:\n", __FILE__, __LINE__, __func__); + for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) { + printf("\t[%d] = %p = {", i, &ST->ConfigurationTable[i]); + printf(".VendorGuid=" GUID_FMT, GUID_ARGS(ST->ConfigurationTable[i].VendorGuid)); + printf(".VendorTable=%p}\n", ST->ConfigurationTable[i].VendorTable); + } +#endif + + return EFI_SUCCESS; +} + void CONSTRUCTOR mock_reset_variables(void) { @@ -1222,10 +1357,44 @@ mock_reset_variables(void) mock_uninstall_query_variable_info(); } +void CONSTRUCTOR +mock_reset_config_table(void) +{ + init_efi_system_table(); + + /* + * Note that BS->InstallConfigurationTable() is *not* defined as + * freeing these. If a test case installs non-malloc()ed tables, + * it needs to call BS->InstallConfigurationTable(guid, NULL) to + * clear them. + */ + for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) { + EFI_CONFIGURATION_TABLE *entry = &ST->ConfigurationTable[i]; + + if (entry->VendorTable) + free(entry->VendorTable); + } + + SetMem(ST->ConfigurationTable, + ST->NumberOfTableEntries * sizeof(EFI_CONFIGURATION_TABLE), + 0); + + ST->NumberOfTableEntries = 0; + + if (ST->ConfigurationTable != mock_config_table) { + free(ST->ConfigurationTable); + ST->ConfigurationTable = mock_config_table; + SetMem(mock_config_table, sizeof(mock_config_table), 0); + } + + BS->InstallConfigurationTable = mock_install_configuration_table; +} + void DESTRUCTOR -mock_finalize_vars(void) +mock_finalize_vars_and_configs(void) { mock_reset_variables(); + mock_reset_config_table(); } // vim:fenc=utf-8:tw=75:noet diff --git a/test-mock-variables.c b/test-mock-variables.c index 5ea5a981..c7e42b05 100644 --- a/test-mock-variables.c +++ b/test-mock-variables.c @@ -8,6 +8,7 @@ #include "mock-variables.h" #include +#include #include #include #include @@ -16,6 +17,8 @@ #pragma GCC diagnostic ignored "-Wunused-label" +static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c"); + void mock_print_guidname(EFI_GUID *guid, CHAR16 *name); void mock_print_var_list(list_t *head); @@ -386,6 +389,421 @@ err: return ret; } +static void +dump_config_table_if_wrong(const char * const func, int line, ...) +{ + va_list alist, blist; + bool okay = true; + size_t n = 0, m = 0; + + va_start(alist, line); + va_copy(blist, alist); + + int idx = va_arg(alist, int); + EFI_GUID *guid = va_arg(alist, EFI_GUID *); + while (idx >= 0 && guid != NULL) { + EFI_CONFIGURATION_TABLE *entry; + if (idx < 0) + goto nexta; + + n += 1; + if (idx >= (int)ST->NumberOfTableEntries) { + okay = false; + goto nexta; + } + + entry = &ST->ConfigurationTable[idx]; + if (CompareGuid(guid, &entry->VendorGuid) != 0) + okay = false; + +nexta: + idx = va_arg(alist, int); + guid = va_arg(alist, EFI_GUID *); + } + va_end(alist); + + if (okay) + return; + + printf("%s:%d:%s(): %d entries:\n", __FILE__, line, func, ST->NumberOfTableEntries); + idx = va_arg(blist, int); + guid = va_arg(blist, EFI_GUID *); + while (idx >= 0 && guid != NULL) { + EFI_CONFIGURATION_TABLE *entry; + + if (idx >= (int)ST->NumberOfTableEntries) { + printf("\t[%d]: invalid index for " GUID_FMT "\n", + idx, GUID_ARGS(*guid)); + goto nexta; + } + + if (idx < 0) { + printf("\t[%d]: " GUID_FMT "\n", idx, GUID_ARGS(*guid)); + } else { + entry = &ST->ConfigurationTable[idx]; + printf("\t[%d]: %p ", idx, entry); + printf("{.VendorGuid:" GUID_FMT ",", GUID_ARGS(entry->VendorGuid)); + printf("&.VendorTable:%p}\n", entry->VendorTable); + if (CompareGuid(guid, &entry->VendorGuid) != 0) + printf("\t\t\t expected:" GUID_FMT "\n", GUID_ARGS(*guid)); + } +next: + idx = va_arg(blist, int); + guid = va_arg(blist, EFI_GUID *); + } + va_end(blist); + + if ((int)ST->NumberOfTableEntries - n == 0) + return; + + printf("%d extra table entries:\n", ST->NumberOfTableEntries - n); + for (m = n; m < ST->NumberOfTableEntries; m++) { + EFI_CONFIGURATION_TABLE *entry; + + entry = &ST->ConfigurationTable[m]; + + printf("\t[%d]: %p ", m, entry); + printf("{.VendorGuid:" GUID_FMT ",", GUID_ARGS(entry->VendorGuid)); + printf("&.VendorTable:%p}\n", entry->VendorTable); + } +} + +static int +test_install_config_table_0(void) +{ + int ret = -1; + EFI_STATUS status; + + /* + * These three guids are chosen on purpose: they start with "a", + * "b", and "c", respective to their variable names, so you can + * identify them when dumped. + */ + EFI_GUID aguid = SECURITY_PROTOCOL_GUID; + char astr[guidstr_size]; + void *astrp = &astr[0]; + int aidx = -1; + + EFI_GUID bguid = EFI_HTTP_BINDING_GUID; + char bstr[guidstr_size]; + void *bstrp = &bstr[0]; + int bidx = -1; + + EFI_GUID cguid = MOK_VARIABLE_STORE; + char cstr[guidstr_size]; + void *cstrp = &cstr[0]; + int cidx = -1; + + EFI_GUID lip = LOADED_IMAGE_PROTOCOL; + + EFI_GUID guids[3]; + + char tmpstr[guidstr_size]; + + sprintf(astrp, GUID_FMT, GUID_ARGS(aguid)); + sprintf(bstrp, GUID_FMT, GUID_ARGS(bguid)); + sprintf(cstrp, GUID_FMT, GUID_ARGS(cguid)); + + assert_equal_return(ST->NumberOfTableEntries, 0, -1, "%lu != %lu\n"); + + /* + * test installing one + */ + status = BS->InstallConfigurationTable(&bguid, bstrp); + assert_equal_return(status, EFI_SUCCESS, -1, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 1, err, "%lu != %lu\n"); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[0].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[0].VendorGuid, &bguid), + err, "%d != 0 (%s != %s)\n", tmpstr, bstr); + assert_equal_goto(ST->ConfigurationTable[0].VendorTable, + bstrp, err, "%p != %p\n"); + + /* + * test re-installing the same one + */ + status = BS->InstallConfigurationTable(&bguid, bstrp); + assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 1, err, "%lu != %lu\n"); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[0].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[0].VendorGuid, &bguid), + err, "%d != 0 (%s != %s)\n", tmpstr, bstr); + assert_equal_goto(ST->ConfigurationTable[0].VendorTable, + bstrp, err, "%p != %p\n"); + + /* + * Test installing a second one + */ + status = BS->InstallConfigurationTable(&aguid, astrp); + assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 2, err, "%lu != %lu\n"); + + switch (mock_config_table_sort_policy) { + case MOCK_SORT_DESCENDING: + aidx = 1; + bidx = 0; + break; + case MOCK_SORT_PREPEND: + aidx = 0; + bidx = 1; + break; + case MOCK_SORT_APPEND: + aidx = 1; + bidx = 0; + break; + case MOCK_SORT_ASCENDING: + aidx = 0; + bidx = 1; + break; + default: + break; + } + + dump_config_table_if_wrong(__func__, __LINE__, + aidx, &aguid, + bidx, &bguid, + cidx, &cguid, + -1, NULL); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid), + err, "%d != 0 (%s != %s)\n", tmpstr, astr); + assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp, + err, "%p != %p\n"); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid), + err, "%d != 0 (%s != %s)\n", tmpstr, bstr); + assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp, + err, "%p != %p\n"); + + /* + * Test installing a third one + */ + status = BS->InstallConfigurationTable(&cguid, cstrp); + assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 3, err, "%lu != %lu\n"); + + switch (mock_config_table_sort_policy) { + case MOCK_SORT_DESCENDING: + aidx = 2; + bidx = 1; + cidx = 0; + break; + case MOCK_SORT_PREPEND: + aidx = 1; + bidx = 2; + cidx = 0; + break; + case MOCK_SORT_APPEND: + aidx = 1; + bidx = 0; + cidx = 2; + break; + case MOCK_SORT_ASCENDING: + aidx = 0; + bidx = 1; + cidx = 2; + break; + default: + break; + } + + dump_config_table_if_wrong(__func__, __LINE__, + aidx, &aguid, + bidx, &bguid, + cidx, &cguid, + -1, NULL); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid), + err, "%d != 0 (%s != %s)\n", tmpstr, astr); + assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp, + err, "%p != %p\n"); + memcpy(&guids[aidx], &aguid, sizeof(EFI_GUID)); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid), + err, "%d != 0 (%s != %s)\n", tmpstr, bstr); + assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp, + err, "%p != %p\n"); + memcpy(&guids[bidx], &bguid, sizeof(EFI_GUID)); + + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[cidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[cidx].VendorGuid, &cguid), + err, "%d != 0 (%s != %s)\n", tmpstr, cstr); + assert_equal_goto(ST->ConfigurationTable[cidx].VendorTable, cstrp, + err, "%p != %p\n"); + memcpy(&guids[cidx], &cguid, sizeof(EFI_GUID)); + + /* + * Test removing NULL guid + */ + status = BS->InstallConfigurationTable(NULL, NULL); + assert_equal_goto(status, EFI_INVALID_PARAMETER, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 3, err, "%lu != %lu\n"); + + /* + * Test removing a guid that's not present + */ + status = BS->InstallConfigurationTable(&lip, NULL); + assert_equal_goto(status, EFI_NOT_FOUND, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 3, err, "%lu != %lu\n"); + + /* + * Test removing the middle one + */ + status = BS->InstallConfigurationTable(&guids[1], NULL); + assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 2, err, "%lu != %lu\n"); + + switch (mock_config_table_sort_policy) { + case MOCK_SORT_DESCENDING: + aidx = 1; + bidx = -1; + cidx = 0; + break; + case MOCK_SORT_PREPEND: + aidx = -1; + bidx = 1; + cidx = 0; + break; + case MOCK_SORT_APPEND: + aidx = -1; + bidx = 0; + cidx = 1; + break; + case MOCK_SORT_ASCENDING: + aidx = 0; + bidx = -1; + cidx = 1; + break; + default: + break; + } + + dump_config_table_if_wrong(__func__, __LINE__, + aidx, &aguid, + bidx, &bguid, + cidx, &cguid, + -1, NULL); + + if (aidx >= 0) { + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid), + err, "%d != 0 (%s != %s)\n", tmpstr, astr); + assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp, + err, "%p != %p\n"); + memcpy(&guids[aidx], &aguid, sizeof(EFI_GUID)); + } + + if (bidx >= 0) { + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid), + err, "%d != 0 (%s != %s)\n", tmpstr, bstr); + assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp, + err, "%p != %p\n"); + memcpy(&guids[bidx], &bguid, sizeof(EFI_GUID)); + } + + if (cidx >= 0) { + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[cidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[cidx].VendorGuid, &cguid), + err, "%d != 0 (%s != %s)\n", tmpstr, cstr); + assert_equal_goto(ST->ConfigurationTable[cidx].VendorTable, cstrp, + err, "%p != %p\n"); + memcpy(&guids[cidx], &cguid, sizeof(EFI_GUID)); + } + + /* + * Test removing the lowest one + */ + status = BS->InstallConfigurationTable(&guids[0], NULL); + assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 1, err, "%lu != %lu\n"); + + switch (mock_config_table_sort_policy) { + case MOCK_SORT_DESCENDING: + aidx = 0; + bidx = -1; + cidx = -1; + break; + case MOCK_SORT_PREPEND: + aidx = -1; + bidx = 0; + cidx = -1; + break; + case MOCK_SORT_APPEND: + aidx = -1; + bidx = -1; + cidx = 0; + break; + case MOCK_SORT_ASCENDING: + aidx = -1; + bidx = -1; + cidx = 0; + break; + default: + break; + } + + dump_config_table_if_wrong(__func__, __LINE__, + aidx, &aguid, + bidx, &bguid, + cidx, &cguid, + -1, NULL); + + if (aidx >= 0) { + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[aidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[aidx].VendorGuid, &aguid), + err, "%d != 0 (%s != %s)\n", tmpstr, astr); + assert_equal_goto(ST->ConfigurationTable[aidx].VendorTable, astrp, + err, "%p != %p\n"); + memcpy(&guids[aidx], &aguid, sizeof(EFI_GUID)); + } + + if (bidx >= 0) { + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[bidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[bidx].VendorGuid, &bguid), + err, "%d != 0 (%s != %s)\n", tmpstr, bstr); + assert_equal_goto(ST->ConfigurationTable[bidx].VendorTable, bstrp, + err, "%p != %p\n"); + memcpy(&guids[bidx], &bguid, sizeof(EFI_GUID)); + } + + if (cidx >= 0) { + sprintf(tmpstr, GUID_FMT, GUID_ARGS(ST->ConfigurationTable[cidx].VendorGuid)); + assert_zero_goto(CompareGuid(&ST->ConfigurationTable[cidx].VendorGuid, &cguid), + err, "%d != 0 (%s != %s)\n", tmpstr, cstr); + assert_equal_goto(ST->ConfigurationTable[cidx].VendorTable, cstrp, + err, "%p != %p\n"); + memcpy(&guids[cidx], &cguid, sizeof(EFI_GUID)); + } + + /* + * Test removing the last one + */ + status = BS->InstallConfigurationTable(&guids[0], NULL); + assert_equal_goto(status, EFI_SUCCESS, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 0, err, "%lu != %lu\n"); + + /* + * Test removing it again + */ + status = BS->InstallConfigurationTable(&guids[0], NULL); + assert_equal_goto(status, EFI_NOT_FOUND, err, "%lx != %lx\n"); + assert_equal_goto(ST->NumberOfTableEntries, 0, err, "%lu != %lu\n"); + + ret = 0; +err: + while (ST->NumberOfTableEntries) + BS->InstallConfigurationTable(&ST->ConfigurationTable[0].VendorGuid, NULL); + mock_reset_config_table(); + + return ret; +} + int main(void) { @@ -405,12 +823,15 @@ main(void) for (int i = 0; i < MOCK_SORT_MAX_SENTINEL; i++) { mock_variable_sort_policy = i; + mock_config_table_sort_policy = i; printf("%s: setting variable sort policy to %s\n", program_invocation_short_name, policies[i]); test(test_gnvn_buf_size_0); test(test_gnvn_0); test(test_gnvn_1); + + test(test_install_config_table_0); } test(test_get_variable_0); -- cgit v1.2.3 From 4df989abdf893326cb866e153b24ddaf2b29d0d7 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Wed, 20 Apr 2022 15:18:17 +0000 Subject: mock-variables.c: fix gcc warning $ make test ... mock-variables.c: In function 'mock_sv_attrs_match': mock-variables.c:448:23: error: conversion from 'long unsigned int' to 'UINT32' {aka 'unsigned int'} changes value from '18446744073709551551' to '4294967231' [-Werror=overflow] 448 | UINT32 mask = ~EFI_VARIABLE_APPEND_WRITE; | ^ cc1: all warnings being treated as errors Signed-off-by: Alexey Kodanev --- mock-variables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mock-variables.c') diff --git a/mock-variables.c b/mock-variables.c index e9bce544..03044549 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -445,7 +445,7 @@ free_var(struct mock_variable *var) static bool mock_sv_attrs_match(UINT32 old, UINT32 new) { - UINT32 mask = ~EFI_VARIABLE_APPEND_WRITE; + UINT32 mask = ~((UINT32)EFI_VARIABLE_APPEND_WRITE); return (old & mask) == (new & mask); } -- cgit v1.2.3 From 9229e7caea9133484aa18178cb713f2a2f1e93d0 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 20 Sep 2021 17:06:01 -0400 Subject: Make mock_set_variable() correctly account for resource usage. When SetVariable() is called, currently the test for being out of space is correct, but the accounting is backwards - success adds more space available. This fixes the accounting and (with SHIM_DEBUG) logs the variable size. Signed-off-by: Peter Jones --- mock-variables.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'mock-variables.c') diff --git a/mock-variables.c b/mock-variables.c index 03044549..5dc2356d 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -773,9 +773,9 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, #endif #if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) - printf("%s:%d:%s():Setting "GUID_FMT"-%s\n", + printf("%s:%d:%s():Setting "GUID_FMT"-%s size:0x%"PRIx64"\n", __FILE__, __LINE__ - 1, __func__, - GUID_ARGS(*guid), Str2str(name)); + GUID_ARGS(*guid), Str2str(name), size); #endif switch (mock_variable_sort_policy) { case MOCK_SORT_PREPEND: @@ -843,17 +843,17 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, printf("%s:%d:%s():var:%p attrs:0x%lx\n", __FILE__, __LINE__ - 1, __func__, var, attrs); #endif - status = mock_new_variable(name, guid, attrs, size, data, &var); + status = mock_sv_adjust_usage_data(attrs, size, -totalsz); if (EFI_ERROR(status)) { mock_sv_post_hook(name, guid, attrs, size, data, &status, CREATE); return status; } - mock_sv_adjust_usage_data(attrs, size, totalsz); + status = mock_new_variable(name, guid, attrs, size, data, &var); mock_sv_post_hook(name, guid, attrs, size, data, &status, CREATE); if (EFI_ERROR(status)) { - mock_sv_adjust_usage_data(attrs, 0, -totalsz); + mock_sv_adjust_usage_data(attrs, 0, totalsz); return status; } -- cgit v1.2.3 From f7e1d7226de8b9fc005257b8fede70093c547ad5 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 20 Sep 2021 17:09:18 -0400 Subject: tests: make it possible to use different limits for variable space This splits up the API for setting default usage limits, adding a test API function to set alternate usage limits. Signed-off-by: Peter Jones --- include/mock-variables.h | 2 ++ mock-variables.c | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'mock-variables.c') diff --git a/include/mock-variables.h b/include/mock-variables.h index 9f276e63..3f5c5e60 100644 --- a/include/mock-variables.h +++ b/include/mock-variables.h @@ -115,6 +115,8 @@ void mock_uninstall_query_variable_info(void); void mock_reset_variables(void); void mock_reset_config_table(void); void mock_finalize_vars_and_configs(void); +void mock_set_usage_limits(list_t *limit_list, + struct mock_variable_limits *limits); typedef enum { NONE = 0, diff --git a/mock-variables.c b/mock-variables.c index 5dc2356d..656670d5 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -1001,6 +1001,20 @@ static struct mock_variable_limits default_limits[] = { {.attrs = 0, } }; +void +mock_set_usage_limits(list_t *limit_list, + struct mock_variable_limits *limits) +{ + INIT_LIST_HEAD(limit_list); + for (size_t i = 0; limits[i].attrs != 0; i++) { + INIT_LIST_HEAD(&limits[i].list); + list_add_tail(&limits[i].list, limit_list); + } + + mock_qvi_limits = limit_list; + mock_sv_limits = limit_list; +} + void mock_set_default_usage_limits(void) { @@ -1008,12 +1022,7 @@ mock_set_default_usage_limits(void) default_remaining_var_storage = 65536; default_max_var_size = 32768; - INIT_LIST_HEAD(&mock_default_variable_limits); - for (size_t i = 0; default_limits[i].attrs != 0; i++) { - INIT_LIST_HEAD(&default_limits[i].list); - list_add_tail(&default_limits[i].list, - &mock_default_variable_limits); - } + mock_set_usage_limits(&mock_default_variable_limits, &default_limits[0]); } void -- cgit v1.2.3 From e136e645d54983d2b5a89610d1565c23538ca1fa Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 18 Feb 2025 12:55:05 -0500 Subject: mock-variables: fix debugging printf format specifier oopsie This debug printf in our mock variable test code, which isn't normally enabled, has a missing comma at the end of the format specifier. This causes __FILE__ to be part of the format specifier, which then means we've got a missing parameter and also the types don't match up like you'd hope. This causes the most confusing segfaults. Signed-off-by: Peter Jones --- mock-variables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mock-variables.c') diff --git a/mock-variables.c b/mock-variables.c index 656670d5..81828560 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -391,7 +391,7 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) } #if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) if (result) { - printf("%s:%d:%s(): found:%d result:%p &result->guid:%p &result->list:%p\n" + printf("%s:%d:%s(): found:%d result:%p &result->guid:%p &result->list:%p\n", __FILE__, __LINE__-1, __func__, found, result, &result->guid, &result->list); printf("%s:%d:%s(): "GUID_FMT"-%s\n", -- cgit v1.2.3 From f0958baa7cc0fcce0de09323d89dda7bf23afec3 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 18 Feb 2025 15:19:21 -0500 Subject: test-mock-variables: improve some debug prints This changes test-mock-variables and related code to not print all debug messages at SHIM_DEBUG=1, and also adds some prints and comments for context as to what's going on in the tests. Signed-off-by: Peter Jones --- include/test.h | 18 ++++++------ mock-variables.c | 81 +++++++++++++++++++++++++++++++++++++++------------ test-mock-variables.c | 23 +++++++++++++-- 3 files changed, 91 insertions(+), 31 deletions(-) (limited to 'mock-variables.c') diff --git a/include/test.h b/include/test.h index 5261dbd9..ccb61148 100644 --- a/include/test.h +++ b/include/test.h @@ -85,14 +85,14 @@ extern EFI_RUNTIME_SERVICES *RT; static inline INT64 guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): Comparing "GUID_FMT" to "GUID_FMT"\n", __FILE__, __LINE__-1, __func__, GUID_ARGS(*guid0), GUID_ARGS(*guid1)); #endif if (guid0->Data1 != guid1->Data1) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n", __FILE__, __LINE__-1, __func__, (INT64)guid0->Data1, (INT64)guid1->Data1, @@ -102,7 +102,7 @@ guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) } if (guid0->Data2 != guid1->Data2) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n", __FILE__, __LINE__-1, __func__, (INT64)guid0->Data2, (INT64)guid1->Data2, @@ -112,7 +112,7 @@ guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) } if (guid0->Data3 != guid1->Data3) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n", __FILE__, __LINE__-1, __func__, (INT64)guid0->Data3, (INT64)guid1->Data3, @@ -126,7 +126,7 @@ guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) * representation of it. */ if (guid0->Data4[1] != guid1->Data4[1]) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n", __FILE__, __LINE__-1, __func__, (INT64)guid0->Data4[1], (INT64)guid1->Data4[1], @@ -136,7 +136,7 @@ guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) } if (guid0->Data4[0] != guid1->Data4[0]) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n", __FILE__, __LINE__-1, __func__, (INT64)guid0->Data4[0], (INT64)guid1->Data4[0], @@ -147,7 +147,7 @@ guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) for (UINTN i = 2; i < 8; i++) { if (guid0->Data4[i] != guid1->Data4[i]) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x%"PRIx64"-0x%"PRIx64"->0x%"PRIx64"\n", __FILE__, __LINE__-1, __func__, (INT64)guid0->Data4[i], (INT64)guid1->Data4[i], @@ -157,7 +157,7 @@ guidcmp_helper(const EFI_GUID * const guid0, const EFI_GUID * const guid1) } } -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): returning 0x0\n", __FILE__, __LINE__-1, __func__); #endif @@ -177,7 +177,7 @@ guidcmp(const EFI_GUID * const guid0, const EFI_GUID * const guid1) cmp = guidcmp_helper(guida, guidb); ret = cmp < 0 ? -1 : (cmp > 0 ? 1 : 0); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s():CompareGuid("GUID_FMT","GUID_FMT")->%lld (%d)\n", __FILE__, __LINE__-1, __func__, GUID_ARGS(*guida), GUID_ARGS(*guidb), cmp, ret); diff --git a/mock-variables.c b/mock-variables.c index 81828560..723cdda2 100644 --- a/mock-variables.c +++ b/mock-variables.c @@ -163,7 +163,7 @@ variable_cmp(const struct mock_variable * const v0, ret = CompareGuid(&v0->guid, &v1->guid); ret <<= 8ul; -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if (defined(SHIM_DEBUG) && SHIM_DEBUG > 3) printf("%s:%d:%s(): "GUID_FMT" %s "GUID_FMT" (0x%011"PRIx64" %"PRId64")\n", __FILE__, __LINE__-1, __func__, GUID_ARGS(v0->guid), @@ -177,7 +177,7 @@ variable_cmp(const struct mock_variable * const v0, } ret = StrCmp(v0->name, v1->name); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if (defined(SHIM_DEBUG) && SHIM_DEBUG > 3) printf("%s:%d:%s(): \"%s\" %s \"%s\" (0x%02hhx (%d)\n", __FILE__, __LINE__-1, __func__, Str2str(v0->name), @@ -284,7 +284,7 @@ mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid, *size = StrSize(result->name); status = EFI_BUFFER_TOO_SMALL; mock_gnvn_post_hook(size, name, guid, &status); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 3 printf("%s:%d:%s(): returning %lx\n", __FILE__, __LINE__-1, __func__, status); #endif @@ -297,7 +297,7 @@ mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid, status = EFI_SUCCESS; mock_gnvn_post_hook(size, name, guid, &status); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 3 printf("%s:%d:%s(): returning %lx\n", __FILE__, __LINE__-1, __func__, status); #endif @@ -351,15 +351,20 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) struct mock_variable *var; var = list_entry(pos, struct mock_variable, list); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) +# if SHIM_DEBUG > 1 printf("%s:%d:%s(): candidate var:%p &var->guid:%p &var->list:%p\n", __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list); +# elif SHIM_DEBUG > 0 + printf("%s:%d:%s(): candidate var:%p var->guid:" GUID_FMT"\n", + __FILE__, __LINE__-1, __func__, var, GUID_ARGS(var->guid)); +# endif #endif if (name[0] == 0) { if (CompareGuid(&var->guid, guid) == 0) { #if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) - printf("%s:%d:%s(): found\n", - __FILE__, __LINE__-1, __func__); + printf("%s:%d:%s(): found guid in entry var:%p var->name:%p\n", + __FILE__, __LINE__-1, __func__, var, var->name); #endif result = var; found = true; @@ -374,14 +379,14 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) continue; } -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n", __FILE__, __LINE__-1, __func__, GUID_ARGS(goal.guid), Str2str(goal.name), GUID_ARGS(var->guid), Str2str(var->name)); #endif if (variable_cmp(&goal, var) == 0) { -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): found\n", __FILE__, __LINE__-1, __func__); #endif @@ -398,8 +403,8 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) __FILE__, __LINE__-1, __func__, GUID_ARGS(result->guid), Str2str(result->name)); } else { - printf("%s:%d:%s(): not found\n", - __FILE__, __LINE__-1, __func__); + printf("%s:%d:%s(): not found (found:%d status:0x%016x)\n", + __FILE__, __LINE__-1, __func__, found, status); } #endif @@ -408,13 +413,25 @@ mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid) status = EFI_NOT_FOUND; else status = EFI_INVALID_PARAMETER; +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 + printf("%s:%d:%s(): not found (found:%d status:0x%016x)\n", + __FILE__, __LINE__-1, __func__, found, status); +#endif mock_gnvn_post_hook(size, name, guid, &status); +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 + printf("%s:%d:%s(): not found (found:%d status:0x%016x)\n", + __FILE__, __LINE__-1, __func__, found, status); +#endif return status; } if (!result) { status = EFI_NOT_FOUND; mock_gnvn_post_hook(size, name, guid, &status); +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 + printf("%s:%d:%s(): found (found:%d status:0x%016x)\n", + __FILE__, __LINE__-1, __func__, found, status); +#endif return status; } @@ -678,7 +695,7 @@ mock_new_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, } var = (struct mock_variable *)buf; -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): var:%p &var->guid:%p &var->list:%p\n", __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list); #endif @@ -695,7 +712,7 @@ mock_new_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, var->attrs = attrs; INIT_LIST_HEAD(&var->list); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): var: "GUID_FMT"-%s\n", __FILE__, __LINE__-1, __func__, GUID_ARGS(var->guid), Str2str(var->name)); @@ -772,7 +789,7 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, } #endif -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s():Setting "GUID_FMT"-%s size:0x%"PRIx64"\n", __FILE__, __LINE__ - 1, __func__, GUID_ARGS(*guid), Str2str(name), size); @@ -800,7 +817,7 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, list_for_each_safe(pos, tmp, &mock_variables) { found = false; var = list_entry(pos, struct mock_variable, list); -#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n", __FILE__, __LINE__-1, __func__, GUID_ARGS(goal.guid), Str2str(goal.name), @@ -832,14 +849,14 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, if (found) break; } -#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s():var_list:%p &mock_variables:%p cmp:%ld\n", __FILE__, __LINE__ - 1, __func__, var_list, &mock_variables, cmp); #endif if (cmp != 0 || (cmp == 0 && var_list == &mock_variables)) { size_t totalsz = size + StrSize(name); -#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 printf("%s:%d:%s():var:%p attrs:0x%lx\n", __FILE__, __LINE__ - 1, __func__, var, attrs); #endif @@ -857,7 +874,7 @@ mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, return status; } -#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 printf("%s:%d:%s(): Adding "GUID_FMT"-%s %s %s\n", __FILE__, __LINE__ - 1, __func__, GUID_ARGS(var->guid), Str2str(var->name), @@ -1088,7 +1105,8 @@ mock_load_one_variable(int dfd, const char * const dirname, char * const name) name[namelen-1] = 0; #if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0) - printf("loading %s-%s\n", &name[namelen], name); + printf("%s:%d:%s(): loading %s-%s\n", __FILE__, __LINE__, __func__, + &name[namelen], name); #endif for (size_t i = 0; i < namelen; i++) namebuf[i] = name[i]; @@ -1118,6 +1136,9 @@ mock_load_variables(const char *const dirname, const char *filters[], DIR *d; struct dirent *entry; +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("Started loading variablles from \"%s\"\n", dirname); +#endif d = opendir(dirname); if (!d) err(1, "Could not open directory \"%s\"", dirname); @@ -1130,6 +1151,11 @@ mock_load_variables(const char *const dirname, const char *filters[], while ((entry = readdir(d)) != NULL) { size_t len = strlen(entry->d_name); bool found = false; + if (entry->d_type != DT_REG) + continue; +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("%s:%d:%s(): maybe adding entry \"%s\"\n", __FILE__, __LINE__, __func__, entry->d_name); +#endif if (filters && len > guidstr_size + 1) { char spacebuf[len]; @@ -1140,6 +1166,9 @@ mock_load_variables(const char *const dirname, const char *filters[], if (strlen(filters[i]) > len) continue; if (!strncmp(entry->d_name, filters[i], len)) { +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 2 + printf("%s:%d:%s(): filter matched for \"%s\" && \"%s\"\n", __FILE__, __LINE__, __func__, entry->d_name, filters[i]); +#endif found = true; break; } @@ -1147,9 +1176,23 @@ mock_load_variables(const char *const dirname, const char *filters[], } if ((found == false && filter_out == true) || (found == true && filter_out == false)) { +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("%s:%d:%s(): Adding \"%s\" because filter %s\n", + __FILE__, __LINE__-1, __func__, entry->d_name, + found ? "matched" : "did not match"); +#endif mock_load_one_variable(dfd, dirname, entry->d_name); + } else { +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("%s:%d:%s(): Skipping \"%s\" because filter %s\n", + __FILE__, __LINE__-1, __func__, entry->d_name, + found ? "matched" : "did not match"); +#endif } } +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("Done loading variablles from \"%s\"\n", dirname); +#endif closedir(d); #if 0 diff --git a/test-mock-variables.c b/test-mock-variables.c index c7e42b05..79e6628f 100644 --- a/test-mock-variables.c +++ b/test-mock-variables.c @@ -212,14 +212,23 @@ test_gnvn_helper(char *testvars) mock_load_variables(testvars, mok_rt_vars, true); +#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 + dump_mock_variables(__FILE__, __LINE__, __func__); +#endif + + /* + * This tests the sort policy, filtering for only variables in the + * EFI "global" namespace. If ascending the first thing should + * be Boot0000, if descending it should be dbxDefault + */ +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("Testing mock variable sorting in the global namespace\n"); +#endif size = sizeof(buf); buf[0] = L'\0'; status = RT->GetNextVariableName(&size, buf, &GV_GUID); assert_equal_goto(status, EFI_SUCCESS, err, "0x%lx != 0x%lx\n"); -#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0 - dump_mock_variables(__FILE__, __LINE__, __func__); -#endif switch (mock_variable_sort_policy) { case MOCK_SORT_DESCENDING: dump_mock_variables_if_wrong(__FILE__, __LINE__, __func__, @@ -236,6 +245,14 @@ test_gnvn_helper(char *testvars) break; } + /* + * Do it again but test for only variables in the Secure Boot + * policy guid namespace. Ascending should be "db", descending + * "dbx". + */ +#if defined(SHIM_DEBUG) && SHIM_DEBUG >= 1 + printf("Testing mock variable sorting in the Secure Boot GUID namespace\n"); +#endif size = sizeof(buf); buf[0] = 0; status = RT->GetNextVariableName(&size, buf, &EFI_SECURE_BOOT_DB_GUID); -- cgit v1.2.3