Linus Torvalds: backport 2.6 rw_verify_area() to check against file offset overflows

Linux Kernel Mailing List <[email protected]>
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1553, 2005/02/07 17:20:08-02:00, [email protected]

	Linus Torvalds: backport 2.6 rw_verify_area() to check against file offset overflows 
	
	- Make generic rw_verify_area check against file offset overflows.
	- Add 'f_maxcount' to allow filesystems to set a per-file maximum IO size.
	- Rename "locks_verify_area()" to "rw_verify_area()" and clean up the arguments.



 arch/mips64/kernel/linux32.c      |    6 +---
 arch/parisc/kernel/sys_parisc32.c |    6 +---
 arch/ppc64/kernel/sys_ppc32.c     |    6 +---
 arch/s390x/kernel/linux32.c       |    7 +----
 arch/sparc64/kernel/sys_sparc32.c |    7 +----
 fs/file_table.c                   |    1 
 fs/read_write.c                   |   48 ++++++++++++++++++++++++++------------
 include/linux/fs.h                |   10 +------
 mm/filemap.c                      |    4 +--
 9 files changed, 48 insertions(+), 47 deletions(-)


diff -Nru a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c
--- a/arch/mips64/kernel/linux32.c	2005-02-07 15:02:47 -08:00
+++ b/arch/mips64/kernel/linux32.c	2005-02-07 15:02:47 -08:00
@@ -1088,11 +1088,9 @@
 		i--;
 	}
 
-	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
+	retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
+				   file, &file->f_pos, tot_len);
 	if (retval) {
 		if (iov != iovstack)
 			kfree(iov);
diff -Nru a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
--- a/arch/parisc/kernel/sys_parisc32.c	2005-02-07 15:02:47 -08:00
+++ b/arch/parisc/kernel/sys_parisc32.c	2005-02-07 15:02:47 -08:00
@@ -1671,11 +1671,9 @@
 		i--;
 	}
 
-	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
+	retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
+				   file, &file->f_pos, tot_len);
 	if (retval) {
 		if (iov != iovstack)
 			kfree(iov);
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	2005-02-07 15:02:47 -08:00
+++ b/arch/ppc64/kernel/sys_ppc32.c	2005-02-07 15:02:47 -08:00
@@ -183,11 +183,9 @@
 		i--;
 	}
 
-	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
+	retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
+				   file, &file->f_pos, tot_len);
 	if (retval) {
 		if (iov != iovstack)
 			kfree(iov);
diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
--- a/arch/s390x/kernel/linux32.c	2005-02-07 15:02:47 -08:00
+++ b/arch/s390x/kernel/linux32.c	2005-02-07 15:02:48 -08:00
@@ -1108,7 +1108,6 @@
 	unsigned long tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
 	long retval, i;
 	io_fn_t fn;
 	iov_fn_t fnv;
@@ -1145,11 +1144,9 @@
 		i--;
 	}
 
-	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
+	retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
+				   file, &file->f_pos, tot_len);
 	if (retval)
 		goto out;
 
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	2005-02-07 15:02:47 -08:00
+++ b/arch/sparc64/kernel/sys_sparc32.c	2005-02-07 15:02:47 -08:00
@@ -1093,7 +1093,6 @@
 	__kernel_ssize_t32 tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
 	long retval, i;
 	io_fn_t fn;
 	iov_fn_t fnv;
@@ -1140,11 +1139,9 @@
 		i--;
 	}
 
-	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
+	retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
+				   file, &file->f_pos, tot_len);
 	if (retval)
 		goto out;
 
diff -Nru a/fs/file_table.c b/fs/file_table.c
--- a/fs/file_table.c	2005-02-07 15:02:47 -08:00
+++ b/fs/file_table.c	2005-02-07 15:02:47 -08:00
@@ -46,6 +46,7 @@
 		f->f_version = ++event;
 		f->f_uid = current->fsuid;
 		f->f_gid = current->fsgid;
+		f->f_maxcount = INT_MAX;
 		list_add(&f->f_list, &anon_list);
 		file_list_unlock();
 		return f;
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	2005-02-07 15:02:47 -08:00
+++ b/fs/read_write.c	2005-02-07 15:02:47 -08:00
@@ -40,6 +40,28 @@
 	return -EISDIR;
 }
 
