efi_loader: display RO attribute with TEE-backed variables
A previous commit adds support for displaying variables RO flag. Let's add it on the TEE backed variable storage as well. Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
parent
f49ca85fdf
commit
f96744b250
@ -205,4 +205,47 @@ struct smm_variable_query_info {
|
|||||||
u32 attr;
|
u32 attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001
|
||||||
|
#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT(0)
|
||||||
|
/**
|
||||||
|
* struct var_check_property - Used to store variable properties in StMM
|
||||||
|
*
|
||||||
|
* @revision: magic revision number for variable property checking
|
||||||
|
* @property: properties mask for the variable used in StMM.
|
||||||
|
* Currently RO flag is supported
|
||||||
|
* @attributes: variable attributes used in StMM checking when properties
|
||||||
|
* for a variable are enabled
|
||||||
|
* @minsize: minimum allowed size for variable payload checked against
|
||||||
|
* smm_variable_access->datasize in StMM
|
||||||
|
* @maxsize: maximum allowed size for variable payload checked against
|
||||||
|
* smm_variable_access->datasize in StMM
|
||||||
|
*
|
||||||
|
* Defined in EDK2 as VAR_CHECK_VARIABLE_PROPERTY.
|
||||||
|
*/
|
||||||
|
struct var_check_property {
|
||||||
|
u16 revision;
|
||||||
|
u16 property;
|
||||||
|
u32 attributes;
|
||||||
|
efi_uintn_t minsize;
|
||||||
|
efi_uintn_t maxsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct smm_variable_var_check_property - Used to communicate variable
|
||||||
|
* properties with StMM
|
||||||
|
*
|
||||||
|
* @guid: vendor GUID
|
||||||
|
* @name_size: size of EFI name
|
||||||
|
* @property: variable properties struct
|
||||||
|
* @name: variable name
|
||||||
|
*
|
||||||
|
* Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY.
|
||||||
|
*/
|
||||||
|
struct smm_variable_var_check_property {
|
||||||
|
efi_guid_t guid;
|
||||||
|
efi_uintn_t name_size;
|
||||||
|
struct var_check_property property;
|
||||||
|
u16 name[];
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _MM_COMMUNICATION_H_ */
|
#endif /* _MM_COMMUNICATION_H_ */
|
||||||
|
@ -244,10 +244,92 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StMM can store internal attributes and properties for variables, i.e enabling
|
||||||
|
* R/O variables
|
||||||
|
*/
|
||||||
|
static efi_status_t set_property_int(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;
|
||||||
|
|
||||||
|
payload_size = sizeof(*smm_property) + name_size;
|
||||||
|
if (payload_size > max_payload_size) {
|
||||||
|
ret = EFI_INVALID_PARAMETER;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
|
||||||
|
SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
|
||||||
|
&ret);
|
||||||
|
if (!comm_buf)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
guidcpy(&smm_property->guid, vendor);
|
||||||
|
smm_property->name_size = name_size;
|
||||||
|
memcpy(&smm_property->property, var_property,
|
||||||
|
sizeof(smm_property->property));
|
||||||
|
memcpy(smm_property->name, variable_name, name_size);
|
||||||
|
|
||||||
|
ret = mm_communicate(comm_buf, payload_size);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(comm_buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t get_property_int(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));
|
||||||
|
payload_size = sizeof(*smm_property) + name_size;
|
||||||
|
if (payload_size > max_payload_size) {
|
||||||
|
ret = EFI_INVALID_PARAMETER;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
|
||||||
|
SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
|
||||||
|
&ret);
|
||||||
|
if (!comm_buf)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
guidcpy(&smm_property->guid, vendor);
|
||||||
|
smm_property->name_size = name_size;
|
||||||
|
memcpy(smm_property->name, variable_name, name_size);
|
||||||
|
|
||||||
|
ret = mm_communicate(comm_buf, payload_size);
|
||||||
|
/*
|
||||||
|
* Currently only R/O property is supported in StMM.
|
||||||
|
* Variables that are not set to R/O will not set the property in StMM
|
||||||
|
* and the call will return EFI_NOT_FOUND. We are setting the
|
||||||
|
* properties to 0x0 so checking against that is enough for the
|
||||||
|
* EFI_NOT_FOUND case.
|
||||||
|
*/
|
||||||
|
if (ret == EFI_NOT_FOUND)
|
||||||
|
ret = EFI_SUCCESS;
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
memcpy(var_property, &smm_property->property, sizeof(*var_property));
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(comm_buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
||||||
u32 *attributes, efi_uintn_t *data_size,
|
u32 *attributes, efi_uintn_t *data_size,
|
||||||
void *data, u64 *timep)
|
void *data, u64 *timep)
|
||||||
{
|
{
|
||||||
|
struct var_check_property var_property;
|
||||||
struct smm_variable_access *var_acc;
|
struct smm_variable_access *var_acc;
|
||||||
efi_uintn_t payload_size;
|
efi_uintn_t payload_size;
|
||||||
efi_uintn_t name_size;
|
efi_uintn_t name_size;
|
||||||
@ -299,8 +381,16 @@ efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
|||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (attributes)
|
ret = get_property_int(variable_name, name_size, vendor, &var_property);
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (attributes) {
|
||||||
*attributes = var_acc->attr;
|
*attributes = var_acc->attr;
|
||||||
|
if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
|
||||||
|
*attributes |= EFI_VARIABLE_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
|
memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
|
||||||
var_acc->data_size);
|
var_acc->data_size);
|
||||||
@ -387,11 +477,13 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
|||||||
u32 attributes, efi_uintn_t data_size,
|
u32 attributes, efi_uintn_t data_size,
|
||||||
const void *data, bool ro_check)
|
const void *data, bool ro_check)
|
||||||
{
|
{
|
||||||
|
efi_status_t ret, alt_ret = EFI_SUCCESS;
|
||||||
|
struct var_check_property var_property;
|
||||||
struct smm_variable_access *var_acc;
|
struct smm_variable_access *var_acc;
|
||||||
efi_uintn_t payload_size;
|
efi_uintn_t payload_size;
|
||||||
efi_uintn_t name_size;
|
efi_uintn_t name_size;
|
||||||
u8 *comm_buf = NULL;
|
u8 *comm_buf = NULL;
|
||||||
efi_status_t ret;
|
bool ro;
|
||||||
|
|
||||||
if (!variable_name || variable_name[0] == 0 || !vendor) {
|
if (!variable_name || variable_name[0] == 0 || !vendor) {
|
||||||
ret = EFI_INVALID_PARAMETER;
|
ret = EFI_INVALID_PARAMETER;
|
||||||
@ -401,7 +493,6 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
|||||||
ret = EFI_INVALID_PARAMETER;
|
ret = EFI_INVALID_PARAMETER;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check payload size */
|
/* Check payload size */
|
||||||
name_size = u16_strsize(variable_name);
|
name_size = u16_strsize(variable_name);
|
||||||
payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
|
payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
|
||||||
@ -410,12 +501,41 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get communication buffer and initialize header */
|
/*
|
||||||
|
* Allocate the buffer early, before switching to RW (if needed)
|
||||||
|
* so we won't need to account for any failures in reading/setting
|
||||||
|
* the properties, if the allocation fails
|
||||||
|
*/
|
||||||
comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
|
comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
|
||||||
SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
|
SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
|
||||||
if (!comm_buf)
|
if (!comm_buf)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
|
||||||
|
attributes &= EFI_VARIABLE_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The API has the ability to override RO flags. If no RO check was
|
||||||
|
* requested switch the variable to RW for the duration of this call
|
||||||
|
*/
|
||||||
|
ret = get_property_int(variable_name, name_size, vendor,
|
||||||
|
&var_property);
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
|
||||||
|
/* Bypass r/o check */
|
||||||
|
if (!ro_check) {
|
||||||
|
var_property.property &= ~VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
|
||||||
|
ret = set_property_int(variable_name, name_size, vendor, &var_property);
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
ret = EFI_WRITE_PROTECTED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill in contents */
|
/* Fill in contents */
|
||||||
guidcpy(&var_acc->guid, vendor);
|
guidcpy(&var_acc->guid, vendor);
|
||||||
var_acc->data_size = data_size;
|
var_acc->data_size = data_size;
|
||||||
@ -426,10 +546,20 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
|
|||||||
|
|
||||||
/* Communicate */
|
/* Communicate */
|
||||||
ret = mm_communicate(comm_buf, payload_size);
|
ret = mm_communicate(comm_buf, payload_size);
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
alt_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 = var_acc->data_size;
|
||||||
|
ret = set_property_int(variable_name, name_size, vendor, &var_property);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
free(comm_buf);
|
free(comm_buf);
|
||||||
return ret;
|
return alt_ret == EFI_SUCCESS ? ret : alt_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
efi_status_t efi_query_variable_info_int(u32 attributes,
|
efi_status_t efi_query_variable_info_int(u32 attributes,
|
||||||
|
Loading…
Reference in New Issue
Block a user