efi_loader: correcty determine total device path length
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Mon, 16 Apr 2018 05:59:08 +0000 (07:59 +0200)
committerAlexander Graf <agraf@suse.de>
Mon, 23 Apr 2018 19:34:28 +0000 (21:34 +0200)
Device paths may consist of multiple instances. Up to now we have only
considered the size of the first instance. For the services of the
EFI_DEVICE_PATH_UTILITIES_PROTOCOL in most cases the total length of the
device path is relevant.

So let's rename efi_dp_size() to efi_dp_instance_size() and create a new
function efi_dp_size() that calculates the total device path length.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
include/efi_loader.h
lib/efi_loader/efi_boottime.c
lib/efi_loader/efi_device_path.c

index 0358bcb1d7b0885a477a35a20cf36aa0891fe704..1298b5e16032338dd66ad1d864325a73c607a91a 100644 (file)
@@ -324,7 +324,10 @@ int efi_dp_match(const struct efi_device_path *a,
                 const struct efi_device_path *b);
 struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
                                   struct efi_device_path **rem);
-unsigned efi_dp_size(const struct efi_device_path *dp);
+/* get size of the first device path instance excluding end node */
+efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
+/* size of multi-instance device path excluding end node */
+efi_uintn_t efi_dp_size(const struct efi_device_path *dp);
 struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp);
 struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
                                      const struct efi_device_path *dp2);
index 7a9449f59c38368ad3d8bc5e944bb3dd98d54dab..1cfdabf6ebb1e99a86e01ce08928ca482c374dcb 100644 (file)
@@ -2219,7 +2219,7 @@ static efi_status_t EFIAPI efi_locate_device_path(
        }
 
        /* Find end of device path */
-       len = efi_dp_size(*device_path);
+       len = efi_dp_instance_size(*device_path);
 
        /* Get all handles implementing the protocol */
        ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
@@ -2234,7 +2234,7 @@ static efi_status_t EFIAPI efi_locate_device_path(
                if (ret != EFI_SUCCESS)
                        continue;
                dp = (struct efi_device_path *)handler->protocol_interface;
-               len_dp = efi_dp_size(dp);
+               len_dp = efi_dp_instance_size(dp);
                /*
                 * This handle can only be a better fit
                 * if its device path length is longer than the best fit and
index a2e48851d79e6181b7059012a1fab49deceb0132..ada0a9c268274802e10e37ba6c22bf61caaa42f6 100644 (file)
@@ -149,7 +149,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
                                   struct efi_device_path **rem)
 {
        struct efi_object *efiobj;
-       unsigned int dp_size = efi_dp_size(dp);
+       efi_uintn_t dp_size = efi_dp_instance_size(dp);
 
        list_for_each_entry(efiobj, &efi_obj_list, link) {
                struct efi_handler *handler;
@@ -170,11 +170,12 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
                                         * the caller.
                                         */
                                        *rem = ((void *)dp) +
-                                               efi_dp_size(obj_dp);
+                                               efi_dp_instance_size(obj_dp);
                                        return efiobj;
                                } else {
                                        /* Only return on exact matches */
-                                       if (efi_dp_size(obj_dp) == dp_size)
+                                       if (efi_dp_instance_size(obj_dp) ==
+                                           dp_size)
                                                return efiobj;
                                }
                        }
@@ -229,10 +230,10 @@ const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
        return ret;
 }
 
-/* return size not including End node: */
-unsigned efi_dp_size(const struct efi_device_path *dp)
+/* get size of the first device path instance excluding end node */
+efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
 {
-       unsigned sz = 0;
+       efi_uintn_t sz = 0;
 
        if (!dp || dp->type == DEVICE_PATH_TYPE_END)
                return 0;
@@ -244,10 +245,25 @@ unsigned efi_dp_size(const struct efi_device_path *dp)
        return sz;
 }
 
+/* get size of multi-instance device path excluding end node */
+efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
+{
+       const struct efi_device_path *p = dp;
+
+       if (!p)
+               return 0;
+       while (p->type != DEVICE_PATH_TYPE_END ||
+              p->sub_type != DEVICE_PATH_SUB_TYPE_END)
+               p = (void *)p + p->length;
+
+       return (void *)p - (void *)dp;
+}
+
+/* copy multi-instance device path */
 struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
 {
        struct efi_device_path *ndp;
-       unsigned sz = efi_dp_size(dp) + sizeof(END);
+       size_t sz = efi_dp_size(dp) + sizeof(END);
 
        if (!dp)
                return NULL;
@@ -298,7 +314,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
        } else if (!node) {
                ret = efi_dp_dup(dp);
        } else if (!dp) {
-               unsigned sz = node->length;
+               size_t sz = node->length;
                void *p = dp_alloc(sz + sizeof(END));
                if (!p)
                        return NULL;
@@ -307,7 +323,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
                ret = p;
        } else {
                /* both dp and node are non-null */
-               unsigned sz = efi_dp_size(dp);
+               size_t sz = efi_dp_size(dp);
                void *p = dp_alloc(sz + node->length + sizeof(END));
                if (!p)
                        return NULL;