[PATCH 3/3] fsi: core: Make userspace access checks more explicit
Jeremy Kerr
jk at codeconstruct.com.au
Thu Jul 1 18:17:58 AEST 2021
Currently, we have some non-obvious checks on the offset and count
values for cfam_read, cfam_write, sysfs_raw_read and sysfs_raw_write.
This change simplifies these checks into their individual components,
and moves them all into a common fsi_validate_range() function, shared
between all userspace access functions.
Signed-off-by: Jeremy Kerr <jk at codeconstruct.com.au>
Fixes: d1dcd6782576 ("fsi: Add cfam char devices")
Reported-by: Luo Likang <luolikang at nsfocus.com>
---
drivers/fsi/fsi-core.c | 50 ++++++++++++++++++++++++------------------
1 file changed, 29 insertions(+), 21 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index efd0d78ef234..af681866b8f4 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -44,6 +44,10 @@ static const int engine_page_size = 0x400;
#define FSI_SLAVE_BASE 0x800
+/* The FSI protocol itself has a maximum 23-bit address space, all addressing
+ * must be inder this size */
+#define FSI_ADDR_SIZE 0x00800000
+
/*
* FSI slave engine control register offsets
*/
@@ -575,6 +579,19 @@ static unsigned long aligned_access_size(size_t offset, size_t count)
return BIT(__builtin_ctzl(offset_unit | count_unit));
}
+static int fsi_validate_range(loff_t off, size_t count)
+{
+ if (off < 0)
+ return -EINVAL;
+ if (off >= FSI_ADDR_SIZE)
+ return -EINVAL;
+ if (count < 0)
+ return -EINVAL;
+ if (count > FSI_ADDR_SIZE - off)
+ return -EINVAL;
+ return 0;
+}
+
static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
@@ -583,11 +600,9 @@ static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
size_t total_len, read_len;
int rc;
- if (off < 0)
- return -EINVAL;
-
- if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
- return -EINVAL;
+ rc = fsi_validate_range(off, count);
+ if (rc)
+ return rc;
for (total_len = 0; total_len < count; total_len += read_len) {
read_len = aligned_access_size(off, count - total_len);
@@ -610,11 +625,9 @@ static ssize_t fsi_slave_sysfs_raw_write(struct file *file,
size_t total_len, write_len;
int rc;
- if (off < 0)
- return -EINVAL;
-
- if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
- return -EINVAL;
+ rc = fsi_validate_range(off, count);
+ if (rc)
+ return rc;
for (total_len = 0; total_len < count; total_len += write_len) {
write_len = aligned_access_size(off, count - total_len);
@@ -699,11 +712,9 @@ static ssize_t cfam_read(struct file *filep, char __user *buf, size_t count,
loff_t off = *offset;
ssize_t rc;
- if (off < 0)
- return -EINVAL;
-
- if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
- return -EINVAL;
+ rc = fsi_validate_range(off, count);
+ if (rc)
+ return rc;
for (total_len = 0; total_len < count; total_len += read_len) {
__be32 data;
@@ -734,12 +745,9 @@ static ssize_t cfam_write(struct file *filep, const char __user *buf,
loff_t off = *offset;
ssize_t rc;
-
- if (off < 0)
- return -EINVAL;
-
- if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
- return -EINVAL;
+ rc = fsi_validate_range(off, count);
+ if (rc)
+ return rc;
for (total_len = 0; total_len < count; total_len += write_len) {
__be32 data;
--
2.30.2
More information about the linux-fsi
mailing list