+int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
+{
+	struct inode *inode;
+	loff_t pos;
+
+	if (unlikely(count > file->f_maxcount))
+		return -EINVAL;
+
+	pos = *ppos;
+
+	if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
+		goto Einval;
+
+	inode = file->f_dentry->d_inode;
+	if (inode->i_flock && MANDATORY_LOCK(inode))
+		return locks_mandatory_area(read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, *ppos, count);
+	return 0;
+
+Einval:
+	return -EINVAL;
+}
+
 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
 {
 	long long retval;
@@ -168,8 +190,8 @@
 	file = fget(fd);
 	if (file) {
 		if (file->f_mode & FMODE_READ) {
-			ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
-						file, file->f_pos, count);
+			ret = rw_verify_area(READ, file, &file->f_pos, count);
+
 			if (!ret) {
 				ssize_t (*read)(struct file *, char *, size_t, loff_t *);
 				ret = -EINVAL;
@@ -193,9 +215,7 @@
 	file = fget(fd);
 	if (file) {
 		if (file->f_mode & FMODE_WRITE) {
-			struct inode *inode = file->f_dentry->d_inode;
-			ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
-				file->f_pos, count);
+			ret = rw_verify_area(WRITE, file, &file->f_pos, count);
 			if (!ret) {
 				ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
 				ret = -EINVAL;
@@ -224,7 +244,6 @@
 	ssize_t ret, i;
 	io_fn_t fn;
 	iov_fn_t fnv;
-	struct inode *inode;
 
 	/*
 	 * First get the "struct iovec" from user memory and
@@ -275,12 +294,11 @@
 			goto out;
 	}
 
-	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	ret = locks_verify_area((type == VERIFY_WRITE
-				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				inode, file, file->f_pos, tot_len);
-	if (ret) goto out;
+	ret = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
+				file, &file->f_pos, tot_len);
+	if (ret) 
+		goto out;
 
 	fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
 	if (fnv) {
@@ -383,8 +401,8 @@
 		goto bad_file;
 	if (!(file->f_mode & FMODE_READ))
 		goto out;
-	ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
-				file, pos, count);
+	ret = rw_verify_area(READ, file, &pos, count);
+
 	if (ret)
 		goto out;
 	ret = -EINVAL;
@@ -414,8 +432,8 @@
 		goto bad_file;
 	if (!(file->f_mode & FMODE_WRITE))
 		goto out;
-	ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
-				file, pos, count);
+	ret = rw_verify_area(WRITE, file, &pos, count);
+
 	if (ret)
 		goto out;
 	ret = -EINVAL;
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	2005-02-07 15:02:47 -08:00
+++ b/include/linux/fs.h	2005-02-07 15:02:47 -08:00
@@ -576,6 +576,7 @@
 	unsigned int		f_uid, f_gid;
 	int			f_error;
 
+	size_t			f_maxcount;
 	unsigned long		f_version;
 
 	/* needed for tty driver, and maybe others */
@@ -1056,14 +1057,7 @@
 	return 0;
 }
 
-static inline int locks_verify_area(int read_write, struct inode *inode,
-				    struct file *filp, loff_t offset,
-				    size_t count)
-{
-	if (inode->i_flock && MANDATORY_LOCK(inode))
-		return locks_mandatory_area(read_write, inode, filp, offset, count);
-	return 0;
-}
+extern int rw_verify_area(int, struct file *, loff_t *, size_t);
 
 static inline int locks_verify_truncate(struct inode *inode,
 				    struct file *filp,
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	2005-02-07 15:02:47 -08:00
+++ b/mm/filemap.c	2005-02-07 15:02:47 -08:00
@@ -1870,7 +1870,7 @@
 		goto fput_in;
 	if (!in_inode->i_mapping->a_ops->readpage)
 		goto fput_in;
-	retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count);
+	retval = rw_verify_area(READ, in_file, &in_file->f_pos, count);
 	if (retval)
 		goto fput_in;
 
@@ -1887,7 +1887,7 @@
 	if (!out_file->f_op || !out_file->f_op->write)
 		goto fput_out;
 	out_inode = out_file->f_dentry->d_inode;
-	retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
+	retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
 	if (retval)
 		goto fput_out;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.