From 012c56ac76e1bdabc711a90898e81316e1d1a020 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 08:04:49 +0200 Subject: 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 --- lib/efi_loader/efi_variable.c | 159 ------------------------------------------ 1 file changed, 159 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') 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[] = { -- cgit v1.2.3 From 99bfab8b5832273d66d724f906be43fe5bd7c1ba Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 15 Jul 2020 12:40:35 +0200 Subject: 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(-) (limited to 'lib/efi_loader/efi_variable.c') 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; -- cgit v1.2.3 From 7dda16343d2577a52116148540ad7d17c6f19e55 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 14 Jul 2020 21:25:28 +0200 Subject: 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 (limited to 'lib/efi_loader/efi_variable.c') 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(); } -- cgit v1.2.3