Merge tag 'efi-2023-01-rc5' of https://source.denx.de/u-boot/custodians/u-boot-efi
Pull request for efi-2023-01-rc5
UEFI:
* Improve parameter checking in efi_get_next_variable_name_mem()
* Fix a bugs in management of security database via the eficonfig command
Other:
* Allow sound command to play multiple sounds
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index 394ae67..ce7175a 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -1683,7 +1683,7 @@
u32 i;
u16 *bootorder;
efi_status_t ret;
- u16 *var_name16 = NULL, *p;
+ u16 *var_name16 = NULL;
efi_uintn_t num, size, buf_size;
struct efimenu *efi_menu;
struct list_head *pos, *n;
@@ -1718,24 +1718,12 @@
int index;
efi_guid_t guid;
- size = buf_size;
- ret = efi_get_next_variable_name_int(&size, var_name16, &guid);
+ ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
if (ret == EFI_NOT_FOUND)
break;
- if (ret == EFI_BUFFER_TOO_SMALL) {
- buf_size = size;
- p = realloc(var_name16, buf_size);
- if (!p) {
- free(var_name16);
- return EFI_OUT_OF_RESOURCES;
- }
- var_name16 = p;
- ret = efi_get_next_variable_name_int(&size, var_name16, &guid);
- }
- if (ret != EFI_SUCCESS) {
- free(var_name16);
- return ret;
- }
+ if (ret != EFI_SUCCESS)
+ goto out;
+
if (efi_varname_is_load_option(var_name16, &index)) {
/* If the index is included in the BootOrder, skip it */
if (search_bootorder(bootorder, num, index, NULL))
@@ -2026,7 +2014,7 @@
u32 i;
char *title;
efi_status_t ret;
- u16 *var_name16 = NULL, *p;
+ u16 *var_name16 = NULL;
efi_uintn_t size, buf_size;
/* list the load option in the order of BootOrder variable */
@@ -2054,19 +2042,9 @@
break;
size = buf_size;
- ret = efi_get_next_variable_name_int(&size, var_name16, &guid);
+ ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
if (ret == EFI_NOT_FOUND)
break;
- if (ret == EFI_BUFFER_TOO_SMALL) {
- buf_size = size;
- p = realloc(var_name16, buf_size);
- if (!p) {
- ret = EFI_OUT_OF_RESOURCES;
- goto out;
- }
- var_name16 = p;
- ret = efi_get_next_variable_name_int(&size, var_name16, &guid);
- }
if (ret != EFI_SUCCESS)
goto out;
@@ -2332,14 +2310,15 @@
efi_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt,
efi_status_t count)
{
- u32 i;
efi_uintn_t size;
void *load_option;
+ u32 i, list_size = 0;
struct efi_load_option lo;
- u16 *var_name16 = NULL, *p;
+ u16 *var_name16 = NULL;
u16 varname[] = u"Boot####";
efi_status_t ret = EFI_SUCCESS;
- efi_uintn_t varname_size, buf_size;
+ u16 *delete_index_list = NULL, *p;
+ efi_uintn_t buf_size;
buf_size = 128;
var_name16 = malloc(buf_size);
@@ -2352,24 +2331,18 @@
efi_guid_t guid;
efi_uintn_t tmp;
- varname_size = buf_size;
- ret = efi_get_next_variable_name_int(&varname_size, var_name16, &guid);
- if (ret == EFI_NOT_FOUND)
+ ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
+ if (ret == EFI_NOT_FOUND) {
+ /*
+ * EFI_NOT_FOUND indicates we retrieved all EFI variables.
+ * This should be treated as success.
+ */
+ ret = EFI_SUCCESS;
break;
- if (ret == EFI_BUFFER_TOO_SMALL) {
- buf_size = varname_size;
- p = realloc(var_name16, buf_size);
- if (!p) {
- free(var_name16);
- return EFI_OUT_OF_RESOURCES;
- }
- var_name16 = p;
- ret = efi_get_next_variable_name_int(&varname_size, var_name16, &guid);
}
- if (ret != EFI_SUCCESS) {
- free(var_name16);
- return ret;
- }
+ if (ret != EFI_SUCCESS)
+ goto out;
+
if (!efi_varname_is_load_option(var_name16, &index))
continue;
@@ -2383,30 +2356,47 @@
if (ret != EFI_SUCCESS)
goto next;
- if (size >= sizeof(efi_guid_bootmenu_auto_generated)) {
- if (guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated) == 0) {
- for (i = 0; i < count; i++) {
- if (opt[i].size == tmp &&
- memcmp(opt[i].lo, load_option, tmp) == 0) {
- opt[i].exist = true;
- break;
- }
+ if (size >= sizeof(efi_guid_bootmenu_auto_generated) &&
+ !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
+ for (i = 0; i < count; i++) {
+ if (opt[i].size == tmp &&
+ memcmp(opt[i].lo, load_option, tmp) == 0) {
+ opt[i].exist = true;
+ break;
}
+ }
- if (i == count) {
- ret = delete_boot_option(i);
- if (ret != EFI_SUCCESS) {
- free(load_option);
- goto out;
- }
+ /*
+ * The entire list of variables must be retrieved by
+ * efi_get_next_variable_name_int() before deleting the invalid
+ * boot option, just save the index here.
+ */
+ if (i == count) {
+ p = realloc(delete_index_list, sizeof(u32) *
+ (list_size + 1));
+ if (!p) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
}
+ delete_index_list = p;
+ delete_index_list[list_size++] = index;
}
}
next:
free(load_option);
}
+ /* delete all invalid boot options */
+ for (i = 0; i < list_size; i++) {
+ ret = delete_boot_option(delete_index_list[i]);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
out:
+ free(var_name16);
+ free(delete_index_list);
+
return ret;
}
diff --git a/cmd/eficonfig_sbkey.c b/cmd/eficonfig_sbkey.c
index 6e0bebf..ed39aab 100644
--- a/cmd/eficonfig_sbkey.c
+++ b/cmd/eficonfig_sbkey.c
@@ -73,6 +73,28 @@
}
/**
+ * file_is_null_key() - check the file is an authenticated and signed null key
+ *
+ * @auth: pointer to the file
+ * @size: file size
+ * @null_key: pointer to store the result
+ * Return: status code
+ */
+static efi_status_t file_is_null_key(struct efi_variable_authentication_2 *auth,
+ efi_uintn_t size, bool *null_key)
+{
+ efi_uintn_t auth_size =
+ sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
+
+ if (size < auth_size)
+ return EFI_INVALID_PARAMETER;
+
+ *null_key = (size == auth_size);
+
+ return EFI_SUCCESS;
+}
+
+/**
* eficonfig_process_enroll_key() - enroll key into signature database
*
* @data: pointer to the data for each entry
@@ -84,6 +106,7 @@
char *buf = NULL;
efi_uintn_t size;
efi_status_t ret;
+ bool null_key = false;
struct efi_file_handle *f = NULL;
struct efi_device_path *full_dp = NULL;
struct eficonfig_select_file_info file_info;
@@ -149,13 +172,24 @@
goto out;
}
+ ret = file_is_null_key((struct efi_variable_authentication_2 *)buf,
+ size, &null_key);
+ if (ret != EFI_SUCCESS) {
+ eficonfig_print_msg("ERROR! Invalid file format.");
+ goto out;
+ }
+
attr = EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
- /* PK can enroll only one certificate */
- if (u16_strcmp(data, u"PK")) {
+ /*
+ * PK can enroll only one certificate.
+ * The signed null key is used to clear KEK, db and dbx.
+ * EFI_VARIABLE_APPEND_WRITE attribute must not be set in these cases.
+ */
+ if (u16_strcmp(data, u"PK") && !null_key) {
efi_uintn_t db_size = 0;
/* check the variable exists. If exists, add APPEND_WRITE attribute */
diff --git a/cmd/sound.c b/cmd/sound.c
index 20ac3f7..cef71be 100644
--- a/cmd/sound.c
+++ b/cmd/sound.c
@@ -39,26 +39,39 @@
int ret = 0;
int msec = 1000;
int freq = 400;
-
- if (argc > 1)
- msec = dectoul(argv[1], NULL);
- if (argc > 2)
- freq = dectoul(argv[2], NULL);
+ bool first = true;
ret = uclass_first_device_err(UCLASS_SOUND, &dev);
- if (!ret)
+ if (ret)
+ goto err;
+ --argc;
+ ++argv;
+ while (argc || first) {
+ first = false;
+ if (argc && *argv[0] != '-') {
+ msec = dectoul(argv[0], NULL);
+ --argc;
+ ++argv;
+ }
+ if (argc && *argv[0] != '-') {
+ freq = dectoul(argv[0], NULL);
+ --argc;
+ ++argv;
+ }
ret = sound_beep(dev, msec, freq);
- if (ret) {
- printf("Sound device failed to play (err=%d)\n", ret);
- return CMD_RET_FAILURE;
+ if (ret)
+ goto err;
}
-
return 0;
+
+err:
+ printf("Sound device failed to play (err=%d)\n", ret);
+ return CMD_RET_FAILURE;
}
static struct cmd_tbl cmd_sound_sub[] = {
U_BOOT_CMD_MKENT(init, 0, 1, do_init, "", ""),
- U_BOOT_CMD_MKENT(play, 2, 1, do_play, "", ""),
+ U_BOOT_CMD_MKENT(play, INT_MAX, 1, do_play, "", ""),
};
/* process sound command */
@@ -83,8 +96,10 @@
}
U_BOOT_CMD(
- sound, 4, 1, do_sound,
+ sound, INT_MAX, 1, do_sound,
"sound sub-system",
"init - initialise the sound driver\n"
- "sound play [len [freq]] - play a sound for len ms at freq Hz\n"
+ "sound play [[[-q|-s] len [freq]] ...] - play sounds\n"
+ " len - duration in ms\n"
+ " freq - frequency in Hz\n"
);
diff --git a/doc/usage/cmd/printenv.rst b/doc/usage/cmd/printenv.rst
index 9cb20f6..d4184fd 100644
--- a/doc/usage/cmd/printenv.rst
+++ b/doc/usage/cmd/printenv.rst
@@ -78,7 +78,7 @@
=>
Configuration
-=============
+-------------
UEFI variables are only supported if CONFIG_CMD_NVEDIT_EFI=y. The value of UEFI
variables can only be displayed if CONFIG_HEXDUMP=y.
diff --git a/doc/usage/cmd/sound.rst b/doc/usage/cmd/sound.rst
index d3fac24..2cfe9b7 100644
--- a/doc/usage/cmd/sound.rst
+++ b/doc/usage/cmd/sound.rst
@@ -10,12 +10,12 @@
::
sound init
- sound play [len [freq]]
+ sound play [[len freq] ...] [len [freq]]
Description
-----------
-The *sound* command is used to play a beep sound.
+The *sound* command is used to play one or multiple beep sounds.
sound init
initializes the sound driver.
@@ -30,6 +30,25 @@
freq
frequency of the sound in Hz, defaults to 400 Hz
+Examples
+--------
+
+Beep at 400 Hz for 1000 ms::
+
+ sound play
+
+Beep at 400 Hz for 600 ms::
+
+ sound play 600
+
+Beep at 500 Hz for 600 ms::
+
+ sound play 600 500
+
+Play melody::
+
+ sound play 500 1047 500 880 500 0 500 1047 500 880 500 0 500 784 500 698 500 784 1000 698
+
Configuration
-------------
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 0899e29..6991768 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -708,6 +708,8 @@
int efi_link_dev(efi_handle_t handle, struct udevice *dev);
int efi_unlink_dev(efi_handle_t handle);
bool efi_varname_is_load_option(u16 *var_name16, int *index);
+efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf,
+ efi_guid_t *guid);
/**
* efi_size_in_pages() - convert size in bytes to size in pages
diff --git a/include/efi_variable.h b/include/efi_variable.h
index 03a3ecb..805e6c5 100644
--- a/include/efi_variable.h
+++ b/include/efi_variable.h
@@ -268,7 +268,8 @@
* efi_get_next_variable_name_mem() - Runtime common code across efi variable
* implementations for GetNextVariable()
* from the cached memory copy
- * @variable_name_size: size of variable_name buffer in byte
+ *
+ * @variable_name_size: size of variable_name buffer in bytes
* @variable_name: name of uefi variable's name in u16
* @vendor: vendor's guid
*
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 788cb9f..1f4ab2b 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -223,3 +223,37 @@
return false;
}
+
+/**
+ * efi_next_variable_name() - get next variable name
+ *
+ * This function is a wrapper of efi_get_next_variable_name_int().
+ * If efi_get_next_variable_name_int() returns EFI_BUFFER_TOO_SMALL,
+ * @size and @buf are updated by new buffer size and realloced buffer.
+ *
+ * @size: pointer to the buffer size
+ * @buf: pointer to the buffer
+ * @guid: pointer to the guid
+ * Return: status code
+ */
+efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf, efi_guid_t *guid)
+{
+ u16 *p;
+ efi_status_t ret;
+ efi_uintn_t buf_size = *size;
+
+ ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
+ if (ret == EFI_NOT_FOUND)
+ return ret;
+ if (ret == EFI_BUFFER_TOO_SMALL) {
+ p = realloc(*buf, buf_size);
+ if (!p)
+ return EFI_OUT_OF_RESOURCES;
+
+ *buf = p;
+ *size = buf_size;
+ ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
+ }
+
+ return ret;
+}
diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c
index 13909b1..0bac594 100644
--- a/lib/efi_loader/efi_var_mem.c
+++ b/lib/efi_loader/efi_var_mem.c
@@ -315,14 +315,14 @@
u16 *variable_name, efi_guid_t *vendor)
{
struct efi_var_entry *var;
- efi_uintn_t old_size;
+ efi_uintn_t len, old_size;
u16 *pdata;
if (!variable_name_size || !variable_name || !vendor)
return EFI_INVALID_PARAMETER;
- if (u16_strnlen(variable_name, *variable_name_size) ==
- *variable_name_size)
+ len = *variable_name_size >> 1;
+ if (u16_strnlen(variable_name, len) == len)
return EFI_INVALID_PARAMETER;
if (!efi_var_mem_find(vendor, variable_name, &var) && *variable_name)
diff --git a/lib/efi_selftest/efi_selftest_variables.c b/lib/efi_selftest/efi_selftest_variables.c
index dc1d5c8..c7a3fdb 100644
--- a/lib/efi_selftest/efi_selftest_variables.c
+++ b/lib/efi_selftest/efi_selftest_variables.c
@@ -141,6 +141,41 @@
return EFI_ST_FAILURE;
}
/* Enumerate variables */
+
+ ret = runtime->get_next_variable_name(NULL, u"efi_st_var1", &guid);
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("GetNextVariableName missing parameter check\n");
+ return EFI_ST_FAILURE;
+ }
+
+ len = 24;
+ ret = runtime->get_next_variable_name(&len, NULL, &guid);
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("GetNextVariableName missing parameter check\n");
+ return EFI_ST_FAILURE;
+ }
+
+ len = 24;
+ ret = runtime->get_next_variable_name(&len, u"efi_st_var1", NULL);
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("GetNextVariableName missing parameter check\n");
+ return EFI_ST_FAILURE;
+ }
+
+ len = 1;
+ ret = runtime->get_next_variable_name(&len, u"", &guid);
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("GetNextVariableName missing parameter check\n");
+ return EFI_ST_FAILURE;
+ }
+
+ len = 16;
+ ret = runtime->get_next_variable_name(&len, u"efi_st_var1", &guid);
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("GetNextVariableName missing parameter check\n");
+ return EFI_ST_FAILURE;
+ }
+
boottime->set_mem(&guid, 16, 0);
*varname = 0;
flag = 0;
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index d104bd5..3547aef 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -67,6 +67,17 @@
}
UNICODE_TEST(unicode_test_u16_strlen);
+static int unicode_test_u16_strnlen(struct unit_test_state *uts)
+{
+ ut_asserteq(0, u16_strnlen(c1, 0));
+ ut_asserteq(4, u16_strnlen(c1, 4));
+ ut_asserteq(6, u16_strnlen(c1, 6));
+ ut_asserteq(6, u16_strnlen(c1, 7));
+
+ return 0;
+}
+UNICODE_TEST(unicode_test_u16_strnlen);
+
static int unicode_test_u16_strdup(struct unit_test_state *uts)
{
u16 *copy = u16_strdup(c4);