From a2f0b504f4a9320c97bcf1cbd67f42de8a08fbc6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 17 Jun 2020 10:53:29 +0200 Subject: [PATCH 01/13] cmd: drop fitupd command The `fitupd' command is not used by any board. The `dfu tftp' command provides the same capabilities. So let's drop the `fitupd' command. Signed-off-by: Heinrich Schuchardt --- cmd/Kconfig | 7 ------- cmd/Makefile | 1 - cmd/fitupd.c | 30 ------------------------------ doc/README.dfutftp | 2 -- doc/README.update | 5 ----- 5 files changed, 45 deletions(-) delete mode 100644 cmd/fitupd.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 846c905c9c..202c7cc586 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -489,13 +489,6 @@ config CMD_SPL_WRITE_SIZE flash used by Falcon-mode boot. See the documentation until CMD_SPL for detail. -config CMD_FITUPD - bool "fitImage update command" - depends on UPDATE_TFTP - help - Implements the 'fitupd' command, which allows to automatically - store software updates present on a TFTP server in NOR Flash - config CMD_THOR_DOWNLOAD bool "thor - TIZEN 'thor' download" select DFU diff --git a/cmd/Makefile b/cmd/Makefile index dc412d1106..7952138dc2 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -62,7 +62,6 @@ obj-$(CONFIG_CMD_EXT4) += ext4.o obj-$(CONFIG_CMD_EXT2) += ext2.o obj-$(CONFIG_CMD_FAT) += fat.o obj-$(CONFIG_CMD_FDT) += fdt.o -obj-$(CONFIG_CMD_FITUPD) += fitupd.o obj-$(CONFIG_CMD_FLASH) += flash.o obj-$(CONFIG_CMD_FPGA) += fpga.o obj-$(CONFIG_CMD_FPGAD) += fpgad.o diff --git a/cmd/fitupd.c b/cmd/fitupd.c deleted file mode 100644 index 0f490c58fc..0000000000 --- a/cmd/fitupd.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2011 - * Andreas Pretzsch, carpe noctem engineering, apr@cn-eng.de - */ - -#include -#include -#include - -static int do_fitupd(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong addr = 0UL; - - if (argc > 2) - return CMD_RET_USAGE; - - if (argc == 2) - addr = simple_strtoul(argv[1], NULL, 16); - - return update_tftp(addr, NULL, NULL); -} - -U_BOOT_CMD(fitupd, 2, 0, do_fitupd, - "update from FIT image", - "[addr]\n" - "\t- run update from FIT image at addr\n" - "\t or from tftp 'updatefile'" -); diff --git a/doc/README.dfutftp b/doc/README.dfutftp index 127d2d6abc..a3341bbb61 100644 --- a/doc/README.dfutftp +++ b/doc/README.dfutftp @@ -42,8 +42,6 @@ for USB based DFU (CONFIG_DFU_*) and DFU TFTP update The "dfu" command has been extended to support transfer via TFTP - one needs to type for example "dfu tftp 0 mmc 0" -This feature does not depend on "fitupd" command enabled. - As of this writing (SHA1:8d77576371381ade83de475bb639949b44941e8c v2015.10-rc2) the update.c code is not enabled (CONFIG_UPDATE_TFTP) by any board in the contemporary u-boot tree. diff --git a/doc/README.update b/doc/README.update index d37f2c4d4a..bf4379279e 100644 --- a/doc/README.update +++ b/doc/README.update @@ -51,11 +51,6 @@ the mkimage tool. dtc tool with support for binary includes, e.g. in version to be prepared. Refer to the doc/uImage.FIT/ directory for more details on FIT images. -This mechanism can be also triggered by the command "fitupd". -If an optional, non-zero address is provided as argument, the TFTP transfer -is skipped and the image at this address is used. -The fitupd command is enabled by CONFIG_CMD_FITUPD. - Example .its files ------------------ From b961d552f9abbe60bc60aba700c97822299dab53 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 13 Jul 2020 22:22:31 +0200 Subject: [PATCH 02/13] cmd: fix lsblk command Add missing includes. Add CMD_LSBLK to sandbox_defconfig. Signed-off-by: Heinrich Schuchardt --- cmd/lsblk.c | 2 ++ configs/sandbox_defconfig | 1 + 2 files changed, 3 insertions(+) diff --git a/cmd/lsblk.c b/cmd/lsblk.c index ece8bbf108..653dffce04 100644 --- a/cmd/lsblk.c +++ b/cmd/lsblk.c @@ -5,6 +5,8 @@ */ #include +#include +#include #include static int do_lsblk(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 9b74e404bb..d43d78df6f 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -48,6 +48,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y +CONFIG_CMD_LSBLK=y CONFIG_CMD_OSD=y CONFIG_CMD_PCI=y CONFIG_CMD_READ=y From ec5f0ed33f53571fc55a55b0d0cd1c5745dbe885 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 13 Jul 2020 07:33:40 +0200 Subject: [PATCH 03/13] efi_selftest: enable 'bootefi hello' In our Python tests we want to run 'bootefi hello'. Enable it by default when compiling with CMD_BOOTEFI_SELFTEST. Signed-off-by: Heinrich Schuchardt --- cmd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/Kconfig b/cmd/Kconfig index 202c7cc586..bfe6c163dc 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -378,6 +378,7 @@ config CMD_BOOTEFI_HELLO_COMPILE config CMD_BOOTEFI_HELLO bool "Allow booting a standard EFI hello world for testing" depends on CMD_BOOTEFI_HELLO_COMPILE + default y if CMD_BOOTEFI_SELFTEST help This adds a standard EFI hello world application to U-Boot so that it can be used with the 'bootefi hello' command. This is useful From f49ca85fdf8158dc34118f9ec209f752f247e4e4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 13 Jul 2020 12:22:23 +0200 Subject: [PATCH 04/13] efi_loader: skip warnings for network configuration Skip messages should only be written if the setup is not suitable for testing. If DHCP is enabled, we should not write a skip message if no static network configuration is supplied. Likewise if a static network configuration is supplied, we should not write a skip message if DHCP is not enabled. Signed-off-by: Heinrich Schuchardt --- test/py/tests/test_efi_loader.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/py/tests/test_efi_loader.py b/test/py/tests/test_efi_loader.py index 9465c28fbc..7aa422e764 100644 --- a/test/py/tests/test_efi_loader.py +++ b/test/py/tests/test_efi_loader.py @@ -68,8 +68,8 @@ def test_efi_pre_commands(u_boot_console): u_boot_console.run_command('pci enum') @pytest.mark.buildconfigspec('cmd_dhcp') -def test_efi_dhcp(u_boot_console): - """Test the dhcp command. +def test_efi_setup_dhcp(u_boot_console): + """Set up the network using DHCP. The boardenv_* file may be used to enable/disable this test; see the comment at the beginning of this file. @@ -77,7 +77,10 @@ def test_efi_dhcp(u_boot_console): test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False) if not test_dhcp: - pytest.skip('No DHCP server available') + env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None) + if not env_vars: + pytest.skip('No DHCP server available') + return None u_boot_console.run_command('setenv autoload no') output = u_boot_console.run_command('dhcp') @@ -88,7 +91,7 @@ def test_efi_dhcp(u_boot_console): @pytest.mark.buildconfigspec('net') def test_efi_setup_static(u_boot_console): - """Set up a static IP configuration. + """Set up the network using a static IP configuration. The configuration is provided by the boardenv_* file; see the comment at the beginning of this file. @@ -96,7 +99,10 @@ def test_efi_setup_static(u_boot_console): env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None) if not env_vars: - pytest.skip('No static network configuration is defined') + test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False) + if not test_dhcp: + pytest.skip('No static network configuration is defined') + return None for (var, val) in env_vars: u_boot_console.run_command('setenv %s %s' % (var, val)) From f96744b2509622302dbc6bd6f2f669fc406c24d3 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 9 Jul 2020 23:00:40 +0300 Subject: [PATCH 05/13] 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 Reviewed-by: Heinrich Schuchardt --- include/mm_communication.h | 43 +++++++++ lib/efi_loader/efi_variable_tee.c | 140 ++++++++++++++++++++++++++++-- 2 files changed, 178 insertions(+), 5 deletions(-) diff --git a/include/mm_communication.h b/include/mm_communication.h index 193c4d1578..f9c05bb7f1 100644 --- a/include/mm_communication.h +++ b/include/mm_communication.h @@ -205,4 +205,47 @@ struct smm_variable_query_info { 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_ */ diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index ff90aa8e81..24e0663ebd 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -244,10 +244,92 @@ out: 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, u32 *attributes, efi_uintn_t *data_size, void *data, u64 *timep) { + struct var_check_property var_property; struct smm_variable_access *var_acc; efi_uintn_t payload_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) 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; + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) + *attributes |= EFI_VARIABLE_READ_ONLY; + } + if (data) memcpy(data, (u8 *)var_acc->name + var_acc->name_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, 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; efi_uintn_t payload_size; efi_uintn_t name_size; u8 *comm_buf = NULL; - efi_status_t ret; + bool ro; if (!variable_name || variable_name[0] == 0 || !vendor) { 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; goto out; } - /* Check payload size */ name_size = u16_strsize(variable_name); 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; } - /* 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, SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); if (!comm_buf) 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 */ guidcpy(&var_acc->guid, vendor); 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 */ 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: free(comm_buf); - return ret; + return alt_ret == EFI_SUCCESS ? ret : alt_ret; } efi_status_t efi_query_variable_info_int(u32 attributes, From 012c56ac76e1bdabc711a90898e81316e1d1a020 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 08:04:49 +0200 Subject: [PATCH 06/13] efi_loader: restructure code for TEE variables When using secure boot functions needed both for file and TEE based UEFI variables have to be moved to the common code module efi_var_common.c. Signed-off-by: Heinrich Schuchardt --- include/efi_variable.h | 7 ++ lib/efi_loader/efi_var_common.c | 155 +++++++++++++++++++++++++++++++ lib/efi_loader/efi_variable.c | 159 -------------------------------- 3 files changed, 162 insertions(+), 159 deletions(-) diff --git a/include/efi_variable.h b/include/efi_variable.h index bc5985cfdb..5eec407a2b 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -195,4 +195,11 @@ efi_status_t efi_var_mem_ins(u16 *variable_name, */ u64 efi_var_mem_free(void); +/** + * efi_init_secure_state - initialize secure boot state + * + * Return: status code + */ +efi_status_t efi_init_secure_state(void); + #endif diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c index 1e2be1135b..36e31b4d45 100644 --- a/lib/efi_loader/efi_var_common.c +++ b/lib/efi_loader/efi_var_common.c @@ -9,6 +9,16 @@ #include #include +enum efi_secure_mode { + EFI_MODE_SETUP, + EFI_MODE_USER, + EFI_MODE_AUDIT, + EFI_MODE_DEPLOYED, +}; + +static bool efi_secure_boot; +static enum efi_secure_mode efi_secure_mode; + /** * efi_efi_get_variable() - retrieve value of a UEFI variable * @@ -138,3 +148,148 @@ efi_status_t EFIAPI efi_query_variable_info( return EFI_EXIT(ret); } + +/** + * 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; +} diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index eab5f005da..64dc3d6df9 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -19,165 +19,6 @@ #include #include -enum efi_secure_mode { - EFI_MODE_SETUP, - EFI_MODE_USER, - EFI_MODE_AUDIT, - EFI_MODE_DEPLOYED, -}; - -static bool efi_secure_boot; -static enum efi_secure_mode efi_secure_mode; -static u8 efi_vendor_keys; - -/** - * 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_init_secure_state - initialize secure boot state - * - * Return: status code - */ -static efi_status_t efi_init_secure_state(void) -{ - enum efi_secure_mode mode = EFI_MODE_SETUP; - 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; -} #ifdef CONFIG_EFI_SECURE_BOOT static u8 pkcs7_hdr[] = { From 1a7b0f6e4ec908da1f93ea77a251429892ef0c8a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 08:14:08 +0200 Subject: [PATCH 07/13] efi_loader: update secure state Update the UEFI secure state when variable 'PK' is updated in the TEE variables implementation. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_variable_tee.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index 24e0663ebd..c042348938 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -557,6 +557,12 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, var_property.maxsize = var_acc->data_size; ret = set_property_int(variable_name, name_size, vendor, &var_property); } + + if (alt_ret != EFI_SUCCESS) + goto out; + + if (!u16_strcmp(variable_name, L"PK")) + alt_ret = efi_init_secure_state(); out: free(comm_buf); return alt_ret == EFI_SUCCESS ? ret : alt_ret; @@ -716,5 +722,9 @@ efi_status_t efi_init_variables(void) MM_VARIABLE_COMMUNICATE_SIZE + max_payload_size; + ret = efi_init_secure_state(); + if (ret != EFI_SUCCESS) + return ret; + return EFI_SUCCESS; } From 677da1c089ce5462aaf34a19b28ff16543446e71 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 12:52:51 +0200 Subject: [PATCH 08/13] doc: provide links to Microsoft UEFI certificates Some distributions provide UEFI binaries like Shim that have been signed using a Microsoft certificate. Provide the download paths for the public keys. Signed-off-by: Heinrich Schuchardt --- doc/uefi/uefi.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/uefi/uefi.rst b/doc/uefi/uefi.rst index 03d6fd0c6a..a72e729cc8 100644 --- a/doc/uefi/uefi.rst +++ b/doc/uefi/uefi.rst @@ -188,6 +188,15 @@ on the sandbox cd pytest.py test/py/tests/test_efi_secboot/test_signed.py --bd sandbox +UEFI binaries may be signed by Microsoft using the following certificates: + +* KEK: Microsoft Corporation KEK CA 2011 + http://go.microsoft.com/fwlink/?LinkId=321185. +* db: Microsoft Windows Production PCA 2011 + http://go.microsoft.com/fwlink/p/?linkid=321192. +* db: Microsoft Corporation UEFI CA 2011 + http://go.microsoft.com/fwlink/p/?linkid=321194. + Using OP-TEE for EFI variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From be66b89da30670a6a90d07742305d89ed3ccd46e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 19:18:33 +0200 Subject: [PATCH 09/13] efi_loader: configuration of variables store The file based and the OP-TEE based UEFI variable store are mutually exclusive. Define them as choice options in Kconfig. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 4324694d48..8827c76cc9 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -27,13 +27,28 @@ config EFI_LOADER if EFI_LOADER +choice + prompt "Store for non-volatile UEFI variables" + default EFI_VARIABLE_FILE_STORE + help + Select where non-volatile UEFI variables shall be stored. + config EFI_VARIABLE_FILE_STORE bool "Store non-volatile UEFI variables as file" depends on FAT_WRITE - default y help - Select tis option if you want non-volatile UEFI variables to be stored - as file /ubootefi.var on the EFI system partition. + Select this option if you want non-volatile UEFI variables to be + stored as file /ubootefi.var on the EFI system partition. + +config EFI_MM_COMM_TEE + bool "UEFI variables storage service via OP-TEE" + depends on OPTEE + help + If OP-TEE is present and running StandAloneMM, dispatch all UEFI + variable related operations to that. The application will verify, + authenticate and store the variables on an RPMB. + +endchoice config EFI_GET_TIME bool "GetTime() runtime service" @@ -174,13 +189,4 @@ config EFI_SECURE_BOOT it is signed with a trusted key. To do that, you need to install, at least, PK, KEK and db. -config EFI_MM_COMM_TEE - bool "UEFI variables storage service via OP-TEE" - depends on OPTEE - default n - help - If OP-TEE is present and running StandAloneMM, dispatch all UEFI variable - related operations to that. The application will verify, authenticate and - store the variables on an RPMB. - endif From 99bfab8b5832273d66d724f906be43fe5bd7c1ba Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 15 Jul 2020 12:40:35 +0200 Subject: [PATCH 10/13] efi_loader: identify PK, KEK, db, dbx correctly To determine if a varible is on the of the authentication variables PK, KEK, db, dbx we have to check both the name and the GUID. Provide a function converting the variable-name/guid pair to an enum and use it consistently. Signed-off-by: Heinrich Schuchardt --- include/efi_variable.h | 19 +++++++++++++++++++ lib/efi_loader/efi_var_common.c | 27 +++++++++++++++++++++++++++ lib/efi_loader/efi_variable.c | 27 ++++++++++++++------------- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/include/efi_variable.h b/include/efi_variable.h index 5eec407a2b..021a74f309 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -10,6 +10,16 @@ #define EFI_VARIABLE_READ_ONLY BIT(31) +enum efi_auth_var_type { + EFI_AUTH_VAR_NONE = 0, + EFI_AUTH_VAR_PK, + EFI_AUTH_VAR_KEK, + EFI_AUTH_VAR_DB, + EFI_AUTH_VAR_DBX, + EFI_AUTH_VAR_DBT, + EFI_AUTH_VAR_DBR, +}; + /** * efi_get_variable() - retrieve value of a UEFI variable * @@ -202,4 +212,13 @@ u64 efi_var_mem_free(void); */ efi_status_t efi_init_secure_state(void); +/** + * efi_auth_var_get_type() - convert variable name and guid to enum + * + * @name: name of UEFI variable + * @guid: guid of UEFI variable + * Return: identifier for authentication related variables + */ +enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid); + #endif diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c index 36e31b4d45..ee2e67bc8c 100644 --- a/lib/efi_loader/efi_var_common.c +++ b/lib/efi_loader/efi_var_common.c @@ -16,6 +16,23 @@ enum efi_secure_mode { 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; @@ -293,3 +310,13 @@ 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; +} diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 64dc3d6df9..ecbc4f7f54 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -133,6 +133,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, struct efi_time timestamp; struct rtc_time tm; u64 new_time; + enum efi_auth_var_type var_type; efi_status_t ret; var_sig = NULL; @@ -209,18 +210,20 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } /* signature database used for authentication */ - if (u16_strcmp(variable, L"PK") == 0 || - u16_strcmp(variable, L"KEK") == 0) { + var_type = efi_auth_var_get_type(variable, vendor); + switch (var_type) { + case EFI_AUTH_VAR_PK: + case EFI_AUTH_VAR_KEK: /* with PK */ truststore = efi_sigstore_parse_sigdb(L"PK"); if (!truststore) goto err; - } else if (u16_strcmp(variable, L"db") == 0 || - u16_strcmp(variable, L"dbx") == 0) { + break; + case EFI_AUTH_VAR_DB: + case EFI_AUTH_VAR_DBX: /* with PK and KEK */ truststore = efi_sigstore_parse_sigdb(L"KEK"); truststore2 = efi_sigstore_parse_sigdb(L"PK"); - if (!truststore) { if (!truststore2) goto err; @@ -228,7 +231,8 @@ static efi_status_t efi_variable_authenticate(u16 *variable, truststore = truststore2; truststore2 = NULL; } - } else { + break; + default: /* TODO: support private authenticated variables */ goto err; } @@ -347,6 +351,7 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, efi_uintn_t ret; bool append, delete; u64 time = 0; + enum efi_auth_var_type var_type; if (!variable_name || !*variable_name || !vendor || ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) && @@ -381,12 +386,8 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, return EFI_NOT_FOUND; } - if (((!u16_strcmp(variable_name, L"PK") || - !u16_strcmp(variable_name, L"KEK")) && - !guidcmp(vendor, &efi_global_variable_guid)) || - ((!u16_strcmp(variable_name, L"db") || - !u16_strcmp(variable_name, L"dbx")) && - !guidcmp(vendor, &efi_guid_image_security_database))) { + var_type = efi_auth_var_get_type(variable_name, vendor); + if (var_type != EFI_AUTH_VAR_NONE) { /* authentication is mandatory */ if (!(attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { @@ -445,7 +446,7 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, if (ret != EFI_SUCCESS) return ret; - if (!u16_strcmp(variable_name, L"PK")) + if (var_type == EFI_AUTH_VAR_PK) ret = efi_init_secure_state(); else ret = EFI_SUCCESS; From 7dda16343d2577a52116148540ad7d17c6f19e55 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 21:25:28 +0200 Subject: [PATCH 11/13] efi_loader: pre-seed UEFI variables Include a file with the initial values for non-volatile UEFI variables into the U-Boot binary. If this variable is set, changes to variable PK will not be allowed. Signed-off-by: Heinrich Schuchardt --- include/asm-generic/sections.h | 2 ++ include/efi_variable.h | 8 ++++++++ lib/efi_loader/Kconfig | 23 +++++++++++++++++++++++ lib/efi_loader/Makefile | 6 +++++- lib/efi_loader/efi_var_file.c | 8 +------- lib/efi_loader/efi_var_seed.S | 17 +++++++++++++++++ lib/efi_loader/efi_variable.c | 19 +++++++++++++++++-- 7 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 lib/efi_loader/efi_var_seed.S diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 17a31ec788..0577238d60 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -25,6 +25,8 @@ extern char __initdata_begin[], __initdata_end[]; extern char __start_rodata[], __end_rodata[]; extern char __efi_helloworld_begin[]; extern char __efi_helloworld_end[]; +extern char __efi_var_file_begin[]; +extern char __efi_var_file_end[]; /* Start and end of .ctors section - used for constructor calls. */ extern char __ctors_start[], __ctors_end[]; diff --git a/include/efi_variable.h b/include/efi_variable.h index 021a74f309..17f25ad7a4 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -138,6 +138,14 @@ struct efi_var_file { */ efi_status_t efi_var_to_file(void); +/** + * efi_var_restore() - restore EFI variables from buffer + * + * @buf: buffer + * Return: status code + */ +efi_status_t efi_var_restore(struct efi_var_file *buf); + /** * efi_var_from_file() - read variables from file * diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 8827c76cc9..6017ffe9a6 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -50,6 +50,29 @@ config EFI_MM_COMM_TEE endchoice +config EFI_VARIABLES_PRESEED + bool "Initial values for UEFI variables" + depends on EFI_VARIABLE_FILE_STORE + help + Include a file with the initial values for non-volatile UEFI variables + into the U-Boot binary. If this configuration option is set, changes + to authentication related variables (PK, KEK, db, dbx) are not + allowed. + +if EFI_VARIABLES_PRESEED + +config EFI_VAR_SEED_FILE + string "File with initial values of non-volatile UEFI variables" + default ubootefi.var + help + File with initial values of non-volatile UEFI variables. The file must + be in the same format as the storage in the EFI system partition. The + easiest way to create it is by setting the non-volatile variables in + U-Boot. If a relative file path is used, it is relative to the source + directory. + +endif + config EFI_GET_TIME bool "GetTime() runtime service" depends on DM_RTC diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index f81ec8d277..441ac9432e 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -6,7 +6,7 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it -asflags-y += -DHOST_ARCH="$(HOST_ARCH)" +asflags-y += -DHOST_ARCH="$(HOST_ARCH)" -I. ccflags-y += -DHOST_ARCH="$(HOST_ARCH)" CFLAGS_efi_boottime.o += \ @@ -42,6 +42,7 @@ obj-y += efi_variable_tee.o else obj-y += efi_variable.o obj-y += efi_var_file.o +obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o endif obj-y += efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o @@ -53,3 +54,6 @@ obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-y += efi_signature.o + +EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE)) +$(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c index 880c279aef..6f9d76f2a2 100644 --- a/lib/efi_loader/efi_var_file.c +++ b/lib/efi_loader/efi_var_file.c @@ -159,13 +159,7 @@ error: #endif } -/** - * efi_var_restore() - restore EFI variables from buffer - * - * @buf: buffer - * Return: status code - */ -static efi_status_t __maybe_unused efi_var_restore(struct efi_var_file *buf) +efi_status_t efi_var_restore(struct efi_var_file *buf) { struct efi_var_entry *var, *last_var; efi_status_t ret; diff --git a/lib/efi_loader/efi_var_seed.S b/lib/efi_loader/efi_var_seed.S new file mode 100644 index 0000000000..e0a40cf46c --- /dev/null +++ b/lib/efi_loader/efi_var_seed.S @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Predefined UEFI variables + * + * Copyright (c) 2020, Heinrich Schuchardt + */ + +#include + +.section .rodata.efi_seed.init,"a" +.balign 16 +.global __efi_var_file_begin +__efi_var_file_begin: +.incbin CONFIG_EFI_VAR_SEED_FILE +.global __efi_var_file_end +__efi_var_file_end: +.balign 16 diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index ecbc4f7f54..39a8482903 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -5,12 +5,15 @@ * Copyright (c) 2017 Rob Clark */ +#define LOG_CATEGORY LOGC_EFI + #include #include #include #include #include #include +#include #include #include #include @@ -18,7 +21,7 @@ #include #include #include - +#include #ifdef CONFIG_EFI_SECURE_BOOT static u8 pkcs7_hdr[] = { @@ -365,10 +368,16 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, delete = !append && (!data_size || !attributes); /* check attributes */ + var_type = efi_auth_var_get_type(variable_name, vendor); if (var) { if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY)) return EFI_WRITE_PROTECTED; + if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) { + if (var_type != EFI_AUTH_VAR_NONE) + return EFI_WRITE_PROTECTED; + } + /* attributes won't be changed */ if (!delete && ((ro_check && var->attr != attributes) || @@ -386,7 +395,6 @@ efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, return EFI_NOT_FOUND; } - var_type = efi_auth_var_get_type(variable_name, vendor); if (var_type != EFI_AUTH_VAR_NONE) { /* authentication is mandatory */ if (!(attributes & @@ -589,5 +597,12 @@ efi_status_t efi_init_variables(void) if (ret != EFI_SUCCESS) return ret; + if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) { + ret = efi_var_restore((struct efi_var_file *) + __efi_var_file_begin); + if (ret != EFI_SUCCESS) + log_err("Invalid EFI variable seed\n"); + } + return efi_var_from_file(); } From 627ab390d8ded26f4b8267c55fc4ce39145f24aa Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 16 Jul 2020 07:18:40 +0200 Subject: [PATCH 12/13] efi_loader: describe EFI_VAR_FILE_MAGIC Add documentation for EFI_VAR_FILE_MAGIC used in the file format for UEFI variables. Signed-off-by: Heinrich Schuchardt --- include/efi_variable.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/efi_variable.h b/include/efi_variable.h index 17f25ad7a4..2c629e4dca 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -93,6 +93,10 @@ efi_status_t efi_query_variable_info_int(u32 attributes, #define EFI_VAR_BUF_SIZE 0x4000 +/* + * This constant identifies the file format for storing UEFI variables in + * struct efi_var_file. + */ #define EFI_VAR_FILE_MAGIC 0x0161566966456255 /* UbEfiVa, version 1 */ /** @@ -116,7 +120,7 @@ struct efi_var_entry { * struct efi_var_file - file for storing UEFI variables * * @reserved: unused, may be overwritten by memory probing - * @magic: identifies file format + * @magic: identifies file format, takes value %EFI_VAR_FILE_MAGIC * @length: length including header * @crc32: CRC32 without header * @var: variables From c70f44817d466848c421ed7159bc9aba428e69ad Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 15 Jul 2020 18:00:56 +0200 Subject: [PATCH 13/13] efi_loader: simplify 'printenv -e' Currently default output of 'printenv -e' is restricted to variables with GUID EFI_GLOBAL_VARIABLE. This excludes db and dbx. As the number of variables is small there is no need for this restriction. If no GUID is provided, print all matching variables irrespective of GUID. Always show the numeric value of the GUID. If the GUID provided to 'setenv -e' is invalid, return CMD_RET_USAGE. Signed-off-by: Heinrich Schuchardt --- cmd/nvedit.c | 7 ++-- cmd/nvedit_efi.c | 106 +++++++++-------------------------------------- 2 files changed, 23 insertions(+), 90 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 49338b4d36..ca0be92fc3 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1410,7 +1410,7 @@ static char env_help_text[] = #endif "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "env print -e [-guid guid|-all][-n] [name ...] - print UEFI environment\n" + "env print -e [-guid guid] [-n] [name ...] - print UEFI environment\n" #endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" @@ -1452,8 +1452,9 @@ U_BOOT_CMD_COMPLETE( "print environment variables", "[-a]\n - print [all] values of all environment variables\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "printenv -e [-guid guid|-all][-n] [name ...]\n" + "printenv -e [-guid guid][-n] [name ...]\n" " - print UEFI variable 'name' or all the variables\n" + " \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n" " \"-n\": suppress dumping variable's value\n" #endif "printenv name ...\n" @@ -1487,7 +1488,7 @@ U_BOOT_CMD_COMPLETE( "-e [-guid guid][-nv][-bs][-rt][-at][-a][-v]\n" " [-i addr,size name], or [name [value ...]]\n" " - set UEFI variable 'name' to 'value' ...'\n" - " \"-guid\": set vendor guid\n" + " \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n" " \"-nv\": set non-volatile attribute\n" " \"-bs\": set boot-service attribute\n" " \"-rt\": set runtime attribute\n" diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 3f61d5d6cc..8e31f43e1f 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -52,8 +52,7 @@ static const struct { {EFI_CERT_TYPE_PKCS7_GUID, "EFI_CERT_TYPE_PKCS7_GUID"}, }; -/* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ -static char unknown_guid[37]; +static const char unknown_guid[] = ""; /** * efi_guid_to_str() - convert guid to readable name @@ -71,9 +70,6 @@ static const char *efi_guid_to_str(const efi_guid_t *guid) if (!guidcmp(guid, &efi_guid_text[i].guid)) return efi_guid_text[i].text; - uuid_bin_to_str((unsigned char *)guid->b, unknown_guid, - UUID_STR_FORMAT_GUID); - return unknown_guid; } @@ -115,7 +111,7 @@ static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose) goto out; rtc_to_tm(time, &tm); - printf("%ls:\n %s:\n", name, efi_guid_to_str(guid)); + printf("%ls:\n %pUl %s\n", name, guid, efi_guid_to_str(guid)); if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -136,50 +132,6 @@ out: free(data); } -/** - * efi_dump_vars() - show information about named UEFI variables - * - * @argc: Number of arguments (variables) - * @argv: Argument (variable name) array - * @verbose: if true, dump data - * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE - * - * Show information encoded in named UEFI variables - */ -static int efi_dump_vars(int argc, char *const argv[], - const efi_guid_t *guid, bool verbose) -{ - u16 *var_name16, *p; - efi_uintn_t buf_size, size; - - buf_size = 128; - var_name16 = malloc(buf_size); - if (!var_name16) - return CMD_RET_FAILURE; - - for (; argc > 0; argc--, argv++) { - size = (utf8_utf16_strlen(argv[0]) + 1) * sizeof(u16); - if (buf_size < size) { - buf_size = size; - p = realloc(var_name16, buf_size); - if (!p) { - free(var_name16); - return CMD_RET_FAILURE; - } - var_name16 = p; - } - - p = var_name16; - utf8_utf16_strcpy(&p, argv[0]); - - efi_dump_single_var(var_name16, guid, verbose); - } - - free(var_name16); - - return CMD_RET_SUCCESS; -} - static bool match_name(int argc, char *const argv[], u16 *var_name16) { char *buf, *p; @@ -225,10 +177,7 @@ static int efi_dump_var_all(int argc, char *const argv[], efi_uintn_t buf_size, size; efi_guid_t guid; efi_status_t ret; - - if (argc && guid_p) - /* simplified case */ - return efi_dump_vars(argc, argv, guid_p, verbose); + bool match = false; buf_size = 128; var_name16 = malloc(buf_size); @@ -259,13 +208,18 @@ static int efi_dump_var_all(int argc, char *const argv[], return CMD_RET_FAILURE; } - if ((!guid_p || !guidcmp(guid_p, &guid)) && - (!argc || match_name(argc, argv, var_name16))) + if (guid_p && guidcmp(guid_p, &guid)) + continue; + if (!argc || match_name(argc, argv, var_name16)) { + match = true; efi_dump_single_var(var_name16, &guid, verbose); + } } - free(var_name16); + if (!match && argc == 1) + printf("Error: \"%s\" not defined\n", argv[0]); + return CMD_RET_SUCCESS; } @@ -286,9 +240,8 @@ static int efi_dump_var_all(int argc, char *const argv[], int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - efi_guid_t guid; - const efi_guid_t *guid_p; - bool default_guid, guid_any, verbose; + const efi_guid_t *guid_p = NULL; + bool verbose = true; efi_status_t ret; /* Initialize EFI drivers */ @@ -299,31 +252,18 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - default_guid = true; - guid_any = false; - verbose = true; for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-guid")) { + efi_guid_t guid; + if (argc == 1) return CMD_RET_USAGE; - - /* -a already specified */ - if (!default_guid && guid_any) - return CMD_RET_USAGE; - argc--; argv++; if (uuid_str_to_bin(argv[0], guid.b, UUID_STR_FORMAT_GUID)) return CMD_RET_USAGE; - default_guid = false; - } else if (!strcmp(argv[0], "-all")) { - /* -guid already specified */ - if (!default_guid && !guid_any) - return CMD_RET_USAGE; - - guid_any = true; - default_guid = false; + guid_p = (const efi_guid_t *)guid.b; } else if (!strcmp(argv[0], "-n")) { verbose = false; } else { @@ -331,13 +271,6 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, } } - if (guid_any) - guid_p = NULL; - else if (default_guid) - guid_p = &efi_global_variable_guid; - else - guid_p = (const efi_guid_t *)guid.b; - /* enumerate and show all UEFI variables */ return efi_dump_var_all(argc, argv, guid_p, verbose); } @@ -518,8 +451,7 @@ int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc, argv++; if (uuid_str_to_bin(argv[0], guid.b, UUID_STR_FORMAT_GUID)) { - printf("## Guid not specified or in XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX format\n"); - return CMD_RET_FAILURE; + return CMD_RET_USAGE; } default_guid = false; } else if (!strcmp(argv[0], "-bs")) { @@ -567,8 +499,8 @@ int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc, } if (verbose) { - printf("GUID: %s\n", efi_guid_to_str((const efi_guid_t *) - &guid)); + printf("GUID: %pUl %s\n", &guid, + efi_guid_to_str((const efi_guid_t *)&guid)); printf("Attributes: 0x%x\n", attributes); }