summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-07-16 16:35:15 -0400
committerTom Rini <trini@konsulko.com>2020-07-16 16:35:15 -0400
commitfee68b98fe3890631a9bdf8f8db328179011ee3f (patch)
tree362a05bc5b23abe6183cfc153988351e329fb6da
parent3b33eff3f263e6ccadf505e67d450970cc1c8e6c (diff)
parentc70f44817d466848c421ed7159bc9aba428e69ad (diff)
downloadu-boot-WIP/16Jul2020.tar.gz
Merge tag 'efi-2020-10-rc1-4' of https://gitlab.denx.de/u-boot/custodians/u-boot-efiWIP/16Jul2020
Pull request for UEFI sub-system for efi-2020-10-rc1 (4) Improvements for the UEFI subsystem include: * support for read-only TEE-backed variables * allow to compile PK, KEK, db, dbx fixed values into U-Boot * bug fixes Python testing related changes comprise: * enable 'bootefi hello' for better test coverage * remove SKIP messages in UEFI Python tests The fitupd command is dropped. Build errors for the lsblk command are fixed.
-rw-r--r--cmd/Kconfig8
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/fitupd.c30
-rw-r--r--cmd/lsblk.c2
-rw-r--r--cmd/nvedit.c7
-rw-r--r--cmd/nvedit_efi.c106
-rw-r--r--configs/sandbox_defconfig1
-rw-r--r--doc/README.dfutftp2
-rw-r--r--doc/README.update5
-rw-r--r--doc/uefi/uefi.rst9
-rw-r--r--include/asm-generic/sections.h2
-rw-r--r--include/efi_variable.h40
-rw-r--r--include/mm_communication.h43
-rw-r--r--lib/efi_loader/Kconfig53
-rw-r--r--lib/efi_loader/Makefile6
-rw-r--r--lib/efi_loader/efi_var_common.c182
-rw-r--r--lib/efi_loader/efi_var_file.c8
-rw-r--r--lib/efi_loader/efi_var_seed.S17
-rw-r--r--lib/efi_loader/efi_variable.c203
-rw-r--r--lib/efi_loader/efi_variable_tee.c150
-rw-r--r--test/py/tests/test_efi_loader.py16
21 files changed, 552 insertions, 339 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 846c905c9c..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
@@ -489,13 +490,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 <common.h>
-#include <command.h>
-#include <net.h>
-
-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/cmd/lsblk.c b/cmd/lsblk.c
index ece8bbf108..653dffce04 100644
--- a/cmd/lsblk.c
+++ b/cmd/lsblk.c
@@ -5,6 +5,8 @@
*/
#include <common.h>
+#include <blk.h>
+#include <command.h>
#include <dm.h>
static int do_lsblk(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
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")) {
- if (argc == 1)
- return CMD_RET_USAGE;
+ efi_guid_t guid;
- /* -a already specified */
- if (!default_guid && guid_any)
+ if (argc == 1)
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);
}
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
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
------------------
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 <U-Boot source directory>
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 bc5985cfdb..2c629e4dca 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
*
@@ -83,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 */
/**
@@ -106,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
@@ -129,6 +143,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
*
* File ubootefi.var is read from the EFI system partitions and the variables
@@ -195,4 +217,20 @@ 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);
+
+/**
+ * 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/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/Kconfig b/lib/efi_loader/Kconfig
index 4324694d48..6017ffe9a6 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -27,13 +27,51 @@ 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_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"
@@ -174,13 +212,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
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_common.c b/lib/efi_loader/efi_var_common.c
index 1e2be1135b..ee2e67bc8c 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -9,6 +9,33 @@
#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
*
@@ -138,3 +165,158 @@ 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;
+}
+
+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_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 <xypron.glpk@gmx.de>
+ */
+
+#include <config.h>
+
+.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 eab5f005da..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 <common.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <env.h>
#include <env_internal.h>
#include <hexdump.h>
+#include <log.h>
#include <malloc.h>
#include <rtc.h>
#include <search.h>
@@ -18,166 +21,7 @@
#include <crypto/pkcs7_parser.h>
#include <linux/compat.h>
#include <u-boot/crc.h>
-
-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;
-}
+#include <asm/sections.h>
#ifdef CONFIG_EFI_SECURE_BOOT
static u8 pkcs7_hdr[] = {
@@ -292,6 +136,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;
@@ -368,18 +213,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;
@@ -387,7 +234,8 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
truststore = truststore2;
truststore2 = NULL;
}
- } else {
+ break;
+ default:
/* TODO: support private authenticated variables */
goto err;
}
@@ -506,6 +354,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) &&
@@ -519,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) ||
@@ -540,12 +395,7 @@ 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))) {
+ if (var_type != EFI_AUTH_VAR_NONE) {
/* authentication is mandatory */
if (!(attributes &
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
@@ -604,7 +454,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;
@@ -747,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();
}
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index ff90aa8e81..c042348938 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,26 @@ 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);
+ }
+
+ 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 ret;
+ return alt_ret == EFI_SUCCESS ? ret : alt_ret;
}
efi_status_t efi_query_variable_info_int(u32 attributes,
@@ -586,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;
}
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))