diff --git a/handler.c b/handler.c index 37780b0..6e4e5cf 100644 --- a/handler.c +++ b/handler.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -198,6 +199,43 @@ get_space_usage(void) return total; } +static UINTN +get_buf_avail(UINT32 nr_pages, uint8_t *comm_buf, uint8_t *ptr) +{ + ptrdiff_t offset = (ptrdiff_t)ptr - (ptrdiff_t)comm_buf; + ptrdiff_t bufsize = (ptrdiff_t)nr_pages * PAGE_SIZE; + + if (offset < 0 || offset > bufsize) { + assert(0); + return 0; + } + + return (UINTN)(bufsize - offset); +} + +static inline uint8_t * +unserialize_data_checked(UINT32 nr_pages, uint8_t *comm_buf, + uint8_t **ptr, UINTN *len, UINTN limit) +{ + uint8_t *data; + UINTN avail; + + *len = unserialize_uintn(ptr); + avail = get_buf_avail(nr_pages, comm_buf, *ptr); + + if (*len > limit || *len == 0 || *len > avail) + return NULL; + + data = malloc(*len); + if (!data) + return NULL; + + memcpy(data, *ptr, *len); + *ptr += *len; + + return data; +} + /* A limited version of SetVariable for internal use. */ EFI_STATUS internal_set_variable(const uint8_t *name, UINTN name_len, const EFI_GUID *guid, @@ -274,18 +312,19 @@ internal_get_variable(const uint8_t *name, UINTN name_len, const EFI_GUID *guid, } static void -do_get_variable(uint8_t *comm_buf) +do_get_variable(uint8_t *comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command) { uint8_t *ptr, *name; EFI_GUID guid; - UINTN name_len, data_len; + UINTN name_len, data_len, data_avail; BOOLEAN at_runtime; struct efi_variable *l; ptr = comm_buf; - unserialize_uint32(&ptr); /* version */ - unserialize_command(&ptr); - name = unserialize_data(&ptr, &name_len, NAME_LIMIT); + skip_command(&ptr, version, nr_pages, command); + name = unserialize_data_checked(nr_pages, comm_buf, + &ptr, &name_len, NAME_LIMIT); if (!name) { serialize_result(&comm_buf, name_len == 0 ? EFI_NOT_FOUND : EFI_DEVICE_ERROR); return; @@ -295,6 +334,17 @@ do_get_variable(uint8_t *comm_buf) at_runtime = unserialize_boolean(&ptr); ptr = comm_buf; + data_avail = get_buf_avail(nr_pages, comm_buf, ptr) - sizeof(EFI_STATUS) - + sizeof(UINT32); + /* + * DataSize is not firmware-controlled, and callers are not aware of comm + * buffer size. Therefore, we can't return an error code even if DataSize is + * larger than the actual available buffer size; all we can do is to limit + * data_len accordingly. + */ + if (data_len > data_avail) + data_len = data_avail; + l = var_list; while (l) { if (l->name_len == name_len && @@ -307,6 +357,8 @@ do_get_variable(uint8_t *comm_buf) if (data_len < l->data_len) { serialize_result(&ptr, EFI_BUFFER_TOO_SMALL); serialize_uintn(&ptr, l->data_len); + if (version >= 2) + serialize_uint32(&ptr, l->attributes); } else { serialize_result(&ptr, EFI_SUCCESS); serialize_uint32(&ptr, l->attributes); @@ -1584,7 +1636,8 @@ debug_all_variables(const struct efi_variable *l) #endif static void -do_set_variable(uint8_t *comm_buf) +do_set_variable(uint8_t *comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command) { UINTN name_len, data_len; struct efi_variable *l, *prev = NULL; @@ -1597,17 +1650,21 @@ do_set_variable(uint8_t *comm_buf) EFI_TIME timestamp; ptr = comm_buf; - unserialize_uint32(&ptr); /* version */ - unserialize_command(&ptr); - name = unserialize_data(&ptr, &name_len, NAME_LIMIT); + skip_command(&ptr, version, nr_pages, command); + name = unserialize_data_checked(nr_pages, comm_buf, + &ptr, &name_len, NAME_LIMIT); if (!name) { serialize_result(&comm_buf, name_len == 0 ? EFI_INVALID_PARAMETER : EFI_DEVICE_ERROR); return; } unserialize_guid(&ptr, &guid); - data = unserialize_data(&ptr, &data_len, DATA_LIMIT); + data = unserialize_data_checked(nr_pages, comm_buf, + &ptr, &data_len, data_limit(version)); if (!data && data_len) { - serialize_result(&comm_buf, data_len > DATA_LIMIT ? EFI_OUT_OF_RESOURCES : EFI_DEVICE_ERROR); + serialize_result(&comm_buf, + data_len > data_limit(version) + ? EFI_OUT_OF_RESOURCES + : EFI_DEVICE_ERROR); free(name); return; } @@ -1757,7 +1814,7 @@ do_set_variable(uint8_t *comm_buf) } } - if (l->data_len + data_len > DATA_LIMIT || + if (l->data_len + data_len > data_limit(version) || get_space_usage() + data_len > TOTAL_LIMIT) { serialize_result(&ptr, EFI_OUT_OF_RESOURCES); goto err; @@ -1914,7 +1971,8 @@ do_set_variable(uint8_t *comm_buf) } static void -do_get_next_variable(uint8_t *comm_buf) +do_get_next_variable(uint8_t *comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command) { UINTN name_len, avail_len; uint8_t *ptr, *name; @@ -1923,10 +1981,10 @@ do_get_next_variable(uint8_t *comm_buf) BOOLEAN at_runtime; ptr = comm_buf; - unserialize_uint32(&ptr); /* version */ - unserialize_command(&ptr); + skip_command(&ptr, version, nr_pages, command); avail_len = unserialize_uintn(&ptr); - name = unserialize_data(&ptr, &name_len, NAME_LIMIT); + name = unserialize_data_checked(nr_pages, comm_buf, + &ptr, &name_len, NAME_LIMIT); if (!name && name_len) { serialize_result(&comm_buf, EFI_DEVICE_ERROR); return; @@ -1976,14 +2034,14 @@ do_get_next_variable(uint8_t *comm_buf) } static void -do_query_variable_info(uint8_t *comm_buf) +do_query_variable_info(uint8_t *comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command) { uint8_t *ptr; UINT32 attr; ptr = comm_buf; - unserialize_uint32(&ptr); /* version */ - unserialize_command(&ptr); + skip_command(&ptr, version, nr_pages, command); attr = unserialize_uint32(&ptr); ptr = comm_buf; @@ -2000,11 +2058,12 @@ do_query_variable_info(uint8_t *comm_buf) serialize_result(&ptr, EFI_SUCCESS); serialize_uint64(&ptr, TOTAL_LIMIT); serialize_uint64(&ptr, TOTAL_LIMIT - get_space_usage()); - serialize_uint64(&ptr, DATA_LIMIT); + serialize_uint64(&ptr, data_limit(version)); } static void -do_notify_sb_failure(uint8_t *comm_buf) +do_notify_sb_failure(uint8_t *comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command) { uint8_t *ptr; bool ret; @@ -2023,8 +2082,7 @@ do_notify_sb_failure(uint8_t *comm_buf) called = true; ptr = comm_buf; - unserialize_uint32(&ptr); /* version */ - unserialize_command(&ptr); + skip_command(&ptr, version, nr_pages, command); ret = db->sb_notify(); @@ -2032,39 +2090,94 @@ do_notify_sb_failure(uint8_t *comm_buf) serialize_result(&ptr, ret ? EFI_SUCCESS : EFI_DEVICE_ERROR); } -void dispatch_command(uint8_t *comm_buf) +UINTN data_limit(UINT32 version) { + switch (version) { + case 1: + return DATA_LIMIT_V1; + case 2: + return DATA_LIMIT_V2; + default: + assert(0); + return 0; + } +} + +EFI_STATUS snoop_command(uint8_t **comm_buf, UINT32 *out_version, + UINT32 *out_nr_pages, enum command_t *out_command) { - enum command_t command; + uint8_t *ptr = *comm_buf; UINT32 version; - uint8_t *ptr = comm_buf; + UINT32 nr_pages; + enum command_t command; version = unserialize_uint32(&ptr); - if (version != 1) { + switch (version) { + case 1: + nr_pages = SHMEM_PAGES_V1; + break; + case 2: + nr_pages = unserialize_uint32(&ptr); + if (nr_pages < SHMEM_PAGES_V2_MIN || nr_pages > SHMEM_PAGES_V2_MAX) { + DBG("Bad shmem page count: %u\n", nr_pages); + return EFI_INVALID_PARAMETER; + } + break; + default: DBG("Unknown version: %u\n", version); - return; + return EFI_INVALID_PARAMETER; } command = unserialize_command(&ptr); + + if (out_version) + *out_version = version; + if (out_nr_pages) + *out_nr_pages = nr_pages; + if (out_command) + *out_command = command; + *comm_buf = ptr; + return EFI_SUCCESS; +} + +void skip_command(uint8_t **ptr, UINT32 version, UINT32 nr_pages, + enum command_t command) +{ + (void) nr_pages; + (void) command; + + unserialize_uint32(ptr); + if (version == 2) + unserialize_uint32(ptr); + unserialize_command(ptr); +} + +void dispatch_snooped_command(uint8_t *comm_buf, UINT32 version, + UINT32 nr_pages, enum command_t command) +{ + uint8_t *ptr = comm_buf; + + skip_command(&ptr, version, nr_pages, command); + switch (command) { case COMMAND_GET_VARIABLE: DBG("COMMAND_GET_VARIABLE\n"); - do_get_variable(comm_buf); + do_get_variable(comm_buf, version, nr_pages, command); break; case COMMAND_SET_VARIABLE: DBG("COMMAND_SET_VARIABLE\n"); - do_set_variable(comm_buf); + do_set_variable(comm_buf, version, nr_pages, command); break; case COMMAND_GET_NEXT_VARIABLE: DBG("COMMAND_GET_NEXT_VARIABLE\n"); - do_get_next_variable(comm_buf); + do_get_next_variable(comm_buf, version, nr_pages, command); break; case COMMAND_QUERY_VARIABLE_INFO: DBG("COMMAND_QUERY_VARIABLE_INFO\n"); - do_query_variable_info(comm_buf); + do_query_variable_info(comm_buf, version, nr_pages, command); break; case COMMAND_NOTIFY_SB_FAILURE: DBG("COMMAND_NOTIFY_SB_FAILURE\n"); - do_notify_sb_failure(comm_buf); + do_notify_sb_failure(comm_buf, version, nr_pages, command); break; default: DBG("Unknown command\n"); @@ -2072,6 +2185,23 @@ void dispatch_command(uint8_t *comm_buf) }; } +void dispatch_command(uint8_t *comm_buf) +{ + UINT32 version, nr_pages; + enum command_t command; + uint8_t *ptr = comm_buf; + EFI_STATUS status; + + status = snoop_command(&ptr, &version, &nr_pages, &command); + if (status != EFI_SUCCESS) { + ptr = comm_buf; + serialize_result(&ptr, status); + return; + } + + dispatch_snooped_command(comm_buf, version, nr_pages, command); +} + bool setup_crypto(void) { @@ -2152,7 +2282,8 @@ static bool set_variable_from_auth(const uint8_t *name, UINTN name_len, const EFI_GUID *guid, const uint8_t *data, off_t data_len, bool append) { - uint8_t buf[SHMEM_SIZE]; + bool ret = false; + uint8_t *cmd_buf = NULL; uint8_t *ptr; EFI_STATUS status; UINT32 attr = ATTR_BRNV_TIME; @@ -2160,24 +2291,35 @@ set_variable_from_auth(const uint8_t *name, UINTN name_len, const EFI_GUID *guid if (append) attr |= EFI_VARIABLE_APPEND_WRITE; - ptr = buf; - serialize_uint32(&ptr, 1); /* version */ + cmd_buf = calloc(SHMEM_PAGES_V2_MAX, PAGE_SIZE); + if (!cmd_buf) { + ERR("Failed to allocate command buffer\n"); + goto out; + } + + ptr = cmd_buf; + serialize_uint32(&ptr, 2); /* version */ + serialize_uint32(&ptr, SHMEM_PAGES_V2_MAX); /* nr_pages */ serialize_uint32(&ptr, COMMAND_SET_VARIABLE); serialize_data(&ptr, name, name_len); serialize_guid(&ptr, guid); serialize_data(&ptr, data, data_len); serialize_uint32(&ptr, attr); *ptr = 0; /* at_runtime */ - dispatch_command(buf); + dispatch_command(cmd_buf); - ptr = buf; + ptr = cmd_buf; status = unserialize_uintn(&ptr); if (status != EFI_SUCCESS) { ERR("Failed to execute auth data: 0x%lx\n", status); - return false; + goto out; } - return true; + ret = true; + +out: + free(cmd_buf); + return ret; } bool @@ -2246,7 +2388,7 @@ load_one_auth_data(const char *path, uint8_t **data_out, off_t *len) * This will be checked later during SetVariable but check it now to avoid * reading a malicously large file into memory. */ - if (st.st_size > DATA_LIMIT) { + if (st.st_size > DATA_LIMIT_MAX) { ERR("Auth file '%s' is too large: %ld\n", path, st.st_size); fclose(f); return false; diff --git a/handler_port.c b/handler_port.c index 4ddbad0..f859510 100644 --- a/handler_port.c +++ b/handler_port.c @@ -49,31 +49,56 @@ static struct { static void io_port_writel(uint64_t offset, uint64_t size, uint32_t val) { - xen_pfn_t pfns[SHMEM_PAGES]; + xen_pfn_t pfns[SHMEM_PAGES_V2_MAX]; void *shmem; + UINT32 version, nr_pages; + enum command_t command; int i; + uint8_t *ptr; + EFI_STATUS status; if (offset != 0 || size != sizeof(uint32_t)) { DBG("Expected size 4, offset 0. Got %" PRIu64 ", %" PRIu64 ".\n", size, offset); return; } - for (i = 0; i < SHMEM_PAGES; i++) + for (i = 0; i < SHMEM_PAGES_V2_MAX; i++) pfns[i] = val + i; DBG("io_port write\n"); + /* Only the first page is wanted for nr_pages detection */ shmem = xenforeignmemory_map(io_info.fmem, io_info.domid, PROT_READ | PROT_WRITE, - SHMEM_PAGES, pfns, NULL); + 1, pfns, NULL); + if (!shmem) { + DBG("map foreign range failed (snoop): %d\n", errno); + return; + } + + ptr = shmem; + /* nr_pages is the only thing we're interested in here */ + status = snoop_command(&ptr, &version, &nr_pages, &command); + + xenforeignmemory_unmap(io_info.fmem, shmem, 1); + + if (status != EFI_SUCCESS) { + DBG("snoop_command refused version data\n"); + return; + } + + shmem = xenforeignmemory_map(io_info.fmem, + io_info.domid, + PROT_READ | PROT_WRITE, + nr_pages, pfns, NULL); if (!shmem) { DBG("map foreign range failed: %d\n", errno); return; } - dispatch_command(shmem); + dispatch_snooped_command(shmem, version, nr_pages, command); - xenforeignmemory_unmap(io_info.fmem, shmem, SHMEM_PAGES); + xenforeignmemory_unmap(io_info.fmem, shmem, nr_pages); } @@ -85,4 +110,3 @@ setup_handler_io_port(domid_t domid, xenforeignmemory_handle *fmem) { return register_io_port_writel_handler(HANDLER_PORT_ADDRESS, io_port_writel); } - diff --git a/include/handler.h b/include/handler.h index 0851836..0f0105c 100644 --- a/include/handler.h +++ b/include/handler.h @@ -34,9 +34,41 @@ #include "efi.h" +#define PAGE_SIZE 4096 +#define SHMEM_PAGES_V1 16 +/* Consumers shouldn't use this value, but should stick to SHMEM_PAGES_V2_MAX */ +#define SHMEM_PAGES_V2_MIN 18 +#define SHMEM_PAGES_V2_MAX 32 + #define NAME_LIMIT 4096 /* Maximum length of name */ -#define DATA_LIMIT 57344 /* Maximum length of a single variable */ -#define TOTAL_LIMIT 131072 /* Maximum total storage */ + +/* + * Maximum length of a single variable. To ensure that there's sufficient room + * for variables in the communication buffer, SHMEM_PAGES must be high enough to + * cover the data limit + 1 page (4096 bytes) for the variable name + 1 page for + * protocol overhead. + */ +#define DATA_LIMIT(shmem_pages) (((shmem_pages) - 2) * PAGE_SIZE) + +/* The following limits must respect the minimum prescribed by WHCP. */ + +#define DATA_LIMIT_V1 DATA_LIMIT(SHMEM_PAGES_V1) +/* + * For now, DATA_LIMIT_V2 and SHMEM_PAGES_V2_MIN are coupled: DATA_LIMIT_V2 is + * calculated from SHMEM_PAGES_V2_MIN, and one can't be increased without + * increasing the other. + * + * However, there's reserved headroom in SHMEM_PAGES_V2_MAX for later silently + * increasing DATA_LIMIT_V2; consumers should stick to SHMEM_PAGES_V2_MAX and + * not worry about this. + */ +#define DATA_LIMIT_V2 DATA_LIMIT(SHMEM_PAGES_V2_MIN) + +/* For non-protocol uses */ +#define DATA_LIMIT_MAX DATA_LIMIT_V2 + +/* Maximum total storage */ +#define TOTAL_LIMIT 131072 /* * A single variable takes up a minimum number of bytes. @@ -46,10 +78,6 @@ #define VARIABLE_SIZE_OVERHEAD 128 #define MAX_VARIABLE_COUNT (TOTAL_LIMIT / VARIABLE_SIZE_OVERHEAD) -#define PAGE_SIZE 4096 -#define SHMEM_PAGES 16 -#define SHMEM_SIZE (SHMEM_PAGES * PAGE_SIZE) - #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) enum command_t { @@ -74,6 +102,13 @@ struct efi_variable { extern struct efi_variable *var_list; +UINTN data_limit(UINT32 version); +EFI_STATUS snoop_command(uint8_t **comm_buf, UINT32 *out_version, + UINT32 *out_nr_pages, enum command_t *out_command); +void skip_command(uint8_t **comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command); +void dispatch_snooped_command(uint8_t *comm_buf, UINT32 version, UINT32 nr_pages, + enum command_t command); void dispatch_command(uint8_t *comm_buf); bool setup_crypto(void); bool setup_variables(void); diff --git a/test.c b/test.c index 4de7e30..ec70a06 100644 --- a/test.c +++ b/test.c @@ -38,8 +38,20 @@ static char *save_name = "test.dat"; const enum log_level log_level = LOG_LVL_ERROR; +/* Multi-version */ +#define MULTI_TEST(test_name) \ + static void test_name(UINT32 version); \ + static void test_name ## _v1(void) { \ + test_name(1); \ + } \ + static void test_name ## _v2(void) { \ + test_name(2); \ + } \ + static void test_name(UINT32 version) + /* The communication buffer. */ -static uint8_t buf[16 * 4096]; +static uint8_t *buf = NULL; +static UINT32 buf_pages = 0; /* Wide char support */ @@ -333,6 +345,14 @@ static void free_globals(void) free(certPK); } +static void reset_buf(size_t nr_pages) +{ + free(buf); + buf = calloc(nr_pages, PAGE_SIZE); + assert(buf); + buf_pages = nr_pages; +} + static void reset_vars(void) { struct efi_variable *l, *tmp; @@ -348,11 +368,43 @@ static void reset_vars(void) var_list = NULL; } -static void call_get_variable(const dstring *name, const EFI_GUID *guid, - UINTN avail, BOOLEAN at_runtime) +static inline void reset_test(UINT32 version) { + switch (version) { + case 1: + reset_buf(SHMEM_PAGES_V1); + break; + case 2: + reset_buf(SHMEM_PAGES_V2_MAX); + break; + default: + assert(0); + } + + reset_vars(); +} + +static void serialize_buf_version(uint8_t **ptr, UINT32 version) +{ + switch (version) + { + case 1: + serialize_uint32(ptr, 1); + break; + case 2: + serialize_uint32(ptr, 2); + serialize_uint32(ptr, buf_pages); + break; + default: + assert(0); + } +} + +static void call_get_variable(UINT32 version, const dstring *name, + const EFI_GUID *guid, UINTN avail, + BOOLEAN at_runtime) { uint8_t *ptr = buf; - serialize_uint32(&ptr, 1); + serialize_buf_version(&ptr, version); serialize_uint32(&ptr, (UINT32)COMMAND_GET_VARIABLE); serialize_data(&ptr, (uint8_t *)name->data, dstring_data_size(name)); serialize_guid(&ptr, guid); @@ -362,7 +414,7 @@ static void call_get_variable(const dstring *name, const EFI_GUID *guid, dispatch_command(buf); } -static EFI_STATUS call_get_variable_data(const dstring *name, +static EFI_STATUS call_get_variable_data(UINT32 version, const dstring *name, const EFI_GUID *guid, UINTN avail, BOOLEAN at_runtime, uint8_t **data, UINTN *len) @@ -370,32 +422,45 @@ static EFI_STATUS call_get_variable_data(const dstring *name, uint8_t *ptr = buf; EFI_STATUS status; - call_get_variable(name, guid, avail, at_runtime); - - status = unserialize_uintn(&ptr); - unserialize_uint32(&ptr); /* attr */ - *data = unserialize_data(&ptr, len, BSIZ); + call_get_variable(version, name, guid, avail, at_runtime); + + status = unserialize_uintn(&ptr); + switch (status) { + case EFI_SUCCESS: + unserialize_uint32(&ptr); /* attr */ + *data = unserialize_data(&ptr, len, BSIZ); + break; + case EFI_BUFFER_TOO_SMALL: + *data = NULL; + *len = unserialize_uintn(&ptr); + break; + default: + *data = NULL; + *len = 0; + break; + } return status; } -static void call_query_variable_info(void) +static void call_query_variable_info(UINT32 version) { uint8_t *ptr = buf; - serialize_uint32(&ptr, 1); + serialize_buf_version(&ptr, version); serialize_uint32(&ptr, (UINT32)COMMAND_QUERY_VARIABLE_INFO); serialize_uint32(&ptr, 0); dispatch_command(buf); } -static void call_get_next_variable(UINTN avail, const dstring *name, - const EFI_GUID *guid, BOOLEAN at_runtime) +static void call_get_next_variable(UINT32 version, UINTN avail, + const dstring *name, const EFI_GUID *guid, + BOOLEAN at_runtime) { uint8_t *ptr = buf; size_t len = name ? dstring_data_size(name) : 0; const uint8_t *data = (uint8_t *)(name ? name->data : NULL); - serialize_uint32(&ptr, 1); + serialize_buf_version(&ptr, version); serialize_uint32(&ptr, (UINT32)COMMAND_GET_NEXT_VARIABLE); serialize_uintn(&ptr, avail); serialize_data(&ptr, data, len); @@ -405,14 +470,14 @@ static void call_get_next_variable(UINTN avail, const dstring *name, dispatch_command(buf); } -static void call_set_variable(const dstring *name, const EFI_GUID *guid, - const uint8_t *data, UINTN data_len, - UINT32 attr, BOOLEAN at_runtime) +static void call_set_variable(UINT32 version, const dstring *name, + const EFI_GUID *guid, const uint8_t *data, + UINTN data_len, UINT32 attr, BOOLEAN at_runtime) { uint8_t *ptr = buf; size_t name_size = dstring_data_size(name); - serialize_uint32(&ptr, 1); + serialize_buf_version(&ptr, version); serialize_uint32(&ptr, (UINT32)COMMAND_SET_VARIABLE); serialize_data(&ptr, (uint8_t *)name->data, name_size); serialize_guid(&ptr, guid); @@ -427,7 +492,7 @@ static void call_set_variable(const dstring *name, const EFI_GUID *guid, * This calls SetVariable and checks the result against expected. In the * failing case, the line number provided reported. */ -static EFI_STATUS setVariable_check_line(const dstring *name, +static EFI_STATUS setVariable_check_line(UINT32 version, const dstring *name, const EFI_GUID *guid, const uint8_t *data, UINTN len, UINT32 attr, EFI_STATUS expected, @@ -437,7 +502,7 @@ static EFI_STATUS setVariable_check_line(const dstring *name, EFI_STATUS status; char *nice_name; - call_set_variable(name, guid, data, len, attr, 0); + call_set_variable(version, name, guid, data, len, attr, 0); ptr = buf; status = unserialize_uintn(&ptr); @@ -449,12 +514,12 @@ static EFI_STATUS setVariable_check_line(const dstring *name, return status; } -#define sv_check(_name, _guid, _data, _len, _attr, _expected) \ - setVariable_check_line(_name, _guid, _data, _len, _attr, \ +#define sv_check(_version, _name, _guid, _data, _len, _attr, _expected) \ + setVariable_check_line(_version, _name, _guid, _data, _len, _attr, \ _expected, __LINE__); -#define sv_ok(_name, _guid, _data, _len, _attr) \ - setVariable_check_line(_name, _guid, _data, _len, _attr, \ +#define sv_ok(_version, _name, _guid, _data, _len, _attr) \ + setVariable_check_line(_version, _name, _guid, _data, _len, _attr, \ EFI_SUCCESS, __LINE__); /* @@ -679,7 +744,7 @@ static size_t sign(uint8_t **signed_buf, const dstring *varname, return auth_size + data_size; } -static void sign_and_check_(const dstring *varname, const EFI_GUID *vendor_guid, +static void sign_and_check_(UINT32 version, const dstring *varname, const EFI_GUID *vendor_guid, UINT32 attributes, const EFI_TIME *timestamp, const uint8_t *data, size_t data_size, const struct sign_details *sd, EFI_STATUS expected, @@ -690,23 +755,24 @@ static void sign_and_check_(const dstring *varname, const EFI_GUID *vendor_guid, len = sign(&sign_buffer, varname, vendor_guid, attributes, timestamp, data, data_size, sd); - setVariable_check_line(varname, vendor_guid, sign_buffer, len, + setVariable_check_line(version, varname, vendor_guid, sign_buffer, len, attributes, expected, line); free(sign_buffer); } -#define sign_and_check(_name, _vend, _attr, _time, _data, _size, _sig, _e_d) \ - sign_and_check_(_name, _vend, _attr, _time, _data, _size, _sig, _e_d, __LINE__) +#define sign_and_check(_version, _name, _vend, _attr, _time, _data, _size, _sig, _e_d) \ + sign_and_check_(_version, _name, _vend, _attr, _time, _data, _size, _sig, _e_d, __LINE__) /* * This function checks the variable's data is as expected. * The expected data is provided, such that it can be compared */ -#define check_variable_data(_name, _guid, _avai, _runtime, _expected, _len) \ - check_variable_data_(_name, _guid, _avai, _runtime, _expected, _len, __LINE__) +#define check_variable_data(_version, _name, _guid, _avai, _runtime, _expected, _len) \ + check_variable_data_(_version, _name, _guid, _avai, _runtime, _expected, _len, __LINE__) -static void check_variable_data_(const dstring *name, const EFI_GUID *guid, +static void check_variable_data_(UINT32 version, const dstring *name, + const EFI_GUID *guid, UINTN avail, BOOLEAN at_runtime, const uint8_t *expected_data, UINTN expected_len, int line) @@ -717,7 +783,8 @@ static void check_variable_data_(const dstring *name, const EFI_GUID *guid, UINTN len; char *nice_name = get_dstring_pretty(name); - status = call_get_variable_data(name, guid, avail, at_runtime, &ret_data, &len); + status = call_get_variable_data(version, name, guid, avail, at_runtime, + &ret_data, &len); vsd_assert_status("get_variable(\"%s\") at %d", status, ==, 0, nice_name, line); vsd_assert_cmpuint("data length for \"%s\" at %d", expected_len, ==, len, @@ -730,16 +797,16 @@ static void check_variable_data_(const dstring *name, const EFI_GUID *guid, free(nice_name); } -static void test_get_variable_no_name(void) +MULTI_TEST(test_get_variable_no_name) { uint8_t *ptr; EFI_STATUS status; dstring *empty = alloc_dstring(""); - reset_vars(); + reset_test(version); /* An empty name should not be found. */ - call_get_variable(empty, &nullguid, BSIZ, 0); + call_get_variable(version, empty, &nullguid, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); @@ -747,54 +814,54 @@ static void test_get_variable_no_name(void) free_dstring(empty); } -static void test_get_variable_long_name(void) +MULTI_TEST(test_get_variable_long_name) { uint8_t *ptr; EFI_STATUS status; dstring *bigname; - reset_vars(); + reset_test(version); bigname = alloc_dstring_unset(NAME_LIMIT / sizeof(uint16_t) + 1); memset(bigname->data, 42, dstring_data_size(bigname)); /* Test the maximum variable name length. */ - call_get_variable(bigname, &nullguid, BSIZ, 0); + call_get_variable(version, bigname, &nullguid, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_DEVICE_ERROR); free_dstring(bigname); } -static void test_get_variable_not_found(void) +MULTI_TEST(test_get_variable_not_found) { uint8_t *ptr; EFI_STATUS status; - reset_vars(); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); + reset_test(version); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); /* Name is correct, guid is wrong */ - call_get_variable(tname2, &tguid4, BSIZ, 0); + call_get_variable(version, tname2, &tguid4, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Name is wrong, guid is correct */ - call_get_variable(tname4, &tguid2, BSIZ, 0); + call_get_variable(version, tname4, &tguid2, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Boot service only variable cannot be found at runtime */ - call_get_variable(tname2, &tguid2, BSIZ, 1); + call_get_variable(version, tname2, &tguid2, BSIZ, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); } -static void test_get_variable_found(void) +MULTI_TEST(test_get_variable_found) { uint8_t *ptr; uint8_t *data; @@ -802,13 +869,13 @@ static void test_get_variable_found(void) UINT32 attr; EFI_STATUS status; - reset_vars(); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); + reset_test(version); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); /* Variable is correctly retrieved. */ - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -820,7 +887,7 @@ static void test_get_variable_found(void) free(data); /* Runtime variable can be found at runtime */ - call_get_variable(tname2, &tguid2, BSIZ, 1); + call_get_variable(version, tname2, &tguid2, BSIZ, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -832,7 +899,7 @@ static void test_get_variable_found(void) free(data); /* Variable is correctly retrieved. */ - call_get_variable(tname3, &tguid3, BSIZ, 0); + call_get_variable(version, tname3, &tguid3, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -844,34 +911,40 @@ static void test_get_variable_found(void) free(data); } -static void test_get_variable_too_small(void) +MULTI_TEST(test_get_variable_too_small) { uint8_t *ptr; UINTN data_len; + UINT32 attr; EFI_STATUS status; - reset_vars(); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + reset_test(version); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); /* * If the output buffer is too small, check that the correct size is * returned. */ - call_get_variable(tname1, &tguid1, sizeof(tdata1) - 1, 0); + call_get_variable(version, tname1, &tguid1, sizeof(tdata1) - 1, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_BUFFER_TOO_SMALL); data_len = unserialize_uintn(&ptr); g_assert_cmpuint(data_len, ==, sizeof(tdata1)); + + if (version >= 2) { + attr = unserialize_uint32(&ptr); + g_assert_cmpuint(attr, ==, ATTR_B); + } } -static void test_query_variable_info(void) +MULTI_TEST(test_query_variable_info) { uint8_t *ptr; EFI_STATUS status; dstring *longname; - reset_vars(); + reset_test(version); /* * Use a long variable name to ensure the variable is larger than the @@ -882,18 +955,18 @@ static void test_query_variable_info(void) memset(longname->data, 'a', dstring_data_size(longname)); /* Check the defined limits with no variables. */ - call_query_variable_info(); + call_query_variable_info(version); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); g_assert_cmpuint(TOTAL_LIMIT, ==, unserialize_uintn(&ptr)); g_assert_cmpuint(TOTAL_LIMIT, ==, unserialize_uintn(&ptr)); - g_assert_cmpuint(DATA_LIMIT, ==, unserialize_uintn(&ptr)); + g_assert_cmpuint(data_limit(version), ==, unserialize_uintn(&ptr)); - sv_ok(longname, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, longname, &tguid1, tdata1, sizeof(tdata1), ATTR_B); /* Inserting a variable updates the limits correctly. */ - call_query_variable_info(); + call_query_variable_info(version); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -901,11 +974,11 @@ static void test_query_variable_info(void) g_assert_cmpuint(TOTAL_LIMIT - dstring_data_size(longname) - sizeof(tdata1) - VARIABLE_SIZE_OVERHEAD, ==, unserialize_uintn(&ptr)); - g_assert_cmpuint(DATA_LIMIT, ==, unserialize_uintn(&ptr)); + g_assert_cmpuint(data_limit(version), ==, unserialize_uintn(&ptr)); /* Updating a variable updates the limits correctly. */ - sv_ok(longname, &tguid1, tdata2, sizeof(tdata2), ATTR_B); - call_query_variable_info(); + sv_ok(version, longname, &tguid1, tdata2, sizeof(tdata2), ATTR_B); + call_query_variable_info(version); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -913,12 +986,12 @@ static void test_query_variable_info(void) g_assert_cmpuint(TOTAL_LIMIT - dstring_data_size(longname) - sizeof(tdata2) - VARIABLE_SIZE_OVERHEAD, ==, unserialize_uintn(&ptr)); - g_assert_cmpuint(DATA_LIMIT, ==, unserialize_uintn(&ptr)); + g_assert_cmpuint(data_limit(version), ==, unserialize_uintn(&ptr)); /* Appending to a variable updates the limits correctly. */ - sv_ok(longname, &tguid1, tdata1, sizeof(tdata1), + sv_ok(version, longname, &tguid1, tdata1, sizeof(tdata1), ATTR_B | EFI_VARIABLE_APPEND_WRITE); - call_query_variable_info(); + call_query_variable_info(version); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -926,53 +999,53 @@ static void test_query_variable_info(void) g_assert_cmpuint(TOTAL_LIMIT - dstring_data_size(longname) - sizeof(tdata2) - sizeof(tdata1) - VARIABLE_SIZE_OVERHEAD, ==, unserialize_uintn(&ptr)); - g_assert_cmpuint(DATA_LIMIT, ==, unserialize_uintn(&ptr)); + g_assert_cmpuint(data_limit(version), ==, unserialize_uintn(&ptr)); /* Deleting a variable updates the limits correctly. */ - sv_ok(longname, &tguid1, NULL, 0, ATTR_B); - call_query_variable_info(); + sv_ok(version, longname, &tguid1, NULL, 0, ATTR_B); + call_query_variable_info(version); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); g_assert_cmpuint(TOTAL_LIMIT, ==, unserialize_uintn(&ptr)); g_assert_cmpuint(TOTAL_LIMIT, ==, unserialize_uintn(&ptr)); - g_assert_cmpuint(DATA_LIMIT, ==, unserialize_uintn(&ptr)); + g_assert_cmpuint(data_limit(version), ==, unserialize_uintn(&ptr)); free_dstring(longname); } -static void test_get_next_variable_empty(void) +MULTI_TEST(test_get_next_variable_empty) { uint8_t *ptr; EFI_STATUS status; - reset_vars(); + reset_test(version); /* No variables */ - call_get_next_variable(BSIZ, NULL, &nullguid, 0); + call_get_next_variable(version, BSIZ, NULL, &nullguid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); } -static void test_get_next_variable_long_name(void) +MULTI_TEST(test_get_next_variable_long_name) { uint8_t *ptr; EFI_STATUS status; dstring *tmp_name; - reset_vars(); + reset_test(version); tmp_name = alloc_dstring_unset(NAME_LIMIT / sizeof(uint16_t) + 1); memset(tmp_name->data, 42, dstring_data_size(tmp_name)); /* Input name exceeds the limit */ - call_get_next_variable(BSIZ, tmp_name, &nullguid, 0); + call_get_next_variable(version, BSIZ, tmp_name, &nullguid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_DEVICE_ERROR); free_dstring(tmp_name); } -static void test_get_next_variable_only_runtime(void) +MULTI_TEST(test_get_next_variable_only_runtime) { uint8_t *ptr, *data; UINTN data_len; @@ -984,14 +1057,14 @@ static void test_get_next_variable_only_runtime(void) * Only runtime variables should be returned at runtime. */ - reset_vars(); - sv_ok(tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BR); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); + reset_test(version); + sv_ok(version, tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BR); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); - call_get_next_variable(BSIZ, NULL, &nullguid, 1); + call_get_next_variable(version, BSIZ, NULL, &nullguid, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1003,7 +1076,7 @@ static void test_get_next_variable_only_runtime(void) g_assert(!memcmp(&guid, &tguid4, GUID_LEN)); free(data); - call_get_next_variable(BSIZ, tname4, &guid, 1); + call_get_next_variable(version, BSIZ, tname4, &guid, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1014,26 +1087,26 @@ static void test_get_next_variable_only_runtime(void) g_assert(!memcmp(&guid, &tguid2, GUID_LEN)); free(data); - call_get_next_variable(BSIZ, tname2, &guid, 1); + call_get_next_variable(version, BSIZ, tname2, &guid, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); } -static void test_get_next_variable_too_small(void) +MULTI_TEST(test_get_next_variable_too_small) { uint8_t *ptr; UINTN data_len; EFI_STATUS status; - reset_vars(); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + reset_test(version); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); /* * If the output buffer is too small, check that the correct size is * returned. */ - call_get_next_variable(0, NULL, &nullguid, 0); + call_get_next_variable(version, 0, NULL, &nullguid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_BUFFER_TOO_SMALL); @@ -1041,19 +1114,19 @@ static void test_get_next_variable_too_small(void) g_assert_cmpuint(data_len, ==, dstring_data_size(tname1) + sizeof(CHAR16)); } -static void test_get_next_variable_no_match(void) +MULTI_TEST(test_get_next_variable_no_match) { uint8_t *ptr, *data; UINTN data_len; EFI_STATUS status; EFI_GUID guid; - reset_vars(); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); + reset_test(version); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); /* First variable is retrieved successfully. */ - call_get_next_variable(BSIZ, NULL, &nullguid, 0); + call_get_next_variable(version, BSIZ, NULL, &nullguid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1064,13 +1137,13 @@ static void test_get_next_variable_no_match(void) g_assert(!memcmp(&guid, &tguid2, GUID_LEN)); /* Check when an incorrect name is passed in. */ - call_get_next_variable(BSIZ, tname4, &guid, 0); + call_get_next_variable(version, BSIZ, tname4, &guid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* Check when an incorrect guid is passed in. */ - call_get_next_variable(BSIZ, tname2, &tguid4, 0); + call_get_next_variable(version, BSIZ, tname2, &tguid4, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); @@ -1078,7 +1151,7 @@ static void test_get_next_variable_no_match(void) free(data); } -static void test_get_next_variable_all(void) +MULTI_TEST(test_get_next_variable_all) { uint8_t *ptr, *data; UINTN data_len; @@ -1090,14 +1163,14 @@ static void test_get_next_variable_all(void) * At boot time, all variables should be retrieved. */ - reset_vars(); - sv_ok(tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BR); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); + reset_test(version); + sv_ok(version, tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BR); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_B); - call_get_next_variable(BSIZ, NULL, &nullguid, 0); + call_get_next_variable(version, BSIZ, NULL, &nullguid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1107,7 +1180,7 @@ static void test_get_next_variable_all(void) unserialize_guid(&ptr, &guid); g_assert(!memcmp(&guid, &tguid3, GUID_LEN)); - call_get_next_variable(BSIZ, tname3, &guid, 0); + call_get_next_variable(version, BSIZ, tname3, &guid, 0); free(data); ptr = buf; status = unserialize_uintn(&ptr); @@ -1119,7 +1192,7 @@ static void test_get_next_variable_all(void) g_assert(!memcmp(&guid, &tguid4, GUID_LEN)); free(data); - call_get_next_variable(BSIZ, tname4, &guid, 0); + call_get_next_variable(version, BSIZ, tname4, &guid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1129,7 +1202,7 @@ static void test_get_next_variable_all(void) unserialize_guid(&ptr, &guid); g_assert(!memcmp(&guid, &tguid1, GUID_LEN)); - call_get_next_variable(BSIZ, tname1, &guid, 0); + call_get_next_variable(version, BSIZ, tname1, &guid, 0); free(data); ptr = buf; @@ -1142,7 +1215,7 @@ static void test_get_next_variable_all(void) g_assert(!memcmp(&guid, &tguid2, GUID_LEN)); free(data); - call_get_next_variable(BSIZ, tname2, &guid, 0); + call_get_next_variable(version, BSIZ, tname2, &guid, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1152,55 +1225,55 @@ static void test_get_next_variable_all(void) unserialize_guid(&ptr, &guid); g_assert(!memcmp(&guid, &tguid5, GUID_LEN)); - call_get_next_variable(BSIZ, tname5, &guid, 0); + call_get_next_variable(version, BSIZ, tname5, &guid, 0); free(data); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); } -static void test_set_variable_attr(void) +MULTI_TEST(test_set_variable_attr) { uint8_t *ptr; EFI_STATUS status; - reset_vars(); + reset_test(version); setup_variables(); /* hardware error record is not supported */ - call_set_variable(tname1, &tguid1, tdata1, sizeof(tdata1), + call_set_variable(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B | EFI_VARIABLE_HARDWARE_ERROR_RECORD, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* authenticated write access is not supported */ - call_set_variable(tname1, &tguid1, tdata1, sizeof(tdata1), + call_set_variable(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_UNSUPPORTED); /* runtime without boottime access is invalid */ - call_set_variable(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_R, 0); + call_set_variable(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_R, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* Setting boottime variables at runtime is not supported */ - call_set_variable(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B, 1); + call_set_variable(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* Set a volatile variable at runtime fails */ - call_set_variable(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_BR, 1); + call_set_variable(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_BR, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* Set a variable at runtime without runtime access fails */ - call_set_variable(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B, 1); + call_set_variable(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); @@ -1210,36 +1283,36 @@ static void test_set_variable_attr(void) * EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS attribute are set in a * SetVariable() call, then the firmware must return EFI_INVALID_PARAMETER. */ - sign_and_check(tname2, &tguid1, + sign_and_check(version, tname2, &tguid1, ATTR_B_TIME | EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS, &test_timea, tdata1, sizeof(tdata1), &sign_testPK, EFI_INVALID_PARAMETER); } -static void test_set_variable_set(void) +MULTI_TEST(test_set_variable_set) { uint8_t *ptr, *data; UINTN data_len; EFI_STATUS status; UINT32 attr; - reset_vars(); + reset_test(version); /* Basic SetVariable usage. */ - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_BR); /* Set an NV variable at runtime */ - call_set_variable(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BRNV, 1); + call_set_variable(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BRNV, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); /* Set an NV variable at boottime */ - sv_ok(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV); + sv_ok(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV); /* Access boottime variable at boottime */ - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1251,7 +1324,7 @@ static void test_set_variable_set(void) free(data); /* Access BR variable at boottime */ - call_get_variable(tname2, &tguid2, BSIZ, 0); + call_get_variable(version, tname2, &tguid2, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1263,7 +1336,7 @@ static void test_set_variable_set(void) free(data); /* Access runtime variable at runtime */ - call_get_variable(tname2, &tguid2, BSIZ, 1); + call_get_variable(version, tname2, &tguid2, BSIZ, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1275,7 +1348,7 @@ static void test_set_variable_set(void) free(data); /* Access runtime variable at runtime */ - call_get_variable(tname3, &tguid3, BSIZ, 1); + call_get_variable(version, tname3, &tguid3, BSIZ, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1287,7 +1360,7 @@ static void test_set_variable_set(void) free(data); /* Access NV runtime variable at runtime */ - call_get_variable(tname3, &tguid3, BSIZ, 1); + call_get_variable(version, tname3, &tguid3, BSIZ, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1299,7 +1372,7 @@ static void test_set_variable_set(void) free(data); /* Access NV boottime variable at boottime */ - call_get_variable(tname4, &tguid4, BSIZ, 0); + call_get_variable(version, tname4, &tguid4, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1311,25 +1384,25 @@ static void test_set_variable_set(void) free(data); } -static void test_set_variable_update(void) +MULTI_TEST(test_set_variable_update) { uint8_t *ptr, *data; UINTN data_len; EFI_STATUS status; UINT32 attr; - reset_vars(); + reset_test(version); /* Insert a variable... */ - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); /* ... and check it can be updated */ - sv_ok(tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_B); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR); - sv_ok(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV); + sv_ok(version, tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_B); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR); + sv_ok(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV); /* Check the update worked. */ - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1341,47 +1414,47 @@ static void test_set_variable_update(void) free(data); /* Cannot change attributes */ - call_set_variable(tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_BR, 0); + call_set_variable(version, tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_BR, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* Updating a volatile variable at runtime fails */ - call_set_variable(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR, 1); + call_set_variable(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_WRITE_PROTECTED); /* Updating a variable at runtime without runtime access fails */ - call_set_variable(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV, 1); + call_set_variable(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); } -static void test_set_variable_append(void) +MULTI_TEST(test_set_variable_append) { uint8_t *ptr, *data; UINTN data_len; EFI_STATUS status; UINT32 attr; - reset_vars(); + reset_test(version); /* Insert some variables */ - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR); - sv_ok(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR); + sv_ok(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV); /* Append 0 bytes must not delete the variable */ - sv_ok(tname1, &tguid1, NULL, 0, ATTR_B | EFI_VARIABLE_APPEND_WRITE); + sv_ok(version, tname1, &tguid1, NULL, 0, ATTR_B | EFI_VARIABLE_APPEND_WRITE); /* Append data to the variable */ - sv_ok(tname1, &tguid1, tdata2, sizeof(tdata2), + sv_ok(version, tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_B | EFI_VARIABLE_APPEND_WRITE); /* Verify the contents are a concatenation */ - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1394,34 +1467,34 @@ static void test_set_variable_append(void) free(data); /* Appending to a volatile variable at runtime fails */ - call_set_variable(tname3, &tguid3, tdata3, sizeof(tdata3), + call_set_variable(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR | EFI_VARIABLE_APPEND_WRITE, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_WRITE_PROTECTED); /* Appending to a variable at runtime without runtime access fails */ - call_set_variable(tname4, &tguid4, tdata4, sizeof(tdata4), + call_set_variable(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BNV | EFI_VARIABLE_APPEND_WRITE, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); } -static void test_set_variable_delete(void) +MULTI_TEST(test_set_variable_delete) { uint8_t *ptr; EFI_STATUS status; - reset_vars(); + reset_test(version); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR); - sv_ok(tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_BNV); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_B); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BR); + sv_ok(version, tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_BNV); /* Deleting a non-existent variable at boottime fails (by setting no data) */ - call_set_variable(tname4, &tguid4, NULL, 0, ATTR_B, 0); + call_set_variable(version, tname4, &tguid4, NULL, 0, ATTR_B, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); @@ -1430,13 +1503,13 @@ static void test_set_variable_delete(void) * Deleting a non-existent variable at boottime fails (by setting no * access attributes) */ - call_set_variable(tname4, &tguid4, tdata4, sizeof(tdata4), 0, 0); + call_set_variable(version, tname4, &tguid4, tdata4, sizeof(tdata4), 0, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Deleting a non-existent variable at runtime fails (by setting no data) */ - call_set_variable(tname4, &tguid4, NULL, 0, ATTR_BRNV, 0); + call_set_variable(version, tname4, &tguid4, NULL, 0, ATTR_BRNV, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); @@ -1445,106 +1518,108 @@ static void test_set_variable_delete(void) * Deleting a non-existent variable at runtime fails (by setting no access * attributes) */ - call_set_variable(tname4, &tguid4, tdata4, sizeof(tdata4), 0, 0); + call_set_variable(version, tname4, &tguid4, tdata4, sizeof(tdata4), 0, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Delete by setting no data */ - sv_ok(tname1, &tguid1, NULL, 0, ATTR_B); + sv_ok(version, tname1, &tguid1, NULL, 0, ATTR_B); /* Verify it is gone */ - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Delete by setting no access attributes */ - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), 0); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), 0); /* Verify it is gone */ - call_get_variable(tname2, &tguid2, BSIZ, 0); + call_get_variable(version, tname2, &tguid2, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Deleting a volatile variable at runtime fails */ - call_set_variable(tname3, &tguid3, NULL, 0, ATTR_BR, 1); + call_set_variable(version, tname3, &tguid3, NULL, 0, ATTR_BR, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_WRITE_PROTECTED); /* Deleting a variable at runtime without runtime access fails */ - call_set_variable(tname5, &tguid5, NULL, 0, ATTR_B, 1); + call_set_variable(version, tname5, &tguid5, NULL, 0, ATTR_B, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); /* Deleting a variable at runtime by setting attributes to 0 succeeds */ - sv_ok(tname5, &tguid5, NULL, 0, ATTR_BNV); /* Remove old variable */ + sv_ok(version, tname5, &tguid5, NULL, 0, ATTR_BNV); /* Remove old variable */ /* Insert it with different attr */ - sv_ok(tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_BRNV); + sv_ok(version, tname5, &tguid5, tdata5, sizeof(tdata5), ATTR_BRNV); /* Then delete it at runtime */ - call_set_variable(tname5, &tguid5, tdata5, sizeof(tdata5), 0, 1); + call_set_variable(version, tname5, &tguid5, tdata5, sizeof(tdata5), 0, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); } -static void test_set_variable_resource_limit(void) +MULTI_TEST(test_set_variable_resource_limit) { uint8_t *ptr; EFI_STATUS status; - UINTN remaining; + UINTN remaining = TOTAL_LIMIT; uint8_t tmp[TOTAL_LIMIT] = {0}; - reset_vars(); + reset_test(version); /* Check per-variable limit */ - call_set_variable(tname1, &tguid1, tmp, DATA_LIMIT + 1, ATTR_B, 0); + call_set_variable(version, tname1, &tguid1, tmp, data_limit(version) + 1, ATTR_B, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_OUT_OF_RESOURCES); - sv_ok(tname1, &tguid1, tmp, DATA_LIMIT, ATTR_B); + sv_ok(version, tname1, &tguid1, tmp, data_limit(version), ATTR_B); /* Cannot exceed DATA_LIMIT by appending */ - call_set_variable(tname1, &tguid1, tmp, 1, ATTR_B | EFI_VARIABLE_APPEND_WRITE, 0); + call_set_variable(version, tname1, &tguid1, tmp, 1, ATTR_B | EFI_VARIABLE_APPEND_WRITE, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_OUT_OF_RESOURCES); - sv_ok(tname4, &tguid4, tmp, DATA_LIMIT, ATTR_B); + remaining -= data_limit(version) + dstring_data_size(tname1) + VARIABLE_SIZE_OVERHEAD; + if (version == 1) { + sv_ok(version, tname4, &tguid4, tmp, data_limit(version), ATTR_B); + remaining -= data_limit(version) + dstring_data_size(tname4) + VARIABLE_SIZE_OVERHEAD; + } /* Use all the remaining space */ - remaining = TOTAL_LIMIT - 2 * DATA_LIMIT - dstring_data_size(tname1) - - dstring_data_size(tname4) - - dstring_data_size(tname2) - 3 * VARIABLE_SIZE_OVERHEAD; - sv_ok(tname2, &tguid2, tmp, remaining, ATTR_B); + remaining -= dstring_data_size(tname2) + VARIABLE_SIZE_OVERHEAD; + sv_ok(version, tname2, &tguid2, tmp, remaining, ATTR_B); /* Cannot use any more space with a new variable */ - call_set_variable(tname3, &tguid3, tmp, 1, ATTR_B, 0); + call_set_variable(version, tname3, &tguid3, tmp, 1, ATTR_B, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_OUT_OF_RESOURCES); /* Cannot use any more by appending */ - call_set_variable(tname1, &tguid1, tmp, 1, ATTR_B | EFI_VARIABLE_APPEND_WRITE, 0); + call_set_variable(version, tname1, &tguid1, tmp, 1, ATTR_B | EFI_VARIABLE_APPEND_WRITE, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_OUT_OF_RESOURCES); /* Cannot use any more by replacing */ - call_set_variable(tname2, &tguid2, tmp, remaining + 1, ATTR_B, 0); + call_set_variable(version, tname2, &tguid2, tmp, remaining + 1, ATTR_B, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_OUT_OF_RESOURCES); /* Can update without exceeding the limit */ - sv_ok(tname1, &tguid1, tmp, DATA_LIMIT, ATTR_B); + sv_ok(version, tname1, &tguid1, tmp, data_limit(version), ATTR_B); } -static void test_set_variable_many_vars(void) +MULTI_TEST(test_set_variable_many_vars) { uint8_t *ptr; EFI_STATUS status; @@ -1555,12 +1630,12 @@ static void test_set_variable_many_vars(void) const int count = TOTAL_LIMIT / (VARIABLE_SIZE_OVERHEAD + dstring_data_size(dname) + 1); - reset_vars(); + reset_test(version); /* Set more variables than are allowed based on the variable "overhead". */ for (i = 0; i < count + 1; i++) { sprintf(name, "%04d", i); - call_set_variable(dname, &tguid1, &tmp, 1, ATTR_B, 0); + call_set_variable(version, dname, &tguid1, &tmp, 1, ATTR_B, 0); ptr = buf; status = unserialize_uintn(&ptr); if (i == count) @@ -1571,7 +1646,7 @@ static void test_set_variable_many_vars(void) free_dstring(dname); } -static void test_set_variable_non_volatile(void) +MULTI_TEST(test_set_variable_non_volatile) { uint8_t *ptr, *data; EFI_STATUS status; @@ -1579,16 +1654,16 @@ static void test_set_variable_non_volatile(void) UINT32 attr; remove(save_name); - reset_vars(); - sv_ok(tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_BNV); - sv_ok(tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); - sv_ok(tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BRNV); - sv_ok(tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BR); + reset_test(version); + sv_ok(version, tname1, &tguid1, tdata1, sizeof(tdata1), ATTR_BNV); + sv_ok(version, tname2, &tguid2, tdata2, sizeof(tdata2), ATTR_B); + sv_ok(version, tname3, &tguid3, tdata3, sizeof(tdata3), ATTR_BRNV); + sv_ok(version, tname4, &tguid4, tdata4, sizeof(tdata4), ATTR_BR); - reset_vars(); + reset_test(version); db->init(); - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1599,7 +1674,7 @@ static void test_set_variable_non_volatile(void) g_assert(!memcmp(tdata1, data, data_len)); free(data); - call_get_variable(tname3, &tguid3, BSIZ, 0); + call_get_variable(version, tname3, &tguid3, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1610,23 +1685,23 @@ static void test_set_variable_non_volatile(void) g_assert(!memcmp(tdata3, data, data_len)); free(data); - call_get_variable(tname2, &tguid2, BSIZ, 0); + call_get_variable(version, tname2, &tguid2, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); - call_get_variable(tname4, &tguid4, BSIZ, 0); + call_get_variable(version, tname4, &tguid4, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); /* Update, reload & check */ - sv_ok(tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_BNV); + sv_ok(version, tname1, &tguid1, tdata2, sizeof(tdata2), ATTR_BNV); - reset_vars(); + reset_test(version); db->init(); - call_get_variable(tname1, &tguid1, BSIZ, 0); + call_get_variable(version, tname1, &tguid1, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1638,16 +1713,16 @@ static void test_set_variable_non_volatile(void) free(data); /* Append, reload & check */ - call_set_variable(tname3, &tguid3, tdata4, sizeof(tdata4), + call_set_variable(version, tname3, &tguid3, tdata4, sizeof(tdata4), ATTR_BRNV | EFI_VARIABLE_APPEND_WRITE, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); - reset_vars(); + reset_test(version); db->init(); - call_get_variable(tname3, &tguid3, BSIZ, 0); + call_get_variable(version, tname3, &tguid3, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1660,21 +1735,21 @@ static void test_set_variable_non_volatile(void) free(data); /* Delete, reload & check */ - call_set_variable(tname3, &tguid3, NULL, 0, ATTR_BRNV, 1); + call_set_variable(version, tname3, &tguid3, NULL, 0, ATTR_BRNV, 1); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); - reset_vars(); + reset_test(version); db->init(); - call_get_variable(tname3, &tguid3, BSIZ, 0); + call_get_variable(version, tname3, &tguid3, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_NOT_FOUND); } -static void test_set_variable_special_vars(void) +MULTI_TEST(test_set_variable_special_vars) { int i; dstring *vars[] = {auditMode_name, deployedMode_name, setupMode_name, @@ -1682,7 +1757,7 @@ static void test_set_variable_special_vars(void) UINT32 attrs[] = {ATTR_BR, ATTR_BR | EFI_VARIABLE_APPEND_WRITE, ATTR_BRNV, ATTR_BRNV_TIME, 0}; - reset_vars(); + reset_test(version); setup_variables(); for (i = 0; i < ARRAY_SIZE(vars); i++) { @@ -1693,16 +1768,16 @@ static void test_set_variable_special_vars(void) /* Check that special variables cannot be set/appended to. */ for (j = 0; j < ARRAY_SIZE(attrs); j++) { - sv_check(vars[i], &gEfiGlobalVariableGuid, + sv_check(version, vars[i], &gEfiGlobalVariableGuid, tdata1, sizeof(tdata1), attrs[j], EFI_WRITE_PROTECTED); } /* Check that special variables cannot be removed. */ - sv_check(vars[i], &gEfiGlobalVariableGuid, + sv_check(version, vars[i], &gEfiGlobalVariableGuid, NULL, 0, ATTR_BR, EFI_WRITE_PROTECTED); /* Check that special variables exist and their attr are correct. */ - call_get_variable(vars[i], &gEfiGlobalVariableGuid, BSIZ, 0); + call_get_variable(version, vars[i], &gEfiGlobalVariableGuid, BSIZ, 0); status = unserialize_uintn(&ptr); /* status */ g_assert_cmpuint(status, ==, EFI_SUCCESS); @@ -1711,7 +1786,7 @@ static void test_set_variable_special_vars(void) } /* AuditMode must always be 0 in our implementation. */ - check_variable_data(auditMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, auditMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); /* @@ -1722,181 +1797,235 @@ static void test_set_variable_special_vars(void) */ } -static void test_set_variable_mor(void) +MULTI_TEST(test_set_variable_mor) { uint8_t data[] = {0, 0}; uint8_t expected = 0; - reset_vars(); + reset_test(version); setup_variables(); setup_mor_variables(); /* Check initial value of morControl is 0 */ - check_variable_data(morControl_name, &morControlGuid, BSIZ, 0, + check_variable_data(version, morControl_name, &morControlGuid, BSIZ, 0, &expected, 1); /* Storing more than 1 byte in morControl fails */ - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 2, ATTR_BRNV, EFI_INVALID_PARAMETER); /* Deleting morControl fails */ - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 0, ATTR_BRNV, EFI_INVALID_PARAMETER); - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 1, 0, EFI_INVALID_PARAMETER); /* Storing with invalid attributes in morControl fails */ - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 1, ATTR_B, EFI_INVALID_PARAMETER); - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 1, ATTR_BRNV | EFI_VARIABLE_APPEND_WRITE, EFI_INVALID_PARAMETER); /* Setting reserved bits in morControl fails */ data[0] = 0x2e; - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 1, ATTR_BRNV, EFI_INVALID_PARAMETER); /* Setting allowed bits in morControl works */ data[0] = 0x11; - sv_ok(morControl_name, &morControlGuid, + sv_ok(version, morControl_name, &morControlGuid, data, 1, ATTR_BRNV); /* Check morControl is now set */ expected = 0x11; - check_variable_data(morControl_name, &morControlGuid, BSIZ, 0, + check_variable_data(version, morControl_name, &morControlGuid, BSIZ, 0, &expected, 1); /* Check morControlLock is 0 (unlocked) at startup */ expected = 0; - check_variable_data(morControlLock_name, &morControlLockGuid, BSIZ, 0, + check_variable_data(version, morControlLock_name, &morControlLockGuid, BSIZ, 0, &expected, 1); /* Storing something other than 1 or 8 bytes in morControlLock fails */ data[0] = 0; - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 2, ATTR_BRNV, EFI_INVALID_PARAMETER); /* Deleting morControlLock fails */ - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 0, ATTR_BRNV, EFI_WRITE_PROTECTED); - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 1, 0, EFI_WRITE_PROTECTED); /* Storing with invalid attributes in morControlLock fails */ - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_B, EFI_INVALID_PARAMETER); - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_BRNV | EFI_VARIABLE_APPEND_WRITE, EFI_INVALID_PARAMETER); /* Unlock when already unlocked is a no-op */ - sv_ok(morControlLock_name, &morControlLockGuid, + sv_ok(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_BRNV); /* Storing an invalid value in morControlLock fails */ data[0] = 2; - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_BRNV, EFI_INVALID_PARAMETER); /* Locking without a key succeeds */ data[0] = 1; - sv_ok(morControlLock_name, &morControlLockGuid, + sv_ok(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_BRNV); /* morControlLock is now 1 (locked) */ expected = 1; - check_variable_data(morControlLock_name, &morControlLockGuid, BSIZ, 0, + check_variable_data(version, morControlLock_name, &morControlLockGuid, BSIZ, 0, &expected, 1); /* Setting morControl when locked fails */ - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, data, 1, ATTR_BRNV, EFI_WRITE_PROTECTED); /* Locking when already locked fails */ - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_BRNV, EFI_ACCESS_DENIED); /* Unlocking when locked without a key fails */ data[0] = 0; - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 1, ATTR_BRNV, EFI_ACCESS_DENIED); } -static void test_set_variable_mor_key(void) +MULTI_TEST(test_set_variable_mor_key) { uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8}; uint8_t mor_control_data = 1; uint8_t expected; - reset_vars(); + reset_test(version); setup_variables(); setup_mor_variables(); /* morControlLock is initialized to 0 (unlocked) */ expected = 0; - check_variable_data(morControlLock_name, &morControlLockGuid, BSIZ, 0, + check_variable_data(version, morControlLock_name, &morControlLockGuid, BSIZ, 0, &expected, 1); /* Setting morControl when unlocked succeeds */ - sv_ok(morControl_name, &morControlGuid, + sv_ok(version, morControl_name, &morControlGuid, &mor_control_data, 1, ATTR_BRNV); /* Locking with a key succeeds */ - sv_ok(morControlLock_name, &morControlLockGuid, + sv_ok(version, morControlLock_name, &morControlLockGuid, data, 8, ATTR_BRNV); /* morControlLock is now 2 (locked with key) */ expected = 2; - check_variable_data(morControlLock_name, &morControlLockGuid, BSIZ, 0, + check_variable_data(version, morControlLock_name, &morControlLockGuid, BSIZ, 0, &expected, 1); /* Setting morControl when locked fails */ - sv_check(morControl_name, &morControlGuid, + sv_check(version, morControl_name, &morControlGuid, &mor_control_data, 1, ATTR_BRNV, EFI_WRITE_PROTECTED); /* Unlocking with the correct key works */ - sv_ok(morControlLock_name, &morControlLockGuid, + sv_ok(version, morControlLock_name, &morControlLockGuid, data, 8, ATTR_BRNV); /* morControlLock is now 0 (unlocked) */ expected = 0; - check_variable_data(morControlLock_name, &morControlLockGuid, BSIZ, 0, + check_variable_data(version, morControlLock_name, &morControlLockGuid, BSIZ, 0, &expected, 1); /* Setting morControl when unlocked succeeds again */ mor_control_data = 0; - sv_ok(morControl_name, &morControlGuid, + sv_ok(version, morControl_name, &morControlGuid, &mor_control_data, 1, ATTR_BRNV); /* Relock it */ - sv_ok(morControlLock_name, &morControlLockGuid, + sv_ok(version, morControlLock_name, &morControlLockGuid, data, 8, ATTR_BRNV); /* Unlocking with an incorrect key fails */ data[0] = 0; - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 8, ATTR_BRNV, EFI_ACCESS_DENIED); /* morControlLock is now 1 (locked without key) */ expected = 1; - check_variable_data(morControlLock_name, &morControlLockGuid, BSIZ, 0, + check_variable_data(version, morControlLock_name, &morControlLockGuid, BSIZ, 0, &expected, 1); /* Unlocking when locked without key fails */ data[0] = 1; - sv_check(morControlLock_name, &morControlLockGuid, + sv_check(version, morControlLock_name, &morControlLockGuid, data, 8, ATTR_BRNV, EFI_ACCESS_DENIED); } -static void set_usermode(void) +static void test_set_variable_v2_downgrade(void) +{ + EFI_STATUS status; + uint8_t tmp[DATA_LIMIT_MAX] = {0}; + uint8_t *ptr; + + reset_test(2); + + sv_ok(2, tname1, &tguid1, tmp, DATA_LIMIT_V2, ATTR_B); + + reset_buf(SHMEM_PAGES_V1); + + call_get_variable(1, tname1, &tguid1, DATA_LIMIT_V1, 1); + + /* Whatever it does here, it shouldn't crash. */ + + ptr = buf; + status = unserialize_uintn(&ptr); /* status */ + g_assert_cmpuint(status, !=, EFI_SUCCESS); +} + +static void test_set_variable_v2_short_buffer(void) +{ + UINT32 nr_pages; + EFI_STATUS status; + uint8_t tmp[DATA_LIMIT_V2] = {0}; + uint8_t *ptr = buf; + + reset_test(2); + + sv_ok(2, tname1, &tguid1, tmp, DATA_LIMIT_V2, ATTR_B); + + for (nr_pages = 1; nr_pages < SHMEM_PAGES_V2_MIN; nr_pages++) { + reset_buf(nr_pages); + call_get_variable(2, tname1, &tguid1, DATA_LIMIT_V2, 0); + ptr = buf; + status = unserialize_uintn(&ptr); /* status */ + g_assert_cmpuint(status, ==, EFI_INVALID_PARAMETER); + } + /* + * TODO: For now all nr_pages values within range are valid for containing + * a variable of size DATA_LIMIT_V2. If DATA_LIMIT_V2 is increased, full + * serialization bounds check would be needed. + */ + for (nr_pages = SHMEM_PAGES_V2_MIN; nr_pages <= SHMEM_PAGES_V2_MAX; + nr_pages++) { + reset_buf(nr_pages); + call_get_variable(2, tname1, &tguid1, DATA_LIMIT_V2, 0); + ptr = buf; + status = unserialize_uintn(&ptr); /* status */ + g_assert_cmpuint(status, ==, EFI_SUCCESS); + } +} + +static void set_usermode(UINT32 version) { /* Move into user mode by enrolling Platform Key. */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timea, (uint8_t *)certPK, certPK_len, &sign_testPK, EFI_SUCCESS); } -static void test_use_bad_digest(void) +MULTI_TEST(test_use_bad_digest) { /* * Attempt bad digest @@ -1906,14 +2035,14 @@ static void test_use_bad_digest(void) * algorithm of SHA-256 is accepted. */ - reset_vars(); + reset_test(version); setup_variables(); - sign_and_check(tname1, &tguid1, ATTR_B_TIME, &test_timea, tdata1, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME, &test_timea, tdata1, sizeof(tdata1), &sign_bad_digest, EFI_SECURITY_VIOLATION); } -static void test_set_secure_variable(void) +static void test_set_secure_variable(UINT32 version) { const char tosign_data[] = "testdata"; const char tosign2_data[] = "|appended"; @@ -1925,25 +2054,25 @@ static void test_set_secure_variable(void) int len; /* 1. Create a EFI_VARIABLE_AUTHENTICATION_2 variable */ - sign_and_check(tname1, &tguid1, ATTR_B_TIME, &test_timea, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME, &test_timea, (uint8_t *)tosign_data, strlen((char *)tosign_data), &sign_testPK, EFI_SUCCESS); - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_data, strlen(tosign_data)); /* 2. try append */ - sign_and_check(tname1, &tguid1, ATTR_B_TIME | EFI_VARIABLE_APPEND_WRITE, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME | EFI_VARIABLE_APPEND_WRITE, &test_timeb, (uint8_t *)tosign2_data, strlen(tosign2_data), &sign_testPK, EFI_SUCCESS); - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_appended_data, strlen(tosign_appended_data)); /* 3. Try append with older time stamp (is meant to work!) */ - sign_and_check(tname1, &tguid1, ATTR_B_TIME | EFI_VARIABLE_APPEND_WRITE, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME | EFI_VARIABLE_APPEND_WRITE, &test_timea, (uint8_t *)tosign3_data, strlen(tosign3_data), &sign_testPK, EFI_SUCCESS); - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_appended2_data, strlen(tosign_appended2_data)); @@ -1951,10 +2080,10 @@ static void test_set_secure_variable(void) * Try updating, at time b. This shouldn't work. (appends with bad times, * don't update the time */ - sign_and_check(tname1, &tguid1, ATTR_B_TIME, &test_timeb, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME, &test_timeb, (uint8_t *)tosign3_data, strlen(tosign3_data), &sign_testPK, EFI_SECURITY_VIOLATION); - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_appended2_data, strlen(tosign_appended2_data)); @@ -1968,22 +2097,22 @@ static void test_set_secure_variable(void) ATTR_B_TIME, &test_timec, (uint8_t *)tosign2_data, strlen(tosign2_data), &sign_testPK); assert(len); - sv_check(tname1, &tguid1, sign_buffer, len, ATTR_B_TIME | + sv_check(version, tname1, &tguid1, sign_buffer, len, ATTR_B_TIME | EFI_VARIABLE_APPEND_WRITE, EFI_SECURITY_VIOLATION); free(sign_buffer); /* check it's the same */ - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_appended2_data, strlen(tosign_appended2_data)); /* 4. Try updating with wrong key */ - sign_and_check(tname1, &tguid1, ATTR_B_TIME, &test_timec, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME, &test_timec, (uint8_t *)tosign2_data, strlen(tosign2_data), &sign_certB, EFI_SECURITY_VIOLATION); /* check it's the same */ - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_appended2_data, strlen(tosign_appended2_data)); @@ -1991,23 +2120,23 @@ static void test_set_secure_variable(void) * Check authenticated variables cannot be deleted by unsetting attriubtes * (2.7A page 248) */ - sign_and_check(tname1, &tguid1, 0, &test_timec, + sign_and_check(version, tname1, &tguid1, 0, &test_timec, NULL, 0, &sign_testPK, EFI_INVALID_PARAMETER); /* Check variable is the same */ - check_variable_data(tname1, &tguid1, BSIZ, 0, + check_variable_data(version, tname1, &tguid1, BSIZ, 0, (uint8_t *)tosign_appended2_data, strlen(tosign_appended2_data)); /* try deleting */ - sign_and_check(tname1, &tguid1, ATTR_B_TIME, &test_timec, NULL, 0, + sign_and_check(version, tname1, &tguid1, ATTR_B_TIME, &test_timec, NULL, 0, &sign_testPK, EFI_SUCCESS); } -static void test_secure_set_variable_setupmode(void) +MULTI_TEST(test_secure_set_variable_setupmode) { - reset_vars(); + reset_test(version); setup_variables(); /* @@ -2016,115 +2145,115 @@ static void test_secure_set_variable_setupmode(void) * operating in setup mode. */ - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - test_set_secure_variable(); + test_set_secure_variable(version); } -static void test_secure_set_variable_usermode(void) +MULTI_TEST(test_secure_set_variable_usermode) { - reset_vars(); + reset_test(version); setup_variables(); /* Check we're in setup mode */ - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - set_usermode(); + set_usermode(version); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - test_set_secure_variable(); + test_set_secure_variable(version); } -static void test_secure_set_PK(void) +MULTI_TEST(test_secure_set_PK) { EFI_SIGNATURE_LIST *joint_cert; size_t joint_len; uint8_t *ptr; size_t i; - reset_vars(); + reset_test(version); setup_variables(); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); /* try cert, signed by someone unknown. Should be no mode change. */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timea, (uint8_t *)certPK, certPK_len, &sign_certB, EFI_SECURITY_VIOLATION); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); /* try setting PK, with wrong attributes */ - sv_check(PK_name, &gEfiGlobalVariableGuid, (uint8_t *)certPK, certPK_len, + sv_check(version, PK_name, &gEfiGlobalVariableGuid, (uint8_t *)certPK, certPK_len, ATTR_BRNV, EFI_INVALID_PARAMETER); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, &test_timea, (uint8_t *)certPK, certPK_len, &sign_certB, EFI_NOT_FOUND); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_B_TIME | EFI_VARIABLE_RUNTIME_ACCESS, &test_timea, (uint8_t *)certPK, certPK_len, &sign_certB, EFI_INVALID_PARAMETER); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_B_TIME | EFI_VARIABLE_NON_VOLATILE, &test_timea, (uint8_t *)certPK, certPK_len, &sign_certB, EFI_INVALID_PARAMETER); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, &test_timea, (uint8_t *)certPK, certPK_len, &sign_certB, EFI_INVALID_PARAMETER); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); /* Set PK, self signed - should move to user mode */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timea, (uint8_t *)certPK, certPK_len, &sign_testPK, EFI_SUCCESS); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); /* new cert, signed by self */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, (uint8_t *)certB, certB_len, &sign_certB, EFI_SECURITY_VIOLATION); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); /* @@ -2136,40 +2265,40 @@ static void test_secure_set_PK(void) uint8_t *buf = calloc(i, 1); assert(buf); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, buf, i, &sign_testPK, EFI_INVALID_PARAMETER); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); memcpy(buf, certB, i); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, buf, i, &sign_testPK, EFI_INVALID_PARAMETER); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); free(buf); } /* Try appending a second cert - should not work */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, &test_timeb, (uint8_t *)certB, certB_len, &sign_testPK, EFI_INVALID_PARAMETER); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); /* Try setting two keys in one write, two lists */ @@ -2181,7 +2310,7 @@ static void test_secure_set_PK(void) memcpy(ptr, certB, certB_len); joint_len = certPK_len + certB_len; - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, (uint8_t *)joint_cert, joint_len, &sign_testPK, EFI_INVALID_PARAMETER); @@ -2191,7 +2320,7 @@ static void test_secure_set_PK(void) char *cert_list[] = {"testPK.pem", "testcertB.pem", NULL}; read_x509_list_into_CertList(cert_list, &joint_cert, &joint_len); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, (uint8_t *)joint_cert, joint_len, &sign_testPK, EFI_INVALID_PARAMETER); @@ -2199,40 +2328,40 @@ static void test_secure_set_PK(void) free(joint_cert); /* new cert, signed by previous */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, (uint8_t *)certB, certB_len, &sign_testPK, EFI_SUCCESS); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); /* delete it, with first (should fail) */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timec, NULL, 0, &sign_testPK, EFI_SECURITY_VIOLATION); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); /* delete it, with second */ - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timec, NULL, 0, &sign_certB, EFI_SUCCESS); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - sign_and_check(PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, PK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_timeb, NULL, 0, &sign_testPK, EFI_NOT_FOUND); } -static void sig_db_check(const dstring *key_db, const EFI_GUID *guid, +static void sig_db_check(UINT32 version, const dstring *key_db, const EFI_GUID *guid, EFI_TIME *time, bool setup) { uint8_t *ptr, *data, *data_ptr; @@ -2245,32 +2374,32 @@ static void sig_db_check(const dstring *key_db, const EFI_GUID *guid, uint8_t *securemode = setup ? (uint8_t *)"\0" : (uint8_t *)"\1"; /* Check SetupMode and SecureBoot vars are as expected */ - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, setupmode, 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, deployedmode, 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, securemode, 1); - sv_check(key_db, guid, (uint8_t *)certA, certA_len, + sv_check(version, key_db, guid, (uint8_t *)certA, certA_len, ATTR_BRNV, EFI_INVALID_PARAMETER); - sign_and_check(key_db, guid, + sign_and_check(version, key_db, guid, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, time, (uint8_t *)certA, certA_len, &sign_certB, EFI_NOT_FOUND); - sign_and_check(key_db, guid, + sign_and_check(version, key_db, guid, ATTR_B_TIME | EFI_VARIABLE_RUNTIME_ACCESS, time, (uint8_t *)certA, certA_len, &sign_certB, EFI_INVALID_PARAMETER); - sign_and_check(key_db, guid, + sign_and_check(version, key_db, guid, ATTR_B_TIME | EFI_VARIABLE_NON_VOLATILE, time, (uint8_t *)certA, certA_len, &sign_certB, EFI_INVALID_PARAMETER); - sign_and_check(key_db, guid, + sign_and_check(version, key_db, guid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, time, (uint8_t *)certA, certA_len, @@ -2285,13 +2414,13 @@ static void sig_db_check(const dstring *key_db, const EFI_GUID *guid, uint8_t *buf = calloc(i, 1); assert(buf); - sign_and_check(key_db, guid, ATTR_BRNV_TIME, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, buf, i, &sign_testPK, EFI_INVALID_PARAMETER); memcpy(buf, certA, i); - sign_and_check(key_db, guid, ATTR_BRNV_TIME, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, buf, i, &sign_testPK, EFI_INVALID_PARAMETER); @@ -2299,56 +2428,56 @@ static void sig_db_check(const dstring *key_db, const EFI_GUID *guid, } /* try a valid signed cert, but not signed by PK */ - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)certB, certB_len, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)certB, certB_len, &sign_certB, setup ? EFI_SUCCESS : EFI_SECURITY_VIOLATION); if (setup) { time->Second++; - check_variable_data(key_db, guid, BSIZ, 0, (uint8_t *)certB, certB_len); + check_variable_data(version, key_db, guid, BSIZ, 0, (uint8_t *)certB, certB_len); } /* try a cert, signed by someone unknown. */ - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)certA, certA_len, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)certA, certA_len, &sign_certB, setup ? EFI_SUCCESS : EFI_SECURITY_VIOLATION); if (setup) { time->Second++; - check_variable_data(key_db, guid, BSIZ, 0, (uint8_t *)certA, certA_len); + check_variable_data(version, key_db, guid, BSIZ, 0, (uint8_t *)certA, certA_len); } /* SetupMode and SecureBoot vars should not have changed */ - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, setupmode, 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, deployedmode, 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, securemode, 1); if (!setup) { /* try a valid cert */ - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)certA, certA_len, &sign_testPK, EFI_SUCCESS); time->Second++; - check_variable_data(key_db, guid, BSIZ, 0, (uint8_t *)certA, certA_len); + check_variable_data(version, key_db, guid, BSIZ, 0, (uint8_t *)certA, certA_len); } /* SetupMode and SecureBoot vars should not have changed */ - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, setupmode, 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, deployedmode, 1); - check_variable_data(secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, secureBoot_name, &gEfiGlobalVariableGuid, BSIZ, 0, securemode, 1); /* Try appending another */ - sign_and_check(key_db, guid, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, time, (uint8_t *)certB, certB_len, &sign_certB, setup ? EFI_SUCCESS : EFI_SECURITY_VIOLATION); if (!setup) - sign_and_check(key_db, guid, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, time, (uint8_t *)certB, certB_len, &sign_testPK, EFI_SUCCESS); @@ -2356,7 +2485,7 @@ static void sig_db_check(const dstring *key_db, const EFI_GUID *guid, time->Second++; /* Check it */ - call_get_variable(key_db, guid, certA_len + certB_len, 0); + call_get_variable(version, key_db, guid, certA_len + certB_len, 0); ptr = buf; status = unserialize_uintn(&ptr); vsd_assert_status("status", status, ==, EFI_SUCCESS); @@ -2368,21 +2497,21 @@ static void sig_db_check(const dstring *key_db, const EFI_GUID *guid, assert_cmpmem(data_ptr, data_len - certA_len, certB, certB_len); /* Delete */ - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, &sign_certB, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, &sign_certB, setup ? EFI_SUCCESS : EFI_SECURITY_VIOLATION); if (!setup) - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, &sign_testPK, EFI_SUCCESS); /* Try deleting again */ - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, &sign_testPK, EFI_NOT_FOUND); free(data); } -static void sig_db_check_multi(const dstring *key_db, const EFI_GUID *guid, +static void sig_db_check_multi(UINT32 version, const dstring *key_db, const EFI_GUID *guid, EFI_TIME *time) { EFI_SIGNATURE_LIST *combined_cert; @@ -2400,7 +2529,7 @@ static void sig_db_check_multi(const dstring *key_db, const EFI_GUID *guid, temp = *first_data; *first_data = -1; - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)combined_cert, combined_len, &sign_testPK, EFI_INVALID_PARAMETER); @@ -2412,18 +2541,18 @@ static void sig_db_check_multi(const dstring *key_db, const EFI_GUID *guid, temp = *second_data; *second_data = -1; - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)combined_cert, combined_len, &sign_testPK, EFI_INVALID_PARAMETER); *second_data = temp; - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)combined_cert, combined_len, &sign_testPK, EFI_SUCCESS); free(combined_cert); } -static void test_secure_set_KEK_setupmode(void) +MULTI_TEST(test_secure_set_KEK_setupmode) { uint8_t *ptr, *data, *data_ptr; EFI_STATUS status; @@ -2431,30 +2560,30 @@ static void test_secure_set_KEK_setupmode(void) UINT32 attr; EFI_TIME test_time = {2018, 6, 20, 13, 38, 0, 0, 0, 0, 0, 0}; - reset_vars(); + reset_test(version); setup_variables(); - sig_db_check(KEK_name, &gEfiGlobalVariableGuid, &test_time, true); + sig_db_check(version, KEK_name, &gEfiGlobalVariableGuid, &test_time, true); /* new cert, signed by self */ - sign_and_check(KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certB, certB_len, &sign_certB, EFI_SUCCESS); test_time.Second++; - call_get_variable(KEK_name, &gEfiGlobalVariableGuid, BSIZ, 0); + call_get_variable(version, KEK_name, &gEfiGlobalVariableGuid, BSIZ, 0); ptr = buf; status = unserialize_uintn(&ptr); g_assert_cmpuint(status, ==, EFI_SUCCESS); /* Try appending a second cert */ - sign_and_check(KEK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, &test_time, (uint8_t *)certA, certA_len, &sign_testPK, EFI_SUCCESS); test_time.Second++; - call_get_variable(KEK_name, &gEfiGlobalVariableGuid, certA_len + certB_len, 0); + call_get_variable(version, KEK_name, &gEfiGlobalVariableGuid, certA_len + certB_len, 0); ptr = buf; status = unserialize_uintn(&ptr); vsd_assert_status("status", status, ==, EFI_SUCCESS); @@ -2468,16 +2597,16 @@ static void test_secure_set_KEK_setupmode(void) free(data); } -static void test_secure_set_KEK_usermode(void) +MULTI_TEST(test_secure_set_KEK_usermode) { EFI_TIME test_time = {2018, 6, 20, 13, 38, 0, 0, 0, 0, 0, 0}; - reset_vars(); + reset_test(version); setup_variables(); - set_usermode(); + set_usermode(version); - sig_db_check(KEK_name, &gEfiGlobalVariableGuid, &test_time, false); - sig_db_check_multi(KEK_name, &gEfiGlobalVariableGuid, &test_time); + sig_db_check(version, KEK_name, &gEfiGlobalVariableGuid, &test_time, false); + sig_db_check_multi(version, KEK_name, &gEfiGlobalVariableGuid, &test_time); } /* @@ -2486,7 +2615,7 @@ static void test_secure_set_KEK_usermode(void) * perform an append of EFI_SIGNATURE_DATA values that are already part of * the existing variable value. */ -static void test_duplicate_db(const dstring *key_db, const EFI_GUID *guid, +static void test_duplicate_db(UINT32 version, const dstring *key_db, const EFI_GUID *guid, EFI_TIME *time, bool setup) { uint8_t *ptr, *data, *data_ptr; @@ -2494,21 +2623,21 @@ static void test_duplicate_db(const dstring *key_db, const EFI_GUID *guid, UINTN data_len; UINT32 attr; - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, (uint8_t *)certA, certA_len, &sign_testPK, EFI_SUCCESS); time->Second++; - sign_and_check(key_db, guid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, time, (uint8_t *)certB, certB_len, &sign_testPK, EFI_SUCCESS); time->Second++; - sign_and_check(key_db, guid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, time, (uint8_t *)certA, certA_len, &sign_testPK, EFI_SUCCESS); /* Check DB - should be two items */ - call_get_variable(key_db, guid, certA_len * 2 + certB_len, 0); + call_get_variable(version, key_db, guid, certA_len * 2 + certB_len, 0); ptr = buf; status = unserialize_uintn(&ptr); vsd_assert_status("status", status, ==, EFI_SUCCESS); @@ -2520,92 +2649,92 @@ static void test_duplicate_db(const dstring *key_db, const EFI_GUID *guid, assert_cmpmem(data_ptr, data_len - certA_len, certB, certB_len); /* Check timestamp was updated */ - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, &sign_testPK, setup ? EFI_SUCCESS : EFI_SECURITY_VIOLATION); time->Second++; if (!setup) - sign_and_check(key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, + sign_and_check(version, key_db, guid, ATTR_BRNV_TIME, time, NULL, 0, &sign_testPK, EFI_SUCCESS); free(data); } -static void test_secure_set_db__setupmode(const dstring *key_db) +static void test_secure_set_db__setupmode(UINT32 version, const dstring *key_db) { EFI_TIME test_time = {2018, 6, 20, 13, 38, 0, 0, 0, 0, 0, 0}; - reset_vars(); + reset_test(version); setup_variables(); - check_variable_data(setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, setupMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\1", 1); - check_variable_data(deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, + check_variable_data(version, deployedMode_name, &gEfiGlobalVariableGuid, BSIZ, 0, (uint8_t *)"\0", 1); - sig_db_check(key_db, &gEfiImageSecurityDatabaseGuid, &test_time, true); + sig_db_check(version, key_db, &gEfiImageSecurityDatabaseGuid, &test_time, true); - test_duplicate_db(key_db, &gEfiImageSecurityDatabaseGuid, &test_time, true); + test_duplicate_db(version, key_db, &gEfiImageSecurityDatabaseGuid, &test_time, true); } -static void test_secure_set_db_setupmode(void) +MULTI_TEST(test_secure_set_db_setupmode) { - test_secure_set_db__setupmode(db_name); + test_secure_set_db__setupmode(version, db_name); } -static void test_secure_set_dbx_setupmode(void) +MULTI_TEST(test_secure_set_dbx_setupmode) { - test_secure_set_db__setupmode(dbx_name); + test_secure_set_db__setupmode(version, dbx_name); } -static void test_secure_set_dbt_setupmode(void) +MULTI_TEST(test_secure_set_dbt_setupmode) { - test_secure_set_db__setupmode(dbt_name); + test_secure_set_db__setupmode(version, dbt_name); } -static void test_secure_set_db__usermode(const dstring *key_db) +static void test_secure_set_db__usermode(UINT32 version, const dstring *key_db) { EFI_TIME test_time = {2018, 6, 20, 13, 38, 0, 0, 0, 0, 0, 0}; EFI_SIGNATURE_LIST *combined_cert; size_t combined_len; char *cert_list[] = {"testPK.pem", "testcertB.pem", NULL}; - reset_vars(); + reset_test(version); setup_variables(); - set_usermode(); + set_usermode(version); - sig_db_check(key_db, &gEfiImageSecurityDatabaseGuid, &test_time, false); - sig_db_check_multi(key_db, &gEfiImageSecurityDatabaseGuid, &test_time); + sig_db_check(version, key_db, &gEfiImageSecurityDatabaseGuid, &test_time, false); + sig_db_check_multi(version, key_db, &gEfiImageSecurityDatabaseGuid, &test_time); test_time.Second++; /* * Previous checked PK owner can add db key * Now check a KEK key can be used. */ - sign_and_check(KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certB, certB_len, &sign_testPK, EFI_SUCCESS); - sign_and_check(key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, + sign_and_check(version, key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certA, certA_len, &sign_certB, EFI_SUCCESS); test_time.Second++; /* Try it as KEK second key (two lists) */ - sign_and_check(KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, + sign_and_check(version, KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certPK, certPK_len, &sign_testPK, EFI_SUCCESS); - sign_and_check(key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, + sign_and_check(version, key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certA, certA_len, &sign_certB, EFI_SECURITY_VIOLATION); - sign_and_check(KEK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME | EFI_VARIABLE_APPEND_WRITE, &test_time, (uint8_t *)certB, certB_len, &sign_testPK, EFI_SUCCESS); - sign_and_check(key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, + sign_and_check(version, key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certA, certA_len, &sign_certB, EFI_SUCCESS); @@ -2613,35 +2742,41 @@ static void test_secure_set_db__usermode(const dstring *key_db) /* Try it as KEK second key (one list) */ read_x509_list_into_CertList(cert_list, &combined_cert, &combined_len); - sign_and_check(KEK_name, &gEfiGlobalVariableGuid, + sign_and_check(version, KEK_name, &gEfiGlobalVariableGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)combined_cert, combined_len, &sign_testPK, EFI_SUCCESS); - sign_and_check(key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, + sign_and_check(version, key_db, &gEfiImageSecurityDatabaseGuid, ATTR_BRNV_TIME, &test_time, (uint8_t *)certA, certA_len, &sign_certB, EFI_SUCCESS); test_time.Second++; - test_duplicate_db(key_db, &gEfiImageSecurityDatabaseGuid, &test_time, false); + test_duplicate_db(version, key_db, &gEfiImageSecurityDatabaseGuid, &test_time, false); free(combined_cert); } -static void test_secure_set_db_usermode(void) +MULTI_TEST(test_secure_set_db_usermode) { - test_secure_set_db__usermode(db_name); + test_secure_set_db__usermode(version, db_name); } -static void test_secure_set_dbx_usermode(void) +MULTI_TEST(test_secure_set_dbx_usermode) { - test_secure_set_db__usermode(dbx_name); + test_secure_set_db__usermode(version, dbx_name); } -static void test_secure_set_dbt_usermode(void) +MULTI_TEST(test_secure_set_dbt_usermode) { - test_secure_set_db__usermode(dbt_name); + test_secure_set_db__usermode(version, dbt_name); } +#define ADD_MULTI_TEST(test_name, test_func) \ + do { \ + g_test_add_func(test_name "_v1", test_func ## _v1); \ + g_test_add_func(test_name "_v2", test_func ## _v2); \ + } while (0); + int main(int argc, char **argv) { int r; @@ -2651,79 +2786,83 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); - g_test_add_func("/test/get_variable/no_name", - test_get_variable_no_name); - g_test_add_func("/test/get_variable/long_name", - test_get_variable_long_name); - g_test_add_func("/test/get_variable/not_found", - test_get_variable_not_found); - g_test_add_func("/test/get_variable/found", - test_get_variable_found); - g_test_add_func("/test/get_variable/too_small", - test_get_variable_too_small); - g_test_add_func("/test/query_variable_info", - test_query_variable_info); - g_test_add_func("/test/get_next_variable/empty", - test_get_next_variable_empty); - g_test_add_func("/test/get_next_variable/long_name", - test_get_next_variable_long_name); - g_test_add_func("/test/get_next_variable/only_runtime", - test_get_next_variable_only_runtime); - g_test_add_func("/test/get_next_variable/too_small", - test_get_next_variable_too_small); - g_test_add_func("/test/get_next_variable/no_match", - test_get_next_variable_no_match); - g_test_add_func("/test/get_next_variable/all", - test_get_next_variable_all); - g_test_add_func("/test/set_variable/attr", - test_set_variable_attr); - g_test_add_func("/test/set_variable/set", - test_set_variable_set); - g_test_add_func("/test/set_variable/update", - test_set_variable_update); - g_test_add_func("/test/set_variable/append", - test_set_variable_append); - g_test_add_func("/test/set_variable/delete", - test_set_variable_delete); - g_test_add_func("/test/set_variable/resource_limit", - test_set_variable_resource_limit); - g_test_add_func("/test/set_variable/many_vars", - test_set_variable_many_vars); - g_test_add_func("/test/set_variable/non_volatile", - test_set_variable_non_volatile); - g_test_add_func("/test/set_variable/special_vars", - test_set_variable_special_vars); - g_test_add_func("/test/set_variable/mor", - test_set_variable_mor); - g_test_add_func("/test/set_variable/mor_key", - test_set_variable_mor_key); - - g_test_add_func("/test/secure_set_variable/use_bad_digest", - test_use_bad_digest); - g_test_add_func("/test/secure_set_variable/setupmode", - test_secure_set_variable_setupmode); - g_test_add_func("/test/secure_set_variable/PK", - test_secure_set_PK); - g_test_add_func("/test/secure_set_variable/usermode", - test_secure_set_variable_usermode); - g_test_add_func("/test/secure_set_variable/KEK/setupmode", - test_secure_set_KEK_setupmode); - g_test_add_func("/test/secure_set_variable/KEK/usermode", - test_secure_set_KEK_usermode); - - g_test_add_func("/test/secure_set_variable/DB/setupmode", - test_secure_set_db_setupmode); - g_test_add_func("/test/secure_set_variable/DBX/setupmode", - test_secure_set_dbx_setupmode); - g_test_add_func("/test/secure_set_variable/DBT/setupmode", - test_secure_set_dbt_setupmode); - - g_test_add_func("/test/secure_set_variable/DB/usermode", - test_secure_set_db_usermode); - g_test_add_func("/test/secure_set_variable/DBX/usermode", - test_secure_set_dbx_usermode); - g_test_add_func("/test/secure_set_variable/DBT/usermode", - test_secure_set_dbt_usermode); + ADD_MULTI_TEST("/test/get_variable/no_name", + test_get_variable_no_name); + ADD_MULTI_TEST("/test/get_variable/long_name", + test_get_variable_long_name); + ADD_MULTI_TEST("/test/get_variable/not_found", + test_get_variable_not_found); + ADD_MULTI_TEST("/test/get_variable/found", + test_get_variable_found); + ADD_MULTI_TEST("/test/get_variable/too_small", + test_get_variable_too_small); + ADD_MULTI_TEST("/test/query_variable_info", + test_query_variable_info); + ADD_MULTI_TEST("/test/get_next_variable/empty", + test_get_next_variable_empty); + ADD_MULTI_TEST("/test/get_next_variable/long_name", + test_get_next_variable_long_name); + ADD_MULTI_TEST("/test/get_next_variable/only_runtime", + test_get_next_variable_only_runtime); + ADD_MULTI_TEST("/test/get_next_variable/too_small", + test_get_next_variable_too_small); + ADD_MULTI_TEST("/test/get_next_variable/no_match", + test_get_next_variable_no_match); + ADD_MULTI_TEST("/test/get_next_variable/all", + test_get_next_variable_all); + ADD_MULTI_TEST("/test/set_variable/attr", + test_set_variable_attr); + ADD_MULTI_TEST("/test/set_variable/set", + test_set_variable_set); + ADD_MULTI_TEST("/test/set_variable/update", + test_set_variable_update); + ADD_MULTI_TEST("/test/set_variable/append", + test_set_variable_append); + ADD_MULTI_TEST("/test/set_variable/delete", + test_set_variable_delete); + ADD_MULTI_TEST("/test/set_variable/resource_limit", + test_set_variable_resource_limit); + ADD_MULTI_TEST("/test/set_variable/many_vars", + test_set_variable_many_vars); + ADD_MULTI_TEST("/test/set_variable/non_volatile", + test_set_variable_non_volatile); + ADD_MULTI_TEST("/test/set_variable/special_vars", + test_set_variable_special_vars); + ADD_MULTI_TEST("/test/set_variable/mor", + test_set_variable_mor); + ADD_MULTI_TEST("/test/set_variable/mor_key", + test_set_variable_mor_key); + g_test_add_func("/test/set_variable/v2_downgrade", + test_set_variable_v2_downgrade); + g_test_add_func("/test/set_variable/v2_short_buffer", + test_set_variable_v2_short_buffer); + + ADD_MULTI_TEST("/test/secure_set_variable/use_bad_digest", + test_use_bad_digest); + ADD_MULTI_TEST("/test/secure_set_variable/setupmode", + test_secure_set_variable_setupmode); + ADD_MULTI_TEST("/test/secure_set_variable/PK", + test_secure_set_PK); + ADD_MULTI_TEST("/test/secure_set_variable/usermode", + test_secure_set_variable_usermode); + ADD_MULTI_TEST("/test/secure_set_variable/KEK/setupmode", + test_secure_set_KEK_setupmode); + ADD_MULTI_TEST("/test/secure_set_variable/KEK/usermode", + test_secure_set_KEK_usermode); + + ADD_MULTI_TEST("/test/secure_set_variable/DB/setupmode", + test_secure_set_db_setupmode); + ADD_MULTI_TEST("/test/secure_set_variable/DBX/setupmode", + test_secure_set_dbx_setupmode); + ADD_MULTI_TEST("/test/secure_set_variable/DBT/setupmode", + test_secure_set_dbt_setupmode); + + ADD_MULTI_TEST("/test/secure_set_variable/DB/usermode", + test_secure_set_db_usermode); + ADD_MULTI_TEST("/test/secure_set_variable/DBX/usermode", + test_secure_set_dbx_usermode); + ADD_MULTI_TEST("/test/secure_set_variable/DBT/usermode", + test_secure_set_dbt_usermode); r = g_test_run(); free_globals(); diff --git a/tools/tool-lib.c b/tools/tool-lib.c index 2d7eab5..765e007 100644 --- a/tools/tool-lib.c +++ b/tools/tool-lib.c @@ -39,6 +39,8 @@ #include "tool-lib.h" +uint8_t *cmd_buf = NULL; + /* * Prepare a command-line tool for running by initializing state and loading * the VM's variables from the backend. @@ -51,6 +53,10 @@ tool_init(void) secure_boot_enable = false; auth_enforce = false; + cmd_buf = calloc(SHMEM_PAGES_V2_MAX, PAGE_SIZE); + if (!cmd_buf) + return false; + if (!db->check_args()) return false; @@ -292,7 +298,6 @@ print_depriv_options(void) bool do_rm(const EFI_GUID *guid, const char *name) { - uint8_t buf[SHMEM_SIZE]; uint8_t *ptr; uint8_t variable_name[NAME_LIMIT]; EFI_STATUS status; @@ -301,17 +306,18 @@ do_rm(const EFI_GUID *guid, const char *name) name_size = parse_name(name, variable_name); - ptr = buf; - serialize_uint32(&ptr, 1); /* version */ + ptr = cmd_buf; + serialize_uint32(&ptr, 2); /* version */ + serialize_uint32(&ptr, SHMEM_PAGES_V2_MAX); /* nr_pages */ serialize_uint32(&ptr, COMMAND_GET_VARIABLE); serialize_data(&ptr, variable_name, name_size); serialize_guid(&ptr, guid); - serialize_uintn(&ptr, DATA_LIMIT); + serialize_uintn(&ptr, DATA_LIMIT_V2); *ptr = 0; - dispatch_command(buf); + dispatch_command(cmd_buf); - ptr = buf; + ptr = cmd_buf; status = unserialize_uintn(&ptr); if (status != EFI_SUCCESS) { print_efi_error(status); @@ -320,8 +326,9 @@ do_rm(const EFI_GUID *guid, const char *name) attr = unserialize_uint32(&ptr); - ptr = buf; - serialize_uint32(&ptr, 1); /* version */ + ptr = cmd_buf; + serialize_uint32(&ptr, 2); /* version */ + serialize_uint32(&ptr, SHMEM_PAGES_V2_MAX); /* nr_pages */ serialize_uint32(&ptr, COMMAND_SET_VARIABLE); serialize_data(&ptr, variable_name, name_size); serialize_guid(&ptr, guid); @@ -340,9 +347,9 @@ do_rm(const EFI_GUID *guid, const char *name) serialize_uint32(&ptr, attr); *ptr = 0; - dispatch_command(buf); + dispatch_command(cmd_buf); - ptr = buf; + ptr = cmd_buf; status = unserialize_uintn(&ptr); if (status != EFI_SUCCESS) { print_efi_error(status); diff --git a/tools/tool-lib.h b/tools/tool-lib.h index 46a86d8..ad605f4 100644 --- a/tools/tool-lib.h +++ b/tools/tool-lib.h @@ -75,6 +75,8 @@ } \ break; +extern uint8_t *cmd_buf; + bool tool_init(void); void print_efi_error(EFI_STATUS status); bool parse_guid(EFI_GUID *guid, const char *guid_str); diff --git a/tools/varstore-get.c b/tools/varstore-get.c index 366758a..0d113e1 100644 --- a/tools/varstore-get.c +++ b/tools/varstore-get.c @@ -61,7 +61,6 @@ usage(const char *progname) static bool do_get(const char *guid_str, const char *name, bool show_attr) { - uint8_t buf[SHMEM_SIZE]; uint8_t *ptr; uint8_t variable_name[NAME_LIMIT]; EFI_GUID guid; @@ -76,17 +75,18 @@ do_get(const char *guid_str, const char *name, bool show_attr) return false; } - ptr = buf; - serialize_uint32(&ptr, 1); /* version */ + ptr = cmd_buf; + serialize_uint32(&ptr, 2); /* version */ + serialize_uint32(&ptr, SHMEM_PAGES_V2_MAX); /* nr_pages */ serialize_uint32(&ptr, COMMAND_GET_VARIABLE); serialize_data(&ptr, variable_name, name_size); serialize_guid(&ptr, &guid); - serialize_uintn(&ptr, DATA_LIMIT); + serialize_uintn(&ptr, DATA_LIMIT_V2); *ptr = 0; - dispatch_command(buf); + dispatch_command(cmd_buf); - ptr = buf; + ptr = cmd_buf; status = unserialize_uintn(&ptr); if (status != EFI_SUCCESS) { print_efi_error(status); @@ -110,13 +110,13 @@ do_get(const char *guid_str, const char *name, bool show_attr) uint8_t *data; UINTN data_len; - data = unserialize_data(&ptr, &data_len, DATA_LIMIT); + data = unserialize_data(&ptr, &data_len, DATA_LIMIT_V2); if (!data) { if (data_len == 0) { /* The variable is empty - nothing to write out. */ return true; } else { - ERR("Data too large: %lu > %u\n", data_len, DATA_LIMIT); + ERR("Data too large: %lu > %u\n", data_len, DATA_LIMIT_V2); return false; } } diff --git a/tools/varstore-ls.c b/tools/varstore-ls.c index 8b28434..28f20c1 100644 --- a/tools/varstore-ls.c +++ b/tools/varstore-ls.c @@ -79,7 +79,6 @@ print_guid(const EFI_GUID *guid) static bool do_ls(void) { - uint8_t buf[SHMEM_SIZE]; uint8_t name[NAME_LIMIT] = {0}; uint8_t *ptr; EFI_GUID guid = {{0}}; @@ -88,17 +87,18 @@ do_ls(void) EFI_STATUS status; for (;;) { - ptr = buf; - serialize_uint32(&ptr, 1); /* version */ + ptr = cmd_buf; + serialize_uint32(&ptr, 2); /* version */ + serialize_uint32(&ptr, SHMEM_PAGES_V2_MAX); /* nr_pages */ serialize_uint32(&ptr, COMMAND_GET_NEXT_VARIABLE); serialize_uintn(&ptr, NAME_LIMIT); serialize_data(&ptr, name, size); serialize_guid(&ptr, &guid); *ptr = 0; - dispatch_command(buf); + dispatch_command(cmd_buf); - ptr = buf; + ptr = cmd_buf; status = unserialize_uintn(&ptr); if (status == EFI_NOT_FOUND) break; diff --git a/tools/varstore-set.c b/tools/varstore-set.c index 6185adb..c29c76c 100644 --- a/tools/varstore-set.c +++ b/tools/varstore-set.c @@ -65,7 +65,6 @@ static bool do_set(const char *guid_str, const char *name, const char *attr_str, const char *path) { - uint8_t buf[SHMEM_SIZE]; uint8_t *ptr, *data; uint8_t variable_name[NAME_LIMIT]; EFI_GUID guid; @@ -94,7 +93,7 @@ do_set(const char *guid_str, const char *name, const char *attr_str, ERR("Failed to open %s\n", path); return false; } - if (fstat(fileno(f), &st) == -1 || st.st_size > DATA_LIMIT) { + if (fstat(fileno(f), &st) == -1 || st.st_size > DATA_LIMIT_V2) { printf("Invalid file size\n"); fclose(f); return false; @@ -113,8 +112,9 @@ do_set(const char *guid_str, const char *name, const char *attr_str, } fclose(f); - ptr = buf; - serialize_uint32(&ptr, 1); /* version */ + ptr = cmd_buf; + serialize_uint32(&ptr, 2); /* version */ + serialize_uint32(&ptr, SHMEM_PAGES_V2_MAX); /* nr_pages */ serialize_uint32(&ptr, COMMAND_SET_VARIABLE); serialize_data(&ptr, variable_name, name_size); serialize_guid(&ptr, &guid); @@ -123,9 +123,9 @@ do_set(const char *guid_str, const char *name, const char *attr_str, serialize_uint32(&ptr, attr); *ptr = 0; - dispatch_command(buf); + dispatch_command(cmd_buf); - ptr = buf; + ptr = cmd_buf; status = unserialize_uintn(&ptr); if (status != EFI_SUCCESS) { print_efi_error(status); diff --git a/xapidb-lib.c b/xapidb-lib.c index 91e7e43..64e40ec 100644 --- a/xapidb-lib.c +++ b/xapidb-lib.c @@ -556,7 +556,7 @@ unserialize_variables(uint8_t **buf, size_t count, size_t rem) rem -= l->name_len; l->data = unserialize_data(buf, &l->data_len, - rem < DATA_LIMIT ? rem : DATA_LIMIT); + rem < DATA_LIMIT_MAX ? rem : DATA_LIMIT_MAX); if (!l->data) goto invalid; rem -= l->data_len;