diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c index 394ae67cce..ce7175a566 100644 --- a/cmd/eficonfig.c +++ b/cmd/eficonfig.c @@ -1683,7 +1683,7 @@ static efi_status_t eficonfig_show_boot_selection(unsigned int *selected) 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 @@ static efi_status_t eficonfig_show_boot_selection(unsigned int *selected) 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 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi 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 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi 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 @@ out: 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_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_op 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 @@ efi_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_op 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 6e0bebf1d4..ed39aab081 100644 --- a/cmd/eficonfig_sbkey.c +++ b/cmd/eficonfig_sbkey.c @@ -72,6 +72,28 @@ static bool file_have_auth_header(void *buf, efi_uintn_t size) return true; } +/** + * 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 * @@ -84,6 +106,7 @@ static efi_status_t eficonfig_process_enroll_key(void *data) 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 @@ static efi_status_t eficonfig_process_enroll_key(void *data) 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 20ac3f758e..cef71be5e3 100644 --- a/cmd/sound.c +++ b/cmd/sound.c @@ -39,26 +39,39 @@ static int do_play(struct cmd_tbl *cmdtp, int flag, int argc, 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 @@ static int do_sound(struct cmd_tbl *cmdtp, int flag, int argc, } 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 9cb20f6ce6..d4184fd65e 100644 --- a/doc/usage/cmd/printenv.rst +++ b/doc/usage/cmd/printenv.rst @@ -78,7 +78,7 @@ variable and how to specify a vendor GUID: => 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 d3fac243b1..2cfe9b7ad1 100644 --- a/doc/usage/cmd/sound.rst +++ b/doc/usage/cmd/sound.rst @@ -10,12 +10,12 @@ Synopsis :: 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 @@ len 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 0899e293e5..699176872d 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -708,6 +708,8 @@ int algo_to_len(const char *algo); 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 03a3ecb235..805e6c5f1e 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -268,7 +268,8 @@ const efi_guid_t *efi_auth_var_get_guid(const u16 *name); * 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 788cb9faec..1f4ab2b419 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -223,3 +223,37 @@ bool efi_varname_is_load_option(u16 *var_name16, int *index) 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 13909b1d26..0bac594e00 100644 --- a/lib/efi_loader/efi_var_mem.c +++ b/lib/efi_loader/efi_var_mem.c @@ -315,14 +315,14 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, 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 dc1d5c8f43..c7a3fdbaa6 100644 --- a/lib/efi_selftest/efi_selftest_variables.c +++ b/lib/efi_selftest/efi_selftest_variables.c @@ -141,6 +141,41 @@ static int execute(void) 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 d104bd5997..3547aeffe7 100644 --- a/test/unicode_ut.c +++ b/test/unicode_ut.c @@ -67,6 +67,17 @@ static int unicode_test_u16_strlen(struct unit_test_state *uts) } 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);