| From: |
| Linux Kernel Mailing List <linux-kernel@vger.kernel.org> |
| To: |
| bk-commits-head@vger.kernel.org |
| Subject: |
| Make read/write always do the full "access_ok()" tests. |
| Date: |
| Thu, 03 Feb 2005 17:37:45 +0000 |
| Archive-link: |
| Article,
Thread
|
ChangeSet 1.2040.3.8, 2005/02/03 09:37:45-08:00, torvalds@ppc970.osdl.org
Make read/write always do the full "access_ok()" tests.
The actual user copy will do them too, but only for the
range that ends up being actually copied. That hides
bugs when the range has been clamped by file size or other
issues.
read_write.c | 13 +++++++++++++
1 files changed, 13 insertions(+)
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c 2005-02-03 11:12:19 -08:00
+++ b/fs/read_write.c 2005-02-03 11:12:19 -08:00
@@ -220,6 +220,8 @@
return -EBADF;
if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
return -EINVAL;
+ if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
+ return -EFAULT;
ret = rw_verify_area(READ, file, pos, count);
if (!ret) {
@@ -266,6 +268,8 @@
return -EBADF;
if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
return -EINVAL;
+ if (unlikely(!access_ok(VERIFY_READ, buf, count)))
+ return -EFAULT;
ret = rw_verify_area(WRITE, file, pos, count);
if (!ret) {
@@ -397,6 +401,9 @@
EXPORT_SYMBOL(iov_shorten);
+/* A write operation does a read from user space and vice versa */
+#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
+
static ssize_t do_readv_writev(int type, struct file *file,
const struct iovec __user * uvector,
unsigned long nr_segs, loff_t *pos)
@@ -450,8 +457,11 @@
tot_len = 0;
ret = -EINVAL;
for (seg = 0; seg < nr_segs; seg++) {
+ void __user *buf = iov[seg].iov_base;
ssize_t len = (ssize_t)iov[seg].iov_len;
+ if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
+ goto Efault;
if (len < 0) /* size_t not fitting an ssize_t .. */
goto out;
tot_len += len;
@@ -510,6 +520,9 @@
dnotify_parent(file->f_dentry,
(type == READ) ? DN_ACCESS : DN_MODIFY);
return ret;
+Efault:
+ ret = -EFAULT;
+ goto out;
}
ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,