[PATCH v1 1/2] efi_loader: improve device path matching for partition lookup

Ilias Apalodimas ilias.apalodimas at linaro.org
Fri Nov 21 13:08:06 CET 2025


On Thu, 24 Jul 2025 at 12:00, Balaji Selvanathan
<balaji.selvanathan at oss.qualcomm.com> wrote:
>
> - Refactor find_handle() to improve device path comparison logic.
> - Original logic only compared paths when len_current <= len.
> - This fails when searching for ESP inside a larger boot device.
> - ESP partition path is longer than boot device path by design.
> - New logic allows matching when dp is a prefix of dp_current.
> - Without this change, it was not able to find ESP and capsule
>   update fails to start.
>
> - Also update efi_fs_from_path() to use system partition GUID.
> - Above ensures ESP's EFI handle is returned which contains
>   file system protocol.
> - Without this change, it was returning a wrong EFI handle
>   that was not ESP handle.
>
> - These changes improves reliability for capsule updates.
>
> Signed-off-by: Balaji Selvanathan <balaji.selvanathan at oss.qualcomm.com>
> ---
>  lib/efi_loader/efi_device_path.c | 62 ++++++++++++++++++++++----------
>  lib/efi_loader/efi_disk.c        |  2 +-
>  2 files changed, 45 insertions(+), 19 deletions(-)
>
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index b3fb20b2501..3716165e963 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -107,54 +107,80 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
>   * @rem:       pointer to receive remaining device path
>   * Return:     matching handle
>   */
> +
>  static efi_handle_t find_handle(struct efi_device_path *dp,
>                                 const efi_guid_t *guid, bool short_path,
>                                 struct efi_device_path **rem)
>  {

I am not entirely convinced if the change should go via find_handle() yet.
Is what eventually fails device_is_present_and_system_part()?


>         efi_handle_t handle, best_handle = NULL;
> -       efi_uintn_t len, best_len = 0;
> +       efi_uintn_t len, len_current, best_len = 0;
> +       efi_status_t ret;
> +       struct efi_device_path *dp_current;
> +       struct efi_handler *handler;
>
>         len = efi_dp_instance_size(dp);
>
>         list_for_each_entry(handle, &efi_obj_list, link) {
> -               struct efi_handler *handler;
> -               struct efi_device_path *dp_current;
> -               efi_uintn_t len_current;
> -               efi_status_t ret;
> -
>                 if (guid) {
>                         ret = efi_search_protocol(handle, guid, &handler);
>                         if (ret != EFI_SUCCESS)
>                                 continue;
>                 }
> -               ret = efi_search_protocol(handle, &efi_guid_device_path,
> -                                         &handler);
> +
> +               ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
>                 if (ret != EFI_SUCCESS)
>                         continue;
> +
>                 dp_current = handler->protocol_interface;
>                 if (short_path) {
>                         dp_current = efi_dp_shorten(dp_current);
>                         if (!dp_current)
>                                 continue;
>                 }
> +
>                 len_current = efi_dp_instance_size(dp_current);
> +
>                 if (rem) {
> -                       if (len_current > len)
> +                       /* If current path is shorter than or equal to input path */
> +                       if (len_current <= len) {
> +                               if (memcmp(dp_current, dp, len_current))
> +                                       continue;
> +                               if (!rem)
> +                                       return handle;
> +                               if (len_current > best_len) {
> +                                       best_len = len_current;
> +                                       best_handle = handle;
> +                                       *rem = (void *)((u8 *)dp + len_current);
> +                               }
> +                       }
> +                       /* If current path is greater than input path */
> +                       else if (len_current > len) {
> +                               if (memcmp(dp, dp_current, len))
> +                                       continue;
> +                               if (len > best_len) {
> +                                       best_len = len;
> +                                       best_handle = handle;
> +                                       *rem = (struct efi_device_path *)((u8 *)dp_current + len);
> +                               }
> +                       } else {
>                                 continue;
> +                       }
>                 } else {
> -                       if (len_current != len)
> +                       if (len_current == len) {
> +                               if (memcmp(dp_current, dp, len_current))
> +                                       continue;
> +                       }
> +                       /* If current path is greater than input path */
> +                       else if (len_current > len) {
> +                               if (memcmp(dp, dp_current, len))
> +                                       continue;
> +                       } else {
>                                 continue;
> -               }
> -               if (memcmp(dp_current, dp, len_current))
> -                       continue;
> -               if (!rem)
> +                       }
>                         return handle;
> -               if (len_current > best_len) {
> -                       best_len = len_current;
> -                       best_handle = handle;
> -                       *rem = (void*)((u8 *)dp + len_current);
>                 }
>         }
> +
>         return best_handle;
>  }
>
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index 130c4db9606..49f8b5935f4 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -339,7 +339,7 @@ efi_fs_from_path(struct efi_device_path *full_path)
>         efi_free_pool(file_path);
>
>         /* Get the EFI object for the partition */
> -       efiobj = efi_dp_find_obj(device_path, NULL, NULL);
> +       efiobj = efi_dp_find_obj(device_path, &efi_system_partition_guid, NULL);

This function is not only used in capsule updates. Requiring to have
an ESP GUID installed to search for the file will break other use
cases.

Regards
/Ilias
>         efi_free_pool(device_path);
>         if (!efiobj)
>                 return NULL;
> --
> 2.34.1
>


More information about the U-Boot mailing list