123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * UEFI runtime variable services
- *
- * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
- * Copyright (c) 2020 Linaro Limited, Author: AKASHI Takahiro
- */
- #include <common.h>
- #include <efi_loader.h>
- #include <efi_variable.h>
- enum efi_secure_mode {
- EFI_MODE_SETUP,
- EFI_MODE_USER,
- EFI_MODE_AUDIT,
- EFI_MODE_DEPLOYED,
- };
- struct efi_auth_var_name_type {
- const u16 *name;
- const efi_guid_t *guid;
- const enum efi_auth_var_type type;
- };
- static const struct efi_auth_var_name_type name_type[] = {
- {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
- {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
- {u"db", &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
- {u"dbx", &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
- /* not used yet
- {u"dbt", &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
- {u"dbr", &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
- */
- };
- static bool efi_secure_boot;
- static enum efi_secure_mode efi_secure_mode;
- /**
- * 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_int(variable_name, vendor, attributes,
- data_size, data, NULL);
- /* Remove EFI_VARIABLE_READ_ONLY flag */
- if (attributes)
- *attributes &= EFI_VARIABLE_MASK;
- return EFI_EXIT(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_status_t ret;
- EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
- data_size, data);
- /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
- if (attributes & ~(u32)EFI_VARIABLE_MASK)
- ret = EFI_INVALID_PARAMETER;
- else
- ret = efi_set_variable_int(variable_name, vendor, attributes,
- data_size, data, true);
- return EFI_EXIT(ret);
- }
- /**
- * 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
- *
- * 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 ret;
- EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
- ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
- vendor);
- return EFI_EXIT(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
- * Returns: status code
- */
- efi_status_t EFIAPI efi_query_variable_info(
- u32 attributes, u64 *maximum_variable_storage_size,
- u64 *remaining_variable_storage_size,
- u64 *maximum_variable_size)
- {
- efi_status_t ret;
- EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
- remaining_variable_storage_size, maximum_variable_size);
- ret = efi_query_variable_info_int(attributes,
- maximum_variable_storage_size,
- remaining_variable_storage_size,
- maximum_variable_size);
- return EFI_EXIT(ret);
- }
- efi_status_t __efi_runtime EFIAPI
- efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
- u32 *attributes, efi_uintn_t *data_size, void *data)
- {
- efi_status_t ret;
- ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL);
- /* Remove EFI_VARIABLE_READ_ONLY flag */
- if (attributes)
- *attributes &= EFI_VARIABLE_MASK;
- return ret;
- }
- efi_status_t __efi_runtime EFIAPI
- efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
- u16 *variable_name, efi_guid_t *guid)
- {
- return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid);
- }
- /**
- * efi_set_secure_state - modify secure boot state variables
- * @secure_boot: value of SecureBoot
- * @setup_mode: value of SetupMode
- * @audit_mode: value of AuditMode
- * @deployed_mode: value of DeployedMode
- *
- * Modify secure boot status related variables as indicated.
- *
- * Return: status code
- */
- static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
- u8 audit_mode, u8 deployed_mode)
- {
- 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;
- efi_secure_boot = secure_boot;
- ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid,
- 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_ro, sizeof(setup_mode),
- &setup_mode, false);
- if (ret != EFI_SUCCESS)
- goto err;
- ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid,
- 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,
- audit_mode || deployed_mode || setup_mode ?
- attributes_ro : attributes_rw,
- sizeof(deployed_mode), &deployed_mode,
- false);
- err:
- return ret;
- }
- /**
- * efi_transfer_secure_state - handle a secure boot state transition
- * @mode: new state
- *
- * Depending on @mode, secure boot related variables are updated.
- * Those variables are *read-only* for users, efi_set_variable_int()
- * is called here.
- *
- * Return: status code
- */
- static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
- {
- efi_status_t ret;
- EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
- mode);
- if (mode == EFI_MODE_DEPLOYED) {
- ret = efi_set_secure_state(1, 0, 0, 1);
- if (ret != EFI_SUCCESS)
- goto err;
- } else if (mode == EFI_MODE_AUDIT) {
- 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;
- ret = efi_set_secure_state(0, 1, 1, 0);
- if (ret != EFI_SUCCESS)
- goto err;
- } else if (mode == EFI_MODE_USER) {
- ret = efi_set_secure_state(1, 0, 0, 0);
- if (ret != EFI_SUCCESS)
- goto err;
- } else if (mode == EFI_MODE_SETUP) {
- ret = efi_set_secure_state(0, 1, 0, 0);
- if (ret != EFI_SUCCESS)
- goto err;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- efi_secure_mode = mode;
- return EFI_SUCCESS;
- err:
- /* TODO: What action should be taken here? */
- printf("ERROR: Secure state transition failed\n");
- return ret;
- }
- efi_status_t efi_init_secure_state(void)
- {
- enum efi_secure_mode mode = EFI_MODE_SETUP;
- u8 efi_vendor_keys = 0;
- efi_uintn_t size = 0;
- efi_status_t ret;
- 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;
- }
- ret = efi_transfer_secure_state(mode);
- if (ret != EFI_SUCCESS)
- return ret;
- /* 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;
- }
- /**
- * efi_secure_boot_enabled - return if secure boot is enabled or not
- *
- * Return: true if enabled, false if disabled
- */
- bool efi_secure_boot_enabled(void)
- {
- return efi_secure_boot;
- }
- enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
- {
- for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
- if (!u16_strcmp(name, name_type[i].name) &&
- !guidcmp(guid, name_type[i].guid))
- return name_type[i].type;
- }
- return EFI_AUTH_VAR_NONE;
- }
|