Add the TEE-backed runtime SetVariable() implementation for the FF-A/MM variable backend. The runtime path uses EFI runtime-safe memory helpers and the shared MM communication path so SetVariable() can reach the MM secure partition after ExitBootServices().
Add runtime-safe variable-property helpers for the SetVariable() path and use the original data_size argument when restoring the read-only property maxsize, instead of relying on the MM response buffer. Reviewed-by: Simon Glass <[email protected]> Signed-off-by: Harsimran Singh Tungal <[email protected]> --- Changelog: =============== v6: Ilias: - Guard TEE runtime handler registration with CONFIG_ARM_FFA_RT_MODE - Restore OP-TEE runtime callbacks when FF-A runtime mode is disabled - Rename FF-A SetVariable runtime handler with _ffa_runtime suffix - Reuse runtime-safe property helpers in SetVariable paths v4: Ilias: - Split the runtime SetVariable() support out of the combined runtime variable-services patch. v3: Simon: - Return early on the EFI_NOT_FOUND property-get path at runtime - Use the original data_size for the read-only property maxsize update Ilias: - Rename TEE/FF-A runtime handlers to private *_int_runtime names v2: Simon: - Move the read-only property check before `setup_mm_hdr()` in efi_set_variable_runtime - Drop the stale copied boot-path comment --- lib/efi_loader/efi_variable_tee.c | 179 ++++++++++++++++++++++++------ 1 file changed, 146 insertions(+), 33 deletions(-) diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index a03f2091eb4..b4cf12d6332 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -689,10 +689,10 @@ out: * StMM can store internal attributes and properties for variables, i.e enabling * R/O variables */ -static efi_status_t set_property_int(const u16 *variable_name, - efi_uintn_t name_size, - const efi_guid_t *vendor, - struct var_check_property *var_property) +static efi_status_t __efi_runtime set_property_int(const u16 *variable_name, + efi_uintn_t name_size, + const efi_guid_t *vendor, + struct var_check_property *var_property) { struct smm_variable_var_check_property *smm_property; efi_uintn_t payload_size; @@ -700,54 +700,52 @@ static efi_status_t set_property_int(const u16 *variable_name, efi_status_t ret; payload_size = sizeof(*smm_property) + name_size; - if (payload_size > max_payload_size) { - ret = EFI_INVALID_PARAMETER; - goto out; - } + if (payload_size > max_payload_size) + return EFI_INVALID_PARAMETER; + comm_buf = setup_mm_hdr((void **)&smm_property, payload_size, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET, &ret); if (!comm_buf) - goto out; + return ret; - guidcpy(&smm_property->guid, vendor); + efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(smm_property->guid)); smm_property->name_size = name_size; - memcpy(&smm_property->property, var_property, - sizeof(smm_property->property)); - memcpy(smm_property->name, variable_name, name_size); + efi_memcpy_runtime(&smm_property->property, var_property, + sizeof(smm_property->property)); + efi_memcpy_runtime(smm_property->name, variable_name, name_size); ret = mm_communicate(comm_buf, payload_size); + if (!efi_at_runtime()) + free(comm_buf); -out: - free(comm_buf); return ret; } -static efi_status_t get_property_int(const u16 *variable_name, - efi_uintn_t name_size, - const efi_guid_t *vendor, - struct var_check_property *var_property) +static efi_status_t __efi_runtime get_property_int(const u16 *variable_name, + efi_uintn_t name_size, + const efi_guid_t *vendor, + struct var_check_property *var_property) { struct smm_variable_var_check_property *smm_property; efi_uintn_t payload_size; u8 *comm_buf = NULL; efi_status_t ret; - memset(var_property, 0, sizeof(*var_property)); + efi_memset_runtime(var_property, 0, sizeof(*var_property)); payload_size = sizeof(*smm_property) + name_size; - if (payload_size > max_payload_size) { - ret = EFI_INVALID_PARAMETER; - goto out; - } + if (payload_size > max_payload_size) + return EFI_INVALID_PARAMETER; + comm_buf = setup_mm_hdr((void **)&smm_property, payload_size, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, &ret); if (!comm_buf) - goto out; + return ret; - guidcpy(&smm_property->guid, vendor); + efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(smm_property->guid)); smm_property->name_size = name_size; - memcpy(smm_property->name, variable_name, name_size); + efi_memcpy_runtime(smm_property->name, variable_name, name_size); ret = mm_communicate(comm_buf, payload_size); /* @@ -757,14 +755,17 @@ static efi_status_t get_property_int(const u16 *variable_name, * properties to 0x0 so checking against that is enough for the * EFI_NOT_FOUND case. */ - if (ret == EFI_NOT_FOUND) + if (ret == EFI_NOT_FOUND) { ret = EFI_SUCCESS; + goto out; + } if (ret != EFI_SUCCESS) goto out; - memcpy(var_property, &smm_property->property, sizeof(*var_property)); + efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property)); out: - free(comm_buf); + if (!efi_at_runtime()) + free(comm_buf); return ret; } @@ -1001,7 +1002,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name, var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY; var_property.attributes = attributes; var_property.minsize = 1; - var_property.maxsize = var_acc->data_size; + var_property.maxsize = data_size; ret = set_property_int(variable_name, name_size, vendor, &var_property); } @@ -1078,7 +1079,10 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size, } /** - * efi_set_variable_runtime() - runtime implementation of SetVariable() + * efi_set_variable_ffa_runtime() - runtime implementation of SetVariable() + * + * This function implements the SetVariable() runtime service for OP-TEE + * with FF-A runtime transport. * * @variable_name: name of the variable * @guid: vendor GUID @@ -1088,6 +1092,111 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size, * Return: status code */ static efi_status_t __efi_runtime EFIAPI +efi_set_variable_ffa_runtime(u16 *variable_name, const efi_guid_t *guid, + u32 attributes, efi_uintn_t data_size, + const void *data) +{ + efi_status_t ret, mm_communicate_ret = EFI_SUCCESS; + struct var_check_property var_property; + struct smm_variable_access *var_acc; + efi_uintn_t payload_size; + efi_uintn_t name_size; + u8 *comm_buf = NULL; + bool ro; + + if (!variable_name || variable_name[0] == 0 || !guid) + return EFI_INVALID_PARAMETER; + + if (data_size > 0 && !data) + return EFI_INVALID_PARAMETER; + + /* Check payload size */ + name_size = u16_strsize(variable_name); + payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size; + if (payload_size > max_payload_size) + return EFI_INVALID_PARAMETER; + + ro = !!(attributes & EFI_VARIABLE_READ_ONLY); + attributes &= EFI_VARIABLE_MASK; + + ret = get_property_int(variable_name, name_size, guid, + &var_property); + if (ret != EFI_SUCCESS) + return ret; + + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) + return EFI_WRITE_PROTECTED; + + comm_buf = setup_mm_hdr((void **)&var_acc, payload_size, + SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); + if (!comm_buf) + return ret; + + /* Fill in contents */ + efi_memcpy_runtime(&var_acc->guid, guid, sizeof(*guid)); + var_acc->data_size = data_size; + var_acc->name_size = name_size; + var_acc->attr = attributes; + efi_memcpy_runtime(var_acc->name, variable_name, name_size); + efi_memcpy_runtime((u8 *)var_acc->name + name_size, data, data_size); + + /* Communicate */ + ret = mm_communicate(comm_buf, payload_size); + if (ret != EFI_SUCCESS) + mm_communicate_ret = ret; + + if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) { + var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION; + var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY; + var_property.attributes = attributes; + var_property.minsize = 1; + var_property.maxsize = data_size; + ret = set_property_int(variable_name, name_size, guid, &var_property); + } + + return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret; +} + +/** + * 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. + * + * @attributes: bitmask to select variables to be + * queried + * @maximum_variable_storage_size: maximum size of storage area for the + * selected variable types + * @remaining_variable_storage_size: remaining size of storage are for the + * selected variable types + * @maximum_variable_size: maximum size of a variable of the + * selected type + * Return: status code + */ +efi_status_t EFIAPI __efi_runtime +efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size, + u64 *remain_variable_storage_size, + u64 *max_variable_size) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_set_variable_runtime() - runtime implementation of SetVariable() + * + * This function implements the SetVariable() runtime service for OP-TEE + * without FF-A runtime transport. + * + * @variable_name: name of the variable + * @guid: 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 + */ +static efi_status_t __efi_runtime EFIAPI efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid, u32 attributes, efi_uintn_t data_size, const void *data) @@ -1124,12 +1233,16 @@ void efi_variables_boot_exit_notify(void) free(var_buf); /* Update runtime service table */ + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) { + efi_runtime_services.set_variable = efi_set_variable_ffa_runtime; + } else { + efi_runtime_services.set_variable = efi_set_variable_runtime; + } efi_runtime_services.query_variable_info = efi_query_variable_info_runtime; efi_runtime_services.get_variable = efi_get_variable_runtime; efi_runtime_services.get_next_variable_name = efi_get_next_variable_name_runtime; - efi_runtime_services.set_variable = efi_set_variable_runtime; efi_update_table_header_crc32(&efi_runtime_services.hdr); /* Record that ExitBootServices() has been called */ -- 2.43.0
