diff mbox series

[3/3] fsi: core: Make userspace access checks more explicit

Message ID 20210701081758.469776-3-jk@codeconstruct.com.au
State New
Headers show
Series [1/3] fsi: core: Fix incorrect variable usage in cfam_write & cfam_read | expand

Commit Message

Jeremy Kerr July 1, 2021, 8:17 a.m. UTC
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@codeconstruct.com.au>
Fixes: d1dcd6782576 ("fsi: Add cfam char devices")
Reported-by: Luo Likang <luolikang@nsfocus.com>
---
 drivers/fsi/fsi-core.c | 50 ++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 21 deletions(-)
diff mbox series

Patch

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;