[PATCH 5/6] nfs: check all iov segments for correct memory access rights

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add Badari's function to check access for all the segments in a passed-in
iov.  We can use the total byte count later.

Signed-off-by: Chuck Lever <[email protected]>
---

 fs/nfs/direct.c |   65 +++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 9cd6b96..3d4ded0 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -374,7 +374,6 @@ static ssize_t nfs_direct_read(struct ki
 	if (!is_sync_kiocb(iocb))
 		dreq->iocb = iocb;
 
-	nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
 	rpc_clnt_sigmask(clnt, &oldset);
 	if (nfs_direct_read_schedule(dreq, user_addr, count, pos))
 		result = nfs_direct_wait(dreq);
@@ -709,8 +708,6 @@ static ssize_t nfs_direct_write(struct k
 	if (!is_sync_kiocb(iocb))
 		dreq->iocb = iocb;
 
-	nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count);
-
 	nfs_begin_data_update(inode);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -721,6 +718,36 @@ static ssize_t nfs_direct_write(struct k
 	return result;
 }
 
+/*
+ * Check:
+ * 1.  All bytes in the user buffers are properly accessible
+ * 2.  The resulting number of bytes won't overflow ssize_t
+ */
+static ssize_t check_access_ok(int type, const struct iovec *iov, unsigned long nr_segs)
+{
+	ssize_t count = 0;
+	ssize_t retval = -EINVAL;
+	unsigned long seg;
+
+	for (seg = 0; seg < nr_segs; seg++) {
+		void __user *buf = iov[seg].iov_base;
+		ssize_t len = (ssize_t) iov[seg].iov_len;
+
+		if (len < 0)		/* size_t not fitting an ssize_t .. */
+			goto out;
+		if (unlikely(!access_ok(type, buf, len))) {
+			retval = -EFAULT;
+			goto out;
+		}
+		count += len;
+		if (count < 0)		/* math overflow on the ssize_t */
+			goto out;
+	}
+	retval = count;
+out:
+	return retval;
+}
+
 /**
  * nfs_file_direct_read - file direct read operation for NFS files
  * @iocb: target I/O control block
@@ -745,13 +772,18 @@ static ssize_t nfs_direct_write(struct k
 ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
 				unsigned long nr_segs, loff_t pos)
 {
-	ssize_t retval = -EINVAL;
+	ssize_t retval;
 	struct file *file = iocb->ki_filp;
 	struct address_space *mapping = file->f_mapping;
 	/* XXX: temporary */
 	const char __user *buf = iov[0].iov_base;
 	size_t count = iov[0].iov_len;
 
+	retval = check_access_ok(VERIFY_WRITE, iov, nr_segs);
+	if (retval <= 0)
+		goto out;
+	nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, retval);
+
 	dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
 		file->f_dentry->d_parent->d_name.name,
 		file->f_dentry->d_name.name,
@@ -760,15 +792,6 @@ ssize_t nfs_file_direct_read(struct kioc
 	if (nr_segs != 1)
 		return -EINVAL;
 
-	if (count < 0)
-		goto out;
-	retval = -EFAULT;
-	if (!access_ok(VERIFY_WRITE, buf, count))
-		goto out;
-	retval = 0;
-	if (!count)
-		goto out;
-
 	retval = nfs_sync_mapping(mapping);
 	if (retval)
 		goto out;
@@ -816,6 +839,11 @@ ssize_t nfs_file_direct_write(struct kio
 	const char __user *buf = iov[0].iov_base;
 	size_t count = iov[0].iov_len;
 
+	retval = check_access_ok(VERIFY_READ, iov, nr_segs);
+	if (retval <= 0)
+		goto out;
+	nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, retval);
+
 	dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
 		file->f_dentry->d_parent->d_name.name,
 		file->f_dentry->d_name.name,
@@ -828,17 +856,6 @@ ssize_t nfs_file_direct_write(struct kio
 	if (retval)
 		goto out;
 
-	retval = -EINVAL;
-	if ((ssize_t) count < 0)
-		goto out;
-	retval = 0;
-	if (!count)
-		goto out;
-
-	retval = -EFAULT;
-	if (!access_ok(VERIFY_READ, buf, count))
-		goto out;
-
 	retval = nfs_sync_mapping(mapping);
 	if (retval)
 		goto out;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux