- 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 <[email protected]>
---
 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)
 {
        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);
        efi_free_pool(device_path);
        if (!efiobj)
                return NULL;
-- 
2.34.1

Reply via email to