[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