From f2d2b3a11ce18663ea95c29eb2c609efd77b7999 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 22 Jun 2020 18:10:27 +0200 Subject: efi_loader: prepare for read only OP-TEE variables We currently have two implementations of UEFI variables: * variables provided via an OP-TEE module * variables stored in the U-Boot environment Read only variables are up to now only implemented in the U-Boot environment implementation. Provide a common interface for both implementations that allows handling read-only variables. As variable access is limited to very few source files put variable related definitions into new include efi_variable.h instead of efi_loader. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 175 ++++++++++++------------------------------ 1 file changed, 48 insertions(+), 127 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index efaba869ef2..6ec1f973269 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,6 @@ #include #include #include -#include #include #include @@ -30,21 +30,6 @@ static bool efi_secure_boot; static enum efi_secure_mode efi_secure_mode; static u8 efi_vendor_keys; -#define READ_ONLY BIT(31) - -static efi_status_t efi_get_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 *attributes, - efi_uintn_t *data_size, void *data, - u64 *timep); - -static efi_status_t efi_set_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 attributes, - efi_uintn_t data_size, - const void *data, - bool ro_check); - /* * Mapping between EFI variables and u-boot variables: * @@ -155,7 +140,7 @@ static const char *parse_attr(const char *str, u32 *attrp, u64 *timep) str++; if ((s = prefix(str, "ro"))) { - attr |= READ_ONLY; + attr |= EFI_VARIABLE_READ_ONLY; } else if ((s = prefix(str, "nv"))) { attr |= EFI_VARIABLE_NON_VOLATILE; } else if ((s = prefix(str, "boot"))) { @@ -203,29 +188,29 @@ static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode, attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | - READ_ONLY; - ret = efi_set_variable_common(L"SecureBoot", &efi_global_variable_guid, - attributes, sizeof(secure_boot), - &secure_boot, false); + EFI_VARIABLE_READ_ONLY; + ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid, + attributes, sizeof(secure_boot), + &secure_boot, false); if (ret != EFI_SUCCESS) goto err; - ret = efi_set_variable_common(L"SetupMode", &efi_global_variable_guid, - attributes, sizeof(setup_mode), - &setup_mode, false); + ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid, + attributes, sizeof(setup_mode), + &setup_mode, false); if (ret != EFI_SUCCESS) goto err; - ret = efi_set_variable_common(L"AuditMode", &efi_global_variable_guid, - attributes, sizeof(audit_mode), - &audit_mode, false); + ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid, + attributes, sizeof(audit_mode), + &audit_mode, false); if (ret != EFI_SUCCESS) goto err; - ret = efi_set_variable_common(L"DeployedMode", - &efi_global_variable_guid, attributes, - sizeof(deployed_mode), &deployed_mode, - false); + ret = efi_set_variable_int(L"DeployedMode", + &efi_global_variable_guid, attributes, + sizeof(deployed_mode), &deployed_mode, + false); err: return ret; } @@ -235,7 +220,7 @@ err: * @mode: new state * * Depending on @mode, secure boot related variables are updated. - * Those variables are *read-only* for users, efi_set_variable_common() + * Those variables are *read-only* for users, efi_set_variable_int() * is called here. * * Return: status code @@ -254,10 +239,10 @@ static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) efi_secure_boot = true; } else if (mode == EFI_MODE_AUDIT) { - ret = efi_set_variable_common(L"PK", &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 0, NULL, false); + ret = efi_set_variable_int(L"PK", &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 0, NULL, false); if (ret != EFI_SUCCESS) goto err; @@ -309,8 +294,8 @@ static efi_status_t efi_init_secure_state(void) */ size = 0; - ret = efi_get_variable_common(L"PK", &efi_global_variable_guid, - NULL, &size, NULL, NULL); + ret = efi_get_variable_int(L"PK", &efi_global_variable_guid, + NULL, &size, NULL, NULL); if (ret == EFI_BUFFER_TOO_SMALL) { if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) mode = EFI_MODE_USER; @@ -327,13 +312,13 @@ static efi_status_t efi_init_secure_state(void) ret = efi_transfer_secure_state(mode); if (ret == EFI_SUCCESS) - ret = efi_set_variable_common(L"VendorKeys", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - READ_ONLY, - sizeof(efi_vendor_keys), - &efi_vendor_keys, false); + ret = efi_set_variable_int(L"VendorKeys", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(efi_vendor_keys), + &efi_vendor_keys, false); err: return ret; @@ -599,11 +584,9 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } #endif /* CONFIG_EFI_SECURE_BOOT */ -static efi_status_t efi_get_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 *attributes, - efi_uintn_t *data_size, void *data, - u64 *timep) +efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 *attributes, efi_uintn_t *data_size, + void *data, u64 *timep) { char *native_name; efi_status_t ret; @@ -684,40 +667,11 @@ static efi_status_t efi_get_variable_common(u16 *variable_name, out: if (attributes) - *attributes = attr & EFI_VARIABLE_MASK; + *attributes = attr; return ret; } -/** - * efi_efi_get_variable() - retrieve value of a UEFI variable - * - * This function implements the GetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @variable_name: name of the variable - * @vendor: vendor GUID - * @attributes: attributes of the variable - * @data_size: size of the buffer to which the variable value is copied - * @data: buffer to which the variable value is copied - * Return: status code - */ -efi_status_t EFIAPI efi_get_variable(u16 *variable_name, - const efi_guid_t *vendor, u32 *attributes, - efi_uintn_t *data_size, void *data) -{ - efi_status_t ret; - - EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes, - data_size, data); - - ret = efi_get_variable_common(variable_name, vendor, attributes, - data_size, data, NULL); - return EFI_EXIT(ret); -} - static char *efi_variables_list; static char *efi_cur_variable; @@ -881,12 +835,9 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, return EFI_EXIT(ret); } -static efi_status_t efi_set_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 attributes, - efi_uintn_t data_size, - const void *data, - bool ro_check) +efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, + const void *data, bool ro_check) { char *native_name = NULL, *old_data = NULL, *val = NULL, *s; efi_uintn_t old_size; @@ -909,15 +860,15 @@ static efi_status_t efi_set_variable_common(u16 *variable_name, /* check if a variable exists */ old_size = 0; attr = 0; - ret = efi_get_variable_common(variable_name, vendor, &attr, - &old_size, NULL, &time); + ret = efi_get_variable_int(variable_name, vendor, &attr, + &old_size, NULL, &time); append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE; delete = !append && (!data_size || !attributes); /* check attributes */ if (old_size) { - if (ro_check && (attr & READ_ONLY)) { + if (ro_check && (attr & EFI_VARIABLE_READ_ONLY)) { ret = EFI_WRITE_PROTECTED; goto err; } @@ -925,8 +876,8 @@ static efi_status_t efi_set_variable_common(u16 *variable_name, /* attributes won't be changed */ if (!delete && ((ro_check && attr != attributes) || - (!ro_check && ((attr & ~(u32)READ_ONLY) - != (attributes & ~(u32)READ_ONLY))))) { + (!ro_check && ((attr & ~(u32)EFI_VARIABLE_READ_ONLY) + != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) { ret = EFI_INVALID_PARAMETER; goto err; } @@ -1000,8 +951,8 @@ static efi_status_t efi_set_variable_common(u16 *variable_name, ret = EFI_OUT_OF_RESOURCES; goto err; } - ret = efi_get_variable_common(variable_name, vendor, - &attr, &old_size, old_data, NULL); + ret = efi_get_variable_int(variable_name, vendor, + &attr, &old_size, old_data, NULL); if (ret != EFI_SUCCESS) goto err; } else { @@ -1021,7 +972,7 @@ static efi_status_t efi_set_variable_common(u16 *variable_name, /* * store attributes */ - attributes &= (READ_ONLY | + attributes &= (EFI_VARIABLE_READ_ONLY | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | @@ -1030,7 +981,7 @@ static efi_status_t efi_set_variable_common(u16 *variable_name, while (attributes) { attr = 1 << (ffs(attributes) - 1); - if (attr == READ_ONLY) { + if (attr == EFI_VARIABLE_READ_ONLY) { s += sprintf(s, "ro"); } else if (attr == EFI_VARIABLE_NON_VOLATILE) { s += sprintf(s, "nv"); @@ -1084,12 +1035,12 @@ out: /* update VendorKeys */ if (vendor_keys_modified & efi_vendor_keys) { efi_vendor_keys = 0; - ret = efi_set_variable_common( + ret = efi_set_variable_int( L"VendorKeys", &efi_global_variable_guid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS - | READ_ONLY, + | EFI_VARIABLE_READ_ONLY, sizeof(efi_vendor_keys), &efi_vendor_keys, false); @@ -1106,36 +1057,6 @@ err: return ret; } -/** - * efi_set_variable() - set value of a UEFI variable - * - * This function implements the SetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @variable_name: name of the variable - * @vendor: vendor GUID - * @attributes: attributes of the variable - * @data_size: size of the buffer with the variable value - * @data: buffer with the variable value - * Return: status code - */ -efi_status_t EFIAPI efi_set_variable(u16 *variable_name, - const efi_guid_t *vendor, u32 attributes, - efi_uintn_t data_size, const void *data) -{ - EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes, - data_size, data); - - /* READ_ONLY bit is not part of API */ - attributes &= ~(u32)READ_ONLY; - - return EFI_EXIT(efi_set_variable_common(variable_name, vendor, - attributes, data_size, data, - true)); -} - /** * efi_query_variable_info() - get information about EFI variables * -- cgit v1.2.3 From 01df8cf33634a36566281af475cc520c3febad4d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 26 Jun 2020 17:57:48 +0200 Subject: efi_loader: separate UEFI variable API from implemementation Separate the remaining UEFI variable API functions GetNextVariableName and QueryVariableInfo() from internal functions implementing them. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 56 ++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 6ec1f973269..36bac867027 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -745,23 +745,9 @@ static efi_status_t parse_uboot_variable(char *variable, return EFI_SUCCESS; } -/** - * efi_get_next_variable_name() - enumerate the current variable names - * - * @variable_name_size: size of variable_name buffer in byte - * @variable_name: name of uefi variable's name in u16 - * @vendor: vendor's guid - * - * This function implements the GetNextVariableName service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, - u16 *variable_name, - efi_guid_t *vendor) +efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, + u16 *variable_name, + efi_guid_t *vendor) { char *native_name, *variable; ssize_t name_len, list_len; @@ -771,10 +757,8 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, int i; efi_status_t ret; - EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor); - if (!variable_name_size || !variable_name || !vendor) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; if (variable_name[0]) { /* check null-terminated string */ @@ -782,12 +766,12 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, if (!variable_name[i]) break; if (i >= *variable_name_size) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; /* search for the last-returned variable */ ret = efi_to_native(&native_name, variable_name, vendor); if (ret) - return EFI_EXIT(ret); + return ret; name_len = strlen(native_name); for (variable = efi_variables_list; variable && *variable;) { @@ -802,14 +786,14 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, free(native_name); if (!(variable && *variable)) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; /* next variable */ variable = strchr(variable, '\n'); if (variable) variable++; if (!(variable && *variable)) - return EFI_EXIT(EFI_NOT_FOUND); + return EFI_NOT_FOUND; } else { /* *new search: free a list used in the previous search @@ -824,7 +808,7 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, &efi_variables_list, 0, 1, regexlist); if (list_len <= 1) - return EFI_EXIT(EFI_NOT_FOUND); + return EFI_NOT_FOUND; variable = efi_variables_list; } @@ -832,7 +816,7 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, ret = parse_uboot_variable(variable, variable_name_size, variable_name, vendor, &attributes); - return EFI_EXIT(ret); + return ret; } efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, @@ -1057,13 +1041,17 @@ err: return ret; } +efi_status_t efi_query_variable_info_int(u32 attributes, + u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size) +{ + return EFI_UNSUPPORTED; +} + /** - * efi_query_variable_info() - get information about EFI variables - * - * This function implements the QueryVariableInfo() runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. + * efi_query_variable_info_runtime() - runtime implementation of + * QueryVariableInfo() * * @attributes: bitmask to select variables to be * queried @@ -1075,7 +1063,7 @@ err: * selected type * Returns: status code */ -efi_status_t __efi_runtime EFIAPI efi_query_variable_info( +efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime( u32 attributes, u64 *maximum_variable_storage_size, u64 *remaining_variable_storage_size, @@ -1144,6 +1132,8 @@ void efi_variables_boot_exit_notify(void) efi_runtime_services.get_next_variable_name = efi_get_next_variable_name_runtime; efi_runtime_services.set_variable = efi_set_variable_runtime; + efi_runtime_services.query_variable_info = + efi_query_variable_info_runtime; efi_update_table_header_crc32(&efi_runtime_services.hdr); } -- cgit v1.2.3 From 37fa7cb045cc15b3a22377fa2e3fb00b2d132d7a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 17 Jun 2020 12:20:46 +0200 Subject: efi_loader: keep attributes in efi_set_variable_int Do not change the value of parameter attributes in function efi_set_variable_int(). This allows to use it later. Do not use variable attr for different purposes but declare separate variables (attr and old_attr). Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 36bac867027..c9980ca6929 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -827,7 +827,7 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, efi_uintn_t old_size; bool append, delete; u64 time = 0; - u32 attr; + u32 old_attr; efi_status_t ret = EFI_SUCCESS; if (!variable_name || !*variable_name || !vendor || @@ -843,8 +843,8 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, /* check if a variable exists */ old_size = 0; - attr = 0; - ret = efi_get_variable_int(variable_name, vendor, &attr, + old_attr = 0; + ret = efi_get_variable_int(variable_name, vendor, &old_attr, &old_size, NULL, &time); append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE; @@ -852,15 +852,15 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, /* check attributes */ if (old_size) { - if (ro_check && (attr & EFI_VARIABLE_READ_ONLY)) { + if (ro_check && (old_attr & EFI_VARIABLE_READ_ONLY)) { ret = EFI_WRITE_PROTECTED; goto err; } /* attributes won't be changed */ if (!delete && - ((ro_check && attr != attributes) || - (!ro_check && ((attr & ~(u32)EFI_VARIABLE_READ_ONLY) + ((ro_check && old_attr != attributes) || + (!ro_check && ((old_attr & ~(u32)EFI_VARIABLE_READ_ONLY) != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) { ret = EFI_INVALID_PARAMETER; goto err; @@ -902,7 +902,7 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { ret = efi_variable_authenticate(variable_name, vendor, &data_size, &data, - attributes, &attr, + attributes, &old_attr, &time); if (ret != EFI_SUCCESS) goto err; @@ -936,7 +936,7 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, goto err; } ret = efi_get_variable_int(variable_name, vendor, - &attr, &old_size, old_data, NULL); + &old_attr, &old_size, old_data, NULL); if (ret != EFI_SUCCESS) goto err; } else { @@ -962,8 +962,8 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS); s += sprintf(s, "{"); - while (attributes) { - attr = 1 << (ffs(attributes) - 1); + for (u32 attr_rem = attributes; attr_rem;) { + u32 attr = 1 << (ffs(attr_rem) - 1); if (attr == EFI_VARIABLE_READ_ONLY) { s += sprintf(s, "ro"); @@ -979,8 +979,8 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, s = bin2hex(s, (u8 *)&time, sizeof(time)); } - attributes &= ~attr; - if (attributes) + attr_rem &= ~attr; + if (attr_rem) s += sprintf(s, ","); } s += sprintf(s, "}"); -- cgit v1.2.3 From fd7b6730aba4540fef8d59cfe10a7dce2649cd8e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 4 Jul 2020 22:41:26 +0200 Subject: efi_loader: value of VendorKeys According to the UEFI specification the variable VendorKeys is 1 if the "system is configured to use only vendor-provided keys". As we do not supply any vendor keys yet the variable VendorKeys must be zero. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 75 +++++++++---------------------------------- 1 file changed, 15 insertions(+), 60 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index c9980ca6929..2f8005bd951 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -282,45 +282,29 @@ err: */ static efi_status_t efi_init_secure_state(void) { - enum efi_secure_mode mode; - efi_uintn_t size; + enum efi_secure_mode mode = EFI_MODE_SETUP; + efi_uintn_t size = 0; efi_status_t ret; - /* - * TODO: - * Since there is currently no "platform-specific" installation - * method of Platform Key, we can't say if VendorKeys is 0 or 1 - * precisely. - */ - - size = 0; ret = efi_get_variable_int(L"PK", &efi_global_variable_guid, NULL, &size, NULL, NULL); if (ret == EFI_BUFFER_TOO_SMALL) { if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) mode = EFI_MODE_USER; - else - mode = EFI_MODE_SETUP; - - efi_vendor_keys = 0; - } else if (ret == EFI_NOT_FOUND) { - mode = EFI_MODE_SETUP; - efi_vendor_keys = 1; - } else { - goto err; } ret = efi_transfer_secure_state(mode); - if (ret == EFI_SUCCESS) - ret = efi_set_variable_int(L"VendorKeys", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - EFI_VARIABLE_READ_ONLY, - sizeof(efi_vendor_keys), - &efi_vendor_keys, false); + if (ret != EFI_SUCCESS) + return ret; -err: + /* As we do not provide vendor keys this variable is always 0. */ + ret = efi_set_variable_int(L"VendorKeys", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(efi_vendor_keys), + &efi_vendor_keys, false); return ret; } @@ -998,39 +982,10 @@ out: if (env_set(native_name, val)) { ret = EFI_DEVICE_ERROR; } else { - bool vendor_keys_modified = false; - - if ((u16_strcmp(variable_name, L"PK") == 0 && - guidcmp(vendor, &efi_global_variable_guid) == 0)) { - ret = efi_transfer_secure_state( - (delete ? EFI_MODE_SETUP : - EFI_MODE_USER)); - if (ret != EFI_SUCCESS) - goto err; - - if (efi_secure_mode != EFI_MODE_SETUP) - vendor_keys_modified = true; - } else if ((u16_strcmp(variable_name, L"KEK") == 0 && - guidcmp(vendor, &efi_global_variable_guid) == 0)) { - if (efi_secure_mode != EFI_MODE_SETUP) - vendor_keys_modified = true; - } - - /* update VendorKeys */ - if (vendor_keys_modified & efi_vendor_keys) { - efi_vendor_keys = 0; - ret = efi_set_variable_int( - L"VendorKeys", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_READ_ONLY, - sizeof(efi_vendor_keys), - &efi_vendor_keys, - false); - } else { + if (!u16_strcmp(variable_name, L"PK")) + ret = efi_init_secure_state(); + else ret = EFI_SUCCESS; - } } err: -- cgit v1.2.3 From 55a830560efafd8ae5a61a2beaaece6701e077c6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 4 Jul 2020 18:34:15 +0200 Subject: efi_loader: read-only AuditMode and DeployedMode Set the read only property of the UEFI variables AuditMode and DeployedMode conforming to the UEFI specification. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 2f8005bd951..4bd976e44a6 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -183,32 +183,36 @@ static const char *parse_attr(const char *str, u32 *attrp, u64 *timep) static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode, u8 audit_mode, u8 deployed_mode) { - u32 attributes; efi_status_t ret; + const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY; + const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; - attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - EFI_VARIABLE_READ_ONLY; ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid, - attributes, sizeof(secure_boot), + attributes_ro, sizeof(secure_boot), &secure_boot, false); if (ret != EFI_SUCCESS) goto err; ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid, - attributes, sizeof(setup_mode), + attributes_ro, sizeof(setup_mode), &setup_mode, false); if (ret != EFI_SUCCESS) goto err; ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid, - attributes, sizeof(audit_mode), - &audit_mode, false); + audit_mode || setup_mode ? + attributes_ro : attributes_rw, + sizeof(audit_mode), &audit_mode, false); if (ret != EFI_SUCCESS) goto err; ret = efi_set_variable_int(L"DeployedMode", - &efi_global_variable_guid, attributes, + &efi_global_variable_guid, + audit_mode || deployed_mode || setup_mode ? + attributes_ro : attributes_rw, sizeof(deployed_mode), &deployed_mode, false); err: -- cgit v1.2.3 From 198bf6418efa282ddb9392d352a2afef20585020 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 5 Jul 2020 02:29:50 +0200 Subject: efi_loader: secure boot flag In audit mode the UEFI variable SecureBoot is set to zero but the efi_secure_boot flag is set to true. The efi_secure_boot flag should match the UEFIvariable SecureBoot. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 4bd976e44a6..0d6bafc76d3 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -190,6 +190,8 @@ static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode, const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; + efi_secure_boot = secure_boot; + ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid, attributes_ro, sizeof(secure_boot), &secure_boot, false); @@ -240,8 +242,6 @@ static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) ret = efi_set_secure_state(1, 0, 0, 1); if (ret != EFI_SUCCESS) goto err; - - efi_secure_boot = true; } else if (mode == EFI_MODE_AUDIT) { ret = efi_set_variable_int(L"PK", &efi_global_variable_guid, EFI_VARIABLE_BOOTSERVICE_ACCESS | @@ -253,14 +253,10 @@ static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) ret = efi_set_secure_state(0, 1, 1, 0); if (ret != EFI_SUCCESS) goto err; - - efi_secure_boot = true; } else if (mode == EFI_MODE_USER) { ret = efi_set_secure_state(1, 0, 0, 0); if (ret != EFI_SUCCESS) goto err; - - efi_secure_boot = true; } else if (mode == EFI_MODE_SETUP) { ret = efi_set_secure_state(0, 1, 0, 0); if (ret != EFI_SUCCESS) -- cgit v1.2.3 From 5f7dcf079de8caa5ef9c332c928bd6a3c3d12335 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 19 Mar 2020 18:21:58 +0000 Subject: efi_loader: UEFI variable persistence Persist non-volatile UEFI variables in a file on the EFI system partition. The file is written whenever a non-volatile UEFI variable is changed after initialization of the UEFI sub-system. The file is read during the UEFI sub-system initialization to restore non-volatile UEFI variables. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 0d6bafc76d3..8ed4b0830ba 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -988,6 +988,11 @@ out: ret = EFI_SUCCESS; } + /* Write non-volatile EFI variables to file */ + if (attributes & EFI_VARIABLE_NON_VOLATILE && + ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS) + efi_var_to_file(); + err: free(native_name); free(old_data); @@ -1083,6 +1088,7 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, */ void efi_variables_boot_exit_notify(void) { + /* Switch variable services functions to runtime version */ efi_runtime_services.get_variable = efi_get_variable_runtime; efi_runtime_services.get_next_variable_name = efi_get_next_variable_name_runtime; @@ -1102,6 +1108,8 @@ efi_status_t efi_init_variables(void) efi_status_t ret; ret = efi_init_secure_state(); + if (ret != EFI_SUCCESS) + return ret; - return ret; + return efi_var_from_file(); } -- cgit v1.2.3 From ab7296c99c273736801f9480cd21fbe862671987 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 4 Jul 2020 18:34:15 +0200 Subject: efi_loader: use memory based variable storage Saving UEFI variable as encoded U-Boot environment variables does not allow implement run-time support. Use a memory buffer for storing UEFI variables. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 562 +++++++----------------------------------- 1 file changed, 94 insertions(+), 468 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 8ed4b0830ba..bbdc071126b 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -30,145 +30,6 @@ static bool efi_secure_boot; static enum efi_secure_mode efi_secure_mode; static u8 efi_vendor_keys; -/* - * Mapping between EFI variables and u-boot variables: - * - * efi_$guid_$varname = {attributes}(type)value - * - * For example: - * - * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported= - * "{ro,boot,run}(blob)0000000000000000" - * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder= - * "(blob)00010000" - * - * The attributes are a comma separated list of these possible - * attributes: - * - * + ro - read-only - * + boot - boot-services access - * + run - runtime access - * - * NOTE: with current implementation, no variables are available after - * ExitBootServices, and all are persisted (if possible). - * - * If not specified, the attributes default to "{boot}". - * - * The required type is one of: - * - * + utf8 - raw utf8 string - * + blob - arbitrary length hex string - * - * Maybe a utf16 type would be useful to for a string value to be auto - * converted to utf16? - */ - -#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_")) - -/** - * efi_to_native() - convert the UEFI variable name and vendor GUID to U-Boot - * variable name - * - * The U-Boot variable name is a concatenation of prefix 'efi', the hexstring - * encoded vendor GUID, and the UTF-8 encoded UEFI variable name separated by - * underscores, e.g. 'efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder'. - * - * @native: pointer to pointer to U-Boot variable name - * @variable_name: UEFI variable name - * @vendor: vendor GUID - * Return: status code - */ -static efi_status_t efi_to_native(char **native, const u16 *variable_name, - const efi_guid_t *vendor) -{ - size_t len; - char *pos; - - len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1; - *native = malloc(len); - if (!*native) - return EFI_OUT_OF_RESOURCES; - - pos = *native; - pos += sprintf(pos, "efi_%pUl_", vendor); - utf16_utf8_strcpy(&pos, variable_name); - - return EFI_SUCCESS; -} - -/** - * prefix() - skip over prefix - * - * Skip over a prefix string. - * - * @str: string with prefix - * @prefix: prefix string - * Return: string without prefix, or NULL if prefix not found - */ -static const char *prefix(const char *str, const char *prefix) -{ - size_t n = strlen(prefix); - if (!strncmp(prefix, str, n)) - return str + n; - return NULL; -} - -/** - * parse_attr() - decode attributes part of variable value - * - * Convert the string encoded attributes of a UEFI variable to a bit mask. - * TODO: Several attributes are not supported. - * - * @str: value of U-Boot variable - * @attrp: pointer to UEFI attributes - * @timep: pointer to time attribute - * Return: pointer to remainder of U-Boot variable value - */ -static const char *parse_attr(const char *str, u32 *attrp, u64 *timep) -{ - u32 attr = 0; - char sep = '{'; - - if (*str != '{') { - *attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS; - return str; - } - - while (*str == sep) { - const char *s; - - str++; - - if ((s = prefix(str, "ro"))) { - attr |= EFI_VARIABLE_READ_ONLY; - } else if ((s = prefix(str, "nv"))) { - attr |= EFI_VARIABLE_NON_VOLATILE; - } else if ((s = prefix(str, "boot"))) { - attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; - } else if ((s = prefix(str, "run"))) { - attr |= EFI_VARIABLE_RUNTIME_ACCESS; - } else if ((s = prefix(str, "time="))) { - attr |= EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; - hex2bin((u8 *)timep, s, sizeof(*timep)); - s += sizeof(*timep) * 2; - } else if (*str == '}') { - break; - } else { - printf("invalid attribute: %s\n", str); - break; - } - - str = s; - sep = ','; - } - - str++; - - *attrp = attr; - - return str; -} - /** * efi_set_secure_state - modify secure boot state variables * @secure_boot: value of SecureBoot @@ -568,296 +429,115 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } #endif /* CONFIG_EFI_SECURE_BOOT */ -efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor, - u32 *attributes, efi_uintn_t *data_size, - void *data, u64 *timep) +efi_status_t __efi_runtime +efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 *attributes, efi_uintn_t *data_size, void *data, + u64 *timep) { - char *native_name; - efi_status_t ret; - unsigned long in_size; - const char *val = NULL, *s; - u64 time = 0; - u32 attr; + efi_uintn_t old_size; + struct efi_var_entry *var; + u16 *pdata; if (!variable_name || !vendor || !data_size) return EFI_INVALID_PARAMETER; - - ret = efi_to_native(&native_name, variable_name, vendor); - if (ret) - return ret; - - EFI_PRINT("get '%s'\n", native_name); - - val = env_get(native_name); - free(native_name); - if (!val) + var = efi_var_mem_find(vendor, variable_name, NULL); + if (!var) return EFI_NOT_FOUND; - val = parse_attr(val, &attr, &time); - - if (timep) - *timep = time; - - in_size = *data_size; - - if ((s = prefix(val, "(blob)"))) { - size_t len = strlen(s); - - /* number of hexadecimal digits must be even */ - if (len & 1) - return EFI_DEVICE_ERROR; - - /* two characters per byte: */ - len /= 2; - *data_size = len; - - if (in_size < len) { - ret = EFI_BUFFER_TOO_SMALL; - goto out; - } - - if (!data) { - EFI_PRINT("Variable with no data shouldn't exist.\n"); - return EFI_INVALID_PARAMETER; - } - - if (hex2bin(data, s, len)) - return EFI_DEVICE_ERROR; - - EFI_PRINT("got value: \"%s\"\n", s); - } else if ((s = prefix(val, "(utf8)"))) { - unsigned len = strlen(s) + 1; - - *data_size = len; - - if (in_size < len) { - ret = EFI_BUFFER_TOO_SMALL; - goto out; - } - - if (!data) { - EFI_PRINT("Variable with no data shouldn't exist.\n"); - return EFI_INVALID_PARAMETER; - } - - memcpy(data, s, len); - ((char *)data)[len] = '\0'; - - EFI_PRINT("got value: \"%s\"\n", (char *)data); - } else { - EFI_PRINT("invalid value: '%s'\n", val); - return EFI_DEVICE_ERROR; - } - -out: if (attributes) - *attributes = attr; - - return ret; -} - -static char *efi_variables_list; -static char *efi_cur_variable; - -/** - * parse_uboot_variable() - parse a u-boot variable and get uefi-related - * information - * @variable: whole data of u-boot variable (ie. name=value) - * @variable_name_size: size of variable_name buffer in byte - * @variable_name: name of uefi variable in u16, null-terminated - * @vendor: vendor's guid - * @attributes: attributes - * - * A uefi variable is encoded into a u-boot variable as described above. - * This function parses such a u-boot variable and retrieve uefi-related - * information into respective parameters. In return, variable_name_size - * is the size of variable name including NULL. - * - * Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when - * the entire variable list has been returned, - * otherwise non-zero status code - */ -static efi_status_t parse_uboot_variable(char *variable, - efi_uintn_t *variable_name_size, - u16 *variable_name, - const efi_guid_t *vendor, - u32 *attributes) -{ - char *guid, *name, *end, c; - size_t name_len; - efi_uintn_t old_variable_name_size; - u64 time; - u16 *p; - - guid = strchr(variable, '_'); - if (!guid) - return EFI_INVALID_PARAMETER; - guid++; - name = strchr(guid, '_'); - if (!name) - return EFI_INVALID_PARAMETER; - name++; - end = strchr(name, '='); - if (!end) - return EFI_INVALID_PARAMETER; + *attributes = var->attr; + if (timep) + *timep = var->time; - name_len = end - name; - old_variable_name_size = *variable_name_size; - *variable_name_size = sizeof(u16) * (name_len + 1); - if (old_variable_name_size < *variable_name_size) + old_size = *data_size; + *data_size = var->length; + if (old_size < var->length) return EFI_BUFFER_TOO_SMALL; - end++; /* point to value */ - - /* variable name */ - p = variable_name; - utf8_utf16_strncpy(&p, name, name_len); - variable_name[name_len] = 0; - - /* guid */ - c = *(name - 1); - *(name - 1) = '\0'; /* guid need be null-terminated here */ - if (uuid_str_to_bin(guid, (unsigned char *)vendor, - UUID_STR_FORMAT_GUID)) - /* The only error would be EINVAL. */ + if (!data) return EFI_INVALID_PARAMETER; - *(name - 1) = c; - /* attributes */ - parse_attr(end, attributes, &time); + for (pdata = var->name; *pdata; ++pdata) + ; + ++pdata; + + efi_memcpy_runtime(data, pdata, var->length); return EFI_SUCCESS; } -efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, - u16 *variable_name, - efi_guid_t *vendor) +efi_status_t __efi_runtime +efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, + u16 *variable_name, efi_guid_t *vendor) { - char *native_name, *variable; - ssize_t name_len, list_len; - char regex[256]; - char * const regexlist[] = {regex}; - u32 attributes; - int i; - efi_status_t ret; + struct efi_var_entry *var; + efi_uintn_t old_size; + u16 *pdata; if (!variable_name_size || !variable_name || !vendor) return EFI_INVALID_PARAMETER; - if (variable_name[0]) { - /* check null-terminated string */ - for (i = 0; i < *variable_name_size; i++) - if (!variable_name[i]) - break; - if (i >= *variable_name_size) - return EFI_INVALID_PARAMETER; + efi_var_mem_find(vendor, variable_name, &var); - /* search for the last-returned variable */ - ret = efi_to_native(&native_name, variable_name, vendor); - if (ret) - return ret; + if (!var) + return EFI_NOT_FOUND; - name_len = strlen(native_name); - for (variable = efi_variables_list; variable && *variable;) { - if (!strncmp(variable, native_name, name_len) && - variable[name_len] == '=') - break; + for (pdata = var->name; *pdata; ++pdata) + ; + ++pdata; - variable = strchr(variable, '\n'); - if (variable) - variable++; - } - - free(native_name); - if (!(variable && *variable)) - return EFI_INVALID_PARAMETER; + old_size = *variable_name_size; + *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name; - /* next variable */ - variable = strchr(variable, '\n'); - if (variable) - variable++; - if (!(variable && *variable)) - return EFI_NOT_FOUND; - } else { - /* - *new search: free a list used in the previous search - */ - free(efi_variables_list); - efi_variables_list = NULL; - efi_cur_variable = NULL; - - snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*"); - list_len = hexport_r(&env_htab, '\n', - H_MATCH_REGEX | H_MATCH_KEY, - &efi_variables_list, 0, 1, regexlist); - - if (list_len <= 1) - return EFI_NOT_FOUND; - - variable = efi_variables_list; - } + if (old_size < *variable_name_size) + return EFI_BUFFER_TOO_SMALL; - ret = parse_uboot_variable(variable, variable_name_size, variable_name, - vendor, &attributes); + efi_memcpy_runtime(variable_name, var->name, *variable_name_size); + efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t)); - return ret; + return EFI_SUCCESS; } efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, u32 attributes, efi_uintn_t data_size, const void *data, bool ro_check) { - char *native_name = NULL, *old_data = NULL, *val = NULL, *s; - efi_uintn_t old_size; + struct efi_var_entry *var; + efi_uintn_t ret; bool append, delete; u64 time = 0; - u32 old_attr; - efi_status_t ret = EFI_SUCCESS; if (!variable_name || !*variable_name || !vendor || ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) && - !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) { - ret = EFI_INVALID_PARAMETER; - goto err; - } - - ret = efi_to_native(&native_name, variable_name, vendor); - if (ret) - goto err; + !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) + return EFI_INVALID_PARAMETER; /* check if a variable exists */ - old_size = 0; - old_attr = 0; - ret = efi_get_variable_int(variable_name, vendor, &old_attr, - &old_size, NULL, &time); + var = efi_var_mem_find(vendor, variable_name, NULL); append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE; delete = !append && (!data_size || !attributes); /* check attributes */ - if (old_size) { - if (ro_check && (old_attr & EFI_VARIABLE_READ_ONLY)) { - ret = EFI_WRITE_PROTECTED; - goto err; - } + if (var) { + if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY)) + return EFI_WRITE_PROTECTED; /* attributes won't be changed */ if (!delete && - ((ro_check && old_attr != attributes) || - (!ro_check && ((old_attr & ~(u32)EFI_VARIABLE_READ_ONLY) + ((ro_check && var->attr != attributes) || + (!ro_check && ((var->attr & ~(u32)EFI_VARIABLE_READ_ONLY) != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) { - ret = EFI_INVALID_PARAMETER; - goto err; + return EFI_INVALID_PARAMETER; } + time = var->time; } else { - if (delete || append) { + if (delete || append) /* * Trying to delete or to update a non-existent * variable. */ - ret = EFI_NOT_FOUND; - goto err; - } + return EFI_NOT_FOUND; } if (((!u16_strcmp(variable_name, L"PK") || @@ -869,27 +549,26 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, /* authentication is mandatory */ if (!(attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { - EFI_PRINT("%ls: AUTHENTICATED_WRITE_ACCESS required\n", + EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n", variable_name); - ret = EFI_INVALID_PARAMETER; - goto err; + return EFI_INVALID_PARAMETER; } } /* authenticate a variable */ if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) { - if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { - ret = EFI_INVALID_PARAMETER; - goto err; - } + if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) + return EFI_INVALID_PARAMETER; if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { + u32 env_attr; + ret = efi_variable_authenticate(variable_name, vendor, &data_size, &data, - attributes, &old_attr, + attributes, &env_attr, &time); if (ret != EFI_SUCCESS) - goto err; + return ret; /* last chance to check for delete */ if (!data_size) @@ -900,105 +579,42 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { EFI_PRINT("Secure boot is not configured\n"); - ret = EFI_INVALID_PARAMETER; - goto err; + return EFI_INVALID_PARAMETER; } } - /* delete a variable */ if (delete) { - /* !old_size case has been handled before */ - val = NULL; + /* EFI_NOT_FOUND has been handled before */ ret = EFI_SUCCESS; - goto out; - } - - if (append) { - old_data = malloc(old_size); - if (!old_data) { - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - ret = efi_get_variable_int(variable_name, vendor, - &old_attr, &old_size, old_data, NULL); - if (ret != EFI_SUCCESS) - goto err; + } else if (append) { + u16 *old_data = var->name; + + for (; *old_data; ++old_data) + ; + ++old_data; + ret = efi_var_mem_ins(variable_name, vendor, attributes, + var->length, old_data, data_size, data, + time); } else { - old_size = 0; - } - - val = malloc(2 * old_size + 2 * data_size - + strlen("{ro,run,boot,nv,time=0123456701234567}(blob)") - + 1); - if (!val) { - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - - s = val; - - /* - * store attributes - */ - attributes &= (EFI_VARIABLE_READ_ONLY | - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS); - s += sprintf(s, "{"); - for (u32 attr_rem = attributes; attr_rem;) { - u32 attr = 1 << (ffs(attr_rem) - 1); - - if (attr == EFI_VARIABLE_READ_ONLY) { - s += sprintf(s, "ro"); - } else if (attr == EFI_VARIABLE_NON_VOLATILE) { - s += sprintf(s, "nv"); - } else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) { - s += sprintf(s, "boot"); - } else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) { - s += sprintf(s, "run"); - } else if (attr == - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { - s += sprintf(s, "time="); - s = bin2hex(s, (u8 *)&time, sizeof(time)); - } - - attr_rem &= ~attr; - if (attr_rem) - s += sprintf(s, ","); + ret = efi_var_mem_ins(variable_name, vendor, attributes, + data_size, data, 0, NULL, time); } - s += sprintf(s, "}"); - s += sprintf(s, "(blob)"); - - /* store payload: */ - if (append) - s = bin2hex(s, old_data, old_size); - s = bin2hex(s, data, data_size); - *s = '\0'; + efi_var_mem_del(var); - EFI_PRINT("setting: %s=%s\n", native_name, val); + if (ret != EFI_SUCCESS) + return ret; -out: - if (env_set(native_name, val)) { - ret = EFI_DEVICE_ERROR; - } else { - if (!u16_strcmp(variable_name, L"PK")) - ret = efi_init_secure_state(); - else - ret = EFI_SUCCESS; - } + if (!u16_strcmp(variable_name, L"PK")) + ret = efi_init_secure_state(); + else + ret = EFI_SUCCESS; /* Write non-volatile EFI variables to file */ if (attributes & EFI_VARIABLE_NON_VOLATILE && ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS) efi_var_to_file(); -err: - free(native_name); - free(old_data); - free(val); - - return ret; + return EFI_SUCCESS; } efi_status_t efi_query_variable_info_int(u32 attributes, @@ -1006,7 +622,13 @@ efi_status_t efi_query_variable_info_int(u32 attributes, u64 *remaining_variable_storage_size, u64 *maximum_variable_size) { - return EFI_UNSUPPORTED; + *maximum_variable_storage_size = EFI_VAR_BUF_SIZE - + sizeof(struct efi_var_file); + *remaining_variable_storage_size = efi_var_mem_free(); + *maximum_variable_size = EFI_VAR_BUF_SIZE - + sizeof(struct efi_var_file) - + sizeof(struct efi_var_entry); + return EFI_SUCCESS; } /** @@ -1107,6 +729,10 @@ efi_status_t efi_init_variables(void) { efi_status_t ret; + ret = efi_var_mem_init(); + if (ret != EFI_SUCCESS) + return ret; + ret = efi_init_secure_state(); if (ret != EFI_SUCCESS) return ret; -- cgit v1.2.3 From b02a707152dc8046de6777c633f1d719c329a133 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 24 Mar 2020 19:54:53 +0000 Subject: efi_loader: enable UEFI variables at runtime Enable UEFI variables at runtime. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index bbdc071126b..eab5f005daa 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -668,7 +668,16 @@ static efi_status_t __efi_runtime EFIAPI efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data) { - return EFI_UNSUPPORTED; + efi_status_t ret; + + ret = efi_get_variable_int(variable_name, vendor, attributes, + data_size, data, NULL); + + /* Remove EFI_VARIABLE_READ_ONLY flag */ + if (attributes) + *attributes &= EFI_VARIABLE_MASK; + + return ret; } /** @@ -684,7 +693,8 @@ static efi_status_t __efi_runtime EFIAPI efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *vendor) { - return EFI_UNSUPPORTED; + return efi_get_next_variable_name_int(variable_name_size, variable_name, + vendor); } /** -- cgit v1.2.3