boot: initialize return parameters on zero-length EFI variable read

When a variable exists but is empty, the initial size-query
GetVariable() in efivar_get_raw_full() returns EFI_SUCCESS instead of
EFI_BUFFER_TOO_SMALL: the zero-length payload already "fits" the
zero-length query buffer. The helper returns success, but does not
initialize the return parameters.
Handle a couple of corner cases by checking the return size.

Follow-up for a409607489
This commit is contained in:
Luca Boccassi
2026-07-03 15:19:38 +01:00
parent 3bcd707d56
commit 7b7599b72d
2 changed files with 24 additions and 5 deletions
+13
View File
@@ -191,6 +191,16 @@ EFI_STATUS efivar_get_raw_full(
size_t size = 0;
err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, NULL);
if (err == EFI_SUCCESS) {
/* The variable exists but is empty, initialize return parameters */
if (ret_attributes)
*ret_attributes = 0;
if (ret_data)
*ret_data = NULL;
if (ret_size)
*ret_size = 0;
return EFI_SUCCESS;
}
if (err != EFI_BUFFER_TOO_SMALL)
return err;
@@ -222,6 +232,9 @@ EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, b
if (err != EFI_SUCCESS)
return err;
if (size == 0)
return EFI_BUFFER_TOO_SMALL;
if (ret)
*ret = *b > 0;
+11 -5
View File
@@ -62,7 +62,7 @@ bool is_direct_boot(EFI_HANDLE device) {
EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
_cleanup_free_ EFI_HANDLE *handles = NULL;
size_t n_handles;
EFI_STATUS err, dp_err;
EFI_STATUS err;
assert(ret_vmm_dev);
assert(ret_vmm_dir);
@@ -79,9 +79,15 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
for (size_t order = 0;; order++) {
_cleanup_free_ EFI_DEVICE_PATH *dp = NULL;
size_t dp_size = 0;
_cleanup_free_ char16_t *order_str = xasprintf("VMMBootOrder%04zx", order);
dp_err = efivar_get_raw(MAKE_GUID_PTR(VMM_BOOT_ORDER), order_str, (void**) &dp, NULL);
err = efivar_get_raw(MAKE_GUID_PTR(VMM_BOOT_ORDER), order_str, (void**) &dp, &dp_size);
/* Drop the device path from the (untrusted) EFI variable if it doesn't validate, so the
* check below simply has to test whether it is set. */
if (err == EFI_SUCCESS && !device_path_is_valid(dp, dp_size))
dp = mfree(dp);
for (size_t i = 0; i < n_handles; i++) {
_cleanup_file_close_ EFI_FILE *root_dir = NULL, *efi_dir = NULL;
@@ -92,8 +98,8 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
if (err != EFI_SUCCESS)
return err;
/* check against VMMBootOrderNNNN (if set) */
if (dp_err == EFI_SUCCESS && !device_path_startswith(fs, dp))
/* check against VMMBootOrderNNNN (if set and valid) */
if (dp && !device_path_startswith(fs, dp))
continue;
err = open_volume(handles[i], &root_dir);
@@ -112,7 +118,7 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
return EFI_SUCCESS;
}
if (dp_err != EFI_SUCCESS)
if (!dp)
return EFI_NOT_FOUND;
}
assert_not_reached();