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.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl8QMDgACgkQxIHbvCwF
 GsQG1g/+P0a7gYDY9LV1CziXE5A3wCm1jTcjy/RemJ4c038V7flfX7beTcTeI8Gg
 8aHDRTnmiPpU974WgiLBT19ok3LAL87PqlwMcui2YOXDhtNB49UXyY4vLqAE8Olq
 2NEi9XsdtE5uKhoPLMf1b2vRzKaw6zcWOUP+BUycVCOQOqn2dPtotB/wFtVcVMKn
 q58VOCItIvPqNNRwVmcdKYBvp8gEtTebdV2gBlr4drrMTB1nG4BzPcya6hQw6SUL
 pMzHUAHRTiMR75taWkyvTY975Z+lX1Cn3JkS5RfdaT++ydNH3xFBpLyn1GTA1SRj
 9g3p9QL/dXSZAtjGHg78YkWN6spCD/VHLAdMaUv6La/EoW6FBWrM25KH+yqEFfDe
 llqa8jJc9YBRtvRfFaKCKKoFcIivvnU72EmHsHdgB2wZea5mSF39lGb8onXGL8XS
 a4TwgQEdAhoGBM6sKG6g+n1wicLPEKlYAUqUEZquhCAyHWg/2TwY+ArcIZd3zPsy
 d59zoHOB7z27ypfYBAa8afN9qMpwcxzODok/UK2JKMkbpOdATNxmRBMB3VP6xyD+
 W2l9Gmbg9oulScFUfbuZJ9jyQGC09OVVmDuk3DrY8/UnIL6ZN9QzsPKzZidmCsx6
 ksGsMXmJL8vDqpZqm33H46WmX+sH75yBl4cxQ5njKr3RwKCe5hw=
 =y4Dr
 -----END PGP SIGNATURE-----

Merge tag 'efi-2020-10-rc1-4' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

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.
This commit is contained in:
Tom Rini 2020-07-16 16:35:15 -04:00
commit fee68b98fe
21 changed files with 552 additions and 339 deletions

View File

@ -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

View File

@ -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

View File

@ -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'"
);

View File

@ -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[])

View File

@ -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"

View File

@ -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);
}

View File

@ -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

View File

@ -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.

View File

@ -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
------------------

View File

@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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[];

View File

@ -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
@ -128,6 +142,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
*
@ -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

View File

@ -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_ */

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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))