]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
efi_loader: check efi_deserialize_load_option() in get_dp_device()
authorHem Parekh <hemparekh1596@gmail.com>
Mon, 27 Jul 2026 11:03:36 +0000 (13:03 +0200)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Mon, 27 Jul 2026 16:50:28 +0000 (18:50 +0200)
get_dp_device() reads a Boot#### variable and passes its contents to
efi_deserialize_load_option() but ignores the return value. On failure
efi_deserialize_load_option() may return without having initialised the
caller's struct efi_load_option, and even on a malformed device path it
sets lo.file_path before validating it with efi_dp_check_length().

As a result get_dp_device() can proceed to walk lo.file_path with
efi_dp_split_file_path() (via efi_dp_dup()/efi_dp_size()) on a device
path that was never validated, or on an uninitialised pointer when the
variable is too short to be parsed. A device-path node with a length of
zero makes the walk loop forever, and a length below the 4-byte node
header leads to an out-of-bounds read. The Boot#### variable is
attacker-controlled in threat models where writing EFI variables does
not imply the ability to execute firmware code, so this is reachable
during capsule-on-disk processing at boot.

Check the return value and bail out, as every other caller of
efi_deserialize_load_option() already does.

Suggested-by: Hem Parekh <hemparekh1596@gmail.com>
Cc: Hem Parekh <hemparekh1596@gmail.com>
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
lib/efi_loader/efi_capsule.c

index 52887f7c2747486d18000e01f28184f31ad686ae..a77810fa15c4504381189c2b0248ad3068cb03c2 100644 (file)
@@ -860,7 +860,11 @@ static efi_status_t get_dp_device(u16 *boot_var,
        if (!buf)
                return EFI_NOT_FOUND;
 
-       efi_deserialize_load_option(&lo, buf, &size);
+       ret = efi_deserialize_load_option(&lo, buf, &size);
+       if (ret != EFI_SUCCESS) {
+               log_err("Invalid load option %ls\n", boot_var);
+               goto out;
+       }
 
        if (lo.attributes & LOAD_OPTION_ACTIVE) {
                efi_dp_split_file_path(lo.file_path, device_dp, &file_dp);
@@ -871,6 +875,7 @@ static efi_status_t get_dp_device(u16 *boot_var,
                ret = EFI_NOT_FOUND;
        }
 
+out:
        free(buf);
 
        return ret;