summaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_loader/efi_variable.c')
-rw-r--r--lib/efi_loader/efi_variable.c361
1 files changed, 104 insertions, 257 deletions
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 7df881a74b..e097670e28 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -7,14 +7,17 @@
#include <common.h>
#include <efi_loader.h>
+#include <env.h>
#include <env_internal.h>
#include <hexdump.h>
#include <malloc.h>
#include <rtc.h>
#include <search.h>
+#include <uuid.h>
+#include <crypto/pkcs7_parser.h>
+#include <linux/bitops.h>
#include <linux/compat.h>
#include <u-boot/crc.h>
-#include "../lib/crypto/pkcs7_parser.h"
enum efi_secure_mode {
EFI_MODE_SETUP,
@@ -23,13 +26,24 @@ enum efi_secure_mode {
EFI_MODE_DEPLOYED,
};
-const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
static bool efi_secure_boot;
static int efi_secure_mode;
static u8 efi_vendor_keys;
#define READ_ONLY BIT(31)
+static efi_status_t efi_get_variable_common(u16 *variable_name,
+ const efi_guid_t *vendor,
+ u32 *attributes,
+ efi_uintn_t *data_size, void *data);
+
+static efi_status_t efi_set_variable_common(u16 *variable_name,
+ const efi_guid_t *vendor,
+ u32 attributes,
+ efi_uintn_t data_size,
+ const void *data,
+ bool ro_check);
+
/*
* Mapping between EFI variables and u-boot variables:
*
@@ -169,176 +183,95 @@ static const char *parse_attr(const char *str, u32 *attrp, u64 *timep)
return str;
}
-static efi_status_t efi_set_variable_internal(u16 *variable_name,
- const efi_guid_t *vendor,
- u32 attributes,
- efi_uintn_t data_size,
- const void *data,
- bool ro_check);
+/**
+ * efi_set_secure_state - modify secure boot state variables
+ * @sec_boot: value of SecureBoot
+ * @setup_mode: value of SetupMode
+ * @audit_mode: value of AuditMode
+ * @deployed_mode: value of DeployedMode
+ *
+ * Modify secure boot stat-related variables as indicated.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_set_secure_state(int sec_boot, int setup_mode,
+ int audit_mode, int deployed_mode)
+{
+ u32 attributes;
+ efi_status_t ret;
+
+ attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ READ_ONLY;
+ ret = efi_set_variable_common(L"SecureBoot", &efi_global_variable_guid,
+ attributes, sizeof(sec_boot), &sec_boot,
+ false);
+ if (ret != EFI_SUCCESS)
+ goto err;
+
+ ret = efi_set_variable_common(L"SetupMode", &efi_global_variable_guid,
+ attributes, sizeof(setup_mode),
+ &setup_mode, false);
+ if (ret != EFI_SUCCESS)
+ goto err;
+
+ ret = efi_set_variable_common(L"AuditMode", &efi_global_variable_guid,
+ attributes, sizeof(audit_mode),
+ &audit_mode, false);
+ if (ret != EFI_SUCCESS)
+ goto err;
+
+ ret = efi_set_variable_common(L"DeployedMode",
+ &efi_global_variable_guid, attributes,
+ 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_internal()
+ * Those variables are *read-only* for users, efi_set_variable_common()
* is called here.
*
- * Return: EFI_SUCCESS on success, status code (negative) on error
+ * Return: status code
*/
static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
{
- u32 attributes;
- u8 val;
efi_status_t ret;
- debug("Secure state from %d to %d\n", efi_secure_mode, mode);
+ debug("Switching secure state from %d to %d\n", efi_secure_mode, mode);
- attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS;
if (mode == EFI_MODE_DEPLOYED) {
- val = 1;
- ret = efi_set_variable_internal(L"SecureBoot",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"SetupMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"AuditMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 1;
- ret = efi_set_variable_internal(L"DeployedMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
+ ret = efi_set_secure_state(1, 0, 0, 1);
if (ret != EFI_SUCCESS)
goto err;
efi_secure_boot = true;
} else if (mode == EFI_MODE_AUDIT) {
- ret = efi_set_variable_internal(L"PK",
- &efi_global_variable_guid,
- attributes,
- 0, NULL,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"SecureBoot",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 1;
- ret = efi_set_variable_internal(L"SetupMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
+ ret = efi_set_variable_common(L"PK", &efi_global_variable_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 0, NULL, false);
if (ret != EFI_SUCCESS)
goto err;
- val = 1;
- ret = efi_set_variable_internal(L"AuditMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"DeployedMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
+
+ ret = efi_set_secure_state(0, 1, 1, 0);
if (ret != EFI_SUCCESS)
goto err;
efi_secure_boot = true;
} else if (mode == EFI_MODE_USER) {
- val = 1;
- ret = efi_set_variable_internal(L"SecureBoot",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"SetupMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"AuditMode",
- &efi_global_variable_guid,
- attributes,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"DeployedMode",
- &efi_global_variable_guid,
- attributes,
- sizeof(val), &val,
- false);
+ ret = efi_set_secure_state(1, 0, 0, 0);
if (ret != EFI_SUCCESS)
goto err;
efi_secure_boot = true;
} else if (mode == EFI_MODE_SETUP) {
- val = 0;
- ret = efi_set_variable_internal(L"SecureBoot",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 1;
- ret = efi_set_variable_internal(L"SetupMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"AuditMode",
- &efi_global_variable_guid,
- attributes,
- sizeof(val), &val,
- false);
- if (ret != EFI_SUCCESS)
- goto err;
- val = 0;
- ret = efi_set_variable_internal(L"DeployedMode",
- &efi_global_variable_guid,
- attributes | READ_ONLY,
- sizeof(val), &val,
- false);
+ ret = efi_set_secure_state(0, 1, 0, 0);
if (ret != EFI_SUCCESS)
goto err;
} else {
@@ -358,7 +291,7 @@ err:
/**
* efi_init_secure_state - initialize secure boot state
*
- * Return: EFI_SUCCESS on success, status code (negative) on error
+ * Return: status code
*/
static efi_status_t efi_init_secure_state(void)
{
@@ -374,8 +307,8 @@ static efi_status_t efi_init_secure_state(void)
*/
size = 0;
- ret = EFI_CALL(efi_get_variable(L"PK", &efi_global_variable_guid,
- NULL, &size, NULL));
+ ret = efi_get_variable_common(L"PK", &efi_global_variable_guid,
+ NULL, &size, NULL);
if (ret == EFI_BUFFER_TOO_SMALL) {
if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
mode = EFI_MODE_USER;
@@ -392,14 +325,13 @@ static efi_status_t efi_init_secure_state(void)
ret = efi_transfer_secure_state(mode);
if (ret == EFI_SUCCESS)
- ret = efi_set_variable_internal(L"VendorKeys",
- &efi_global_variable_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS
- | READ_ONLY,
- sizeof(efi_vendor_keys),
- &efi_vendor_keys,
- false);
+ ret = efi_set_variable_common(L"VendorKeys",
+ &efi_global_variable_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ READ_ONLY,
+ sizeof(efi_vendor_keys),
+ &efi_vendor_keys, false);
err:
return ret;
@@ -513,7 +445,7 @@ out:
* attributes and signed time will also be returned in @env_attr and @time,
* respectively.
*
- * Return: EFI_SUCCESS on success, status code (negative) on error
+ * Return: status code
*/
static efi_status_t efi_variable_authenticate(u16 *variable,
const efi_guid_t *vendor,
@@ -594,9 +526,8 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
auth->auth_info.hdr.dwLength
- sizeof(auth->auth_info));
- if (IS_ERR(var_sig)) {
+ if (!var_sig) {
debug("Parsing variable's signature failed\n");
- var_sig = NULL;
goto err;
}
@@ -662,12 +593,10 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
}
#endif /* CONFIG_EFI_SECURE_BOOT */
-static
-efi_status_t EFIAPI efi_get_variable_common(u16 *variable_name,
+static efi_status_t efi_get_variable_common(u16 *variable_name,
const efi_guid_t *vendor,
u32 *attributes,
- efi_uintn_t *data_size, void *data,
- bool is_non_volatile)
+ efi_uintn_t *data_size, void *data)
{
char *native_name;
efi_status_t ret;
@@ -750,27 +679,6 @@ out:
return ret;
}
-static
-efi_status_t EFIAPI efi_get_volatile_variable(u16 *variable_name,
- const efi_guid_t *vendor,
- u32 *attributes,
- efi_uintn_t *data_size,
- void *data)
-{
- return efi_get_variable_common(variable_name, vendor, attributes,
- data_size, data, false);
-}
-
-efi_status_t EFIAPI efi_get_nonvolatile_variable(u16 *variable_name,
- const efi_guid_t *vendor,
- u32 *attributes,
- efi_uintn_t *data_size,
- void *data)
-{
- return efi_get_variable_common(variable_name, vendor, attributes,
- data_size, data, true);
-}
-
/**
* efi_efi_get_variable() - retrieve value of a UEFI variable
*
@@ -795,12 +703,8 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
data_size, data);
- ret = efi_get_volatile_variable(variable_name, vendor, attributes,
- data_size, data);
- if (ret == EFI_NOT_FOUND)
- ret = efi_get_nonvolatile_variable(variable_name, vendor,
- attributes, data_size, data);
-
+ ret = efi_get_variable_common(variable_name, vendor, attributes,
+ data_size, data);
return EFI_EXIT(ret);
}
@@ -865,7 +769,10 @@ static efi_status_t parse_uboot_variable(char *variable,
/* guid */
c = *(name - 1);
*(name - 1) = '\0'; /* guid need be null-terminated here */
- uuid_str_to_bin(guid, (unsigned char *)vendor, UUID_STR_FORMAT_GUID);
+ if (uuid_str_to_bin(guid, (unsigned char *)vendor,
+ UUID_STR_FORMAT_GUID))
+ /* The only error would be EINVAL. */
+ return EFI_INVALID_PARAMETER;
*(name - 1) = c;
/* attributes */
@@ -964,14 +871,12 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
return EFI_EXIT(ret);
}
-static
-efi_status_t EFIAPI efi_set_variable_common(u16 *variable_name,
+static efi_status_t efi_set_variable_common(u16 *variable_name,
const efi_guid_t *vendor,
u32 attributes,
efi_uintn_t data_size,
const void *data,
- bool ro_check,
- bool is_non_volatile)
+ bool ro_check)
{
char *native_name = NULL, *old_data = NULL, *val = NULL, *s;
efi_uintn_t old_size;
@@ -980,8 +885,6 @@ efi_status_t EFIAPI efi_set_variable_common(u16 *variable_name,
u32 attr;
efi_status_t ret = EFI_SUCCESS;
- debug("%s: set '%s'\n", __func__, native_name);
-
if (!variable_name || !*variable_name || !vendor ||
((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
!(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) {
@@ -996,16 +899,8 @@ efi_status_t EFIAPI efi_set_variable_common(u16 *variable_name,
/* check if a variable exists */
old_size = 0;
attr = 0;
- ret = EFI_CALL(efi_get_variable(variable_name, vendor, &attr,
- &old_size, NULL));
- if (ret == EFI_BUFFER_TOO_SMALL) {
- if ((is_non_volatile && !(attr & EFI_VARIABLE_NON_VOLATILE)) ||
- (!is_non_volatile && (attr & EFI_VARIABLE_NON_VOLATILE))) {
- ret = EFI_INVALID_PARAMETER;
- goto err;
- }
- }
-
+ ret = efi_get_variable_common(variable_name, vendor, &attr,
+ &old_size, NULL);
append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE;
delete = !append && (!data_size || !attributes);
@@ -1092,11 +987,11 @@ efi_status_t EFIAPI efi_set_variable_common(u16 *variable_name,
if (append) {
old_data = malloc(old_size);
if (!old_data) {
- return EFI_OUT_OF_RESOURCES;
+ ret = EFI_OUT_OF_RESOURCES;
goto err;
}
- ret = EFI_CALL(efi_get_variable(variable_name, vendor,
- &attr, &old_size, old_data));
+ ret = efi_get_variable_common(variable_name, vendor,
+ &attr, &old_size, old_data);
if (ret != EFI_SUCCESS)
goto err;
} else {
@@ -1179,7 +1074,7 @@ out:
/* update VendorKeys */
if (vendor_keys_modified & efi_vendor_keys) {
efi_vendor_keys = 0;
- ret = efi_set_variable_internal(
+ ret = efi_set_variable_common(
L"VendorKeys",
&efi_global_variable_guid,
EFI_VARIABLE_BOOTSERVICE_ACCESS
@@ -1201,54 +1096,6 @@ err:
return ret;
}
-static
-efi_status_t EFIAPI efi_set_volatile_variable(u16 *variable_name,
- const efi_guid_t *vendor,
- u32 attributes,
- efi_uintn_t data_size,
- const void *data,
- bool ro_check)
-{
- return efi_set_variable_common(variable_name, vendor, attributes,
- data_size, data, ro_check, false);
-}
-
-efi_status_t EFIAPI efi_set_nonvolatile_variable(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;
-
- ret = efi_set_variable_common(variable_name, vendor, attributes,
- data_size, data, ro_check, true);
-
- return ret;
-}
-
-static efi_status_t efi_set_variable_internal(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;
-
- if (attributes & EFI_VARIABLE_NON_VOLATILE)
- ret = efi_set_nonvolatile_variable(variable_name, vendor,
- attributes,
- data_size, data, ro_check);
- else
- ret = efi_set_volatile_variable(variable_name, vendor,
- attributes, data_size, data,
- ro_check);
-
- return ret;
-}
-
/**
* efi_set_variable() - set value of a UEFI variable
*
@@ -1274,9 +1121,9 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
/* READ_ONLY bit is not part of API */
attributes &= ~(u32)READ_ONLY;
- return EFI_EXIT(efi_set_variable_internal(variable_name, vendor,
- attributes, data_size, data,
- true));
+ return EFI_EXIT(efi_set_variable_common(variable_name, vendor,
+ attributes, data_size, data,
+ true));
}
/**