[RFC PATCH 02/10] vdpa: check vdpa_get_config() parameters and return bytes read

From: Stefano Garzarella
Date: Tue Feb 16 2021 - 04:47:36 EST


Now we have the 'get_config_size()' callback available, so we can
check that 'offset' and 'len' parameters are valid.

When these exceed boundaries, we limit the reading to the available
configuration space in the device, and we return the amount of bytes
read.

We also move vdpa_get_config() implementation in drivers/vdpa/vdpa.c,
since the function are growing.

Signed-off-by: Stefano Garzarella <sgarzare@xxxxxxxxxx>
---
include/linux/vdpa.h | 16 ++--------------
drivers/vdpa/vdpa.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
index fddf42b17573..8a679c98f8b1 100644
--- a/include/linux/vdpa.h
+++ b/include/linux/vdpa.h
@@ -332,20 +332,8 @@ static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features)
return ops->set_features(vdev, features);
}

-
-static inline void vdpa_get_config(struct vdpa_device *vdev, unsigned offset,
- void *buf, unsigned int len)
-{
- const struct vdpa_config_ops *ops = vdev->config;
-
- /*
- * Config accesses aren't supposed to trigger before features are set.
- * If it does happen we assume a legacy guest.
- */
- if (!vdev->features_valid)
- vdpa_set_features(vdev, 0);
- ops->get_config(vdev, offset, buf, len);
-}
+int vdpa_get_config(struct vdpa_device *vdev, unsigned int offset,
+ void *buf, unsigned int len);

/**
* vdpa_mgmtdev_ops - vdpa device ops
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index 3d997b389345..9ed6c779c63c 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -51,6 +51,41 @@ static struct bus_type vdpa_bus = {
.remove = vdpa_dev_remove,
};

+static int vdpa_config_size_wrap(struct vdpa_device *vdev, unsigned int offset,
+ unsigned int len)
+{
+ const struct vdpa_config_ops *ops = vdev->config;
+ unsigned int config_size = ops->get_config_size(vdev);
+
+ if (offset > config_size || len > config_size)
+ return -1;
+
+ return min(len, config_size - offset);
+}
+
+int vdpa_get_config(struct vdpa_device *vdev, unsigned int offset,
+ void *buf, unsigned int len)
+{
+ const struct vdpa_config_ops *ops = vdev->config;
+ int bytes_get;
+
+ bytes_get = vdpa_config_size_wrap(vdev, offset, len);
+ if (bytes_get <= 0)
+ return bytes_get;
+
+ /*
+ * Config accesses aren't supposed to trigger before features are set.
+ * If it does happen we assume a legacy guest.
+ */
+ if (!vdev->features_valid)
+ vdpa_set_features(vdev, 0);
+
+ ops->get_config(vdev, offset, buf, bytes_get);
+
+ return bytes_get;
+}
+EXPORT_SYMBOL_GPL(vdpa_get_config);
+
static void vdpa_release_dev(struct device *d)
{
struct vdpa_device *vdev = dev_to_vdpa(d);
--
2.29.2