efi_loader: efi_dp_check_length()
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sun, 23 Aug 2020 08:49:46 +0000 (10:49 +0200)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Mon, 24 Aug 2020 14:37:53 +0000 (16:37 +0200)
We need to check that device paths provided via UEFI variables are not
malformed.

Provide function efi_dp_check_length() to check if a device path has an
end node within a given number of bytes.

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

index 50a17a3..0baa1d2 100644 (file)
@@ -631,6 +631,8 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
                              const char *path,
                              struct efi_device_path **device,
                              struct efi_device_path **file);
+ssize_t efi_dp_check_length(const struct efi_device_path *dp,
+                           const size_t maxlen);
 
 #define EFI_DP_TYPE(_dp, _type, _subtype) \
        (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
index 7ae14f3..8a5c13c 100644 (file)
@@ -1127,3 +1127,36 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 
        return EFI_SUCCESS;
 }
+
+/**
+ * efi_dp_check_length() - check length of a device path
+ *
+ * @dp:                pointer to device path
+ * @maxlen:    maximum length of the device path
+ * Return:
+ * * length of the device path if it is less or equal @maxlen
+ * * -1 if the device path is longer then @maxlen
+ * * -1 if a device path node has a length of less than 4
+ * * -EINVAL if maxlen exceeds SSIZE_MAX
+ */
+ssize_t efi_dp_check_length(const struct efi_device_path *dp,
+                           const size_t maxlen)
+{
+       ssize_t ret = 0;
+       u16 len;
+
+       if (maxlen > SSIZE_MAX)
+               return -EINVAL;
+       for (;;) {
+               len = dp->length;
+               if (len < 4)
+                       return -1;
+               ret += len;
+               if (ret > maxlen)
+                       return -1;
+               if (dp->type == DEVICE_PATH_TYPE_END &&
+                   dp->sub_type == DEVICE_PATH_SUB_TYPE_END)
+                       return ret;
+               dp = (const struct efi_device_path *)((const u8 *)dp + len);
+       }
+}