[linux] 01/01: Fix potential integer overflow issues in read/write paths
debian-kernel at lists.debian.org
debian-kernel at lists.debian.org
Sun Feb 28 18:22:44 UTC 2016
This is an automated email from the git hooks/post-receive script.
benh pushed a commit to branch squeeze-security
in repository linux.
commit 958ce91476550792795484477ce3a28c6b5025e1
Author: Ben Hutchings <ben at decadent.org.uk>
Date: Sun Feb 28 18:09:21 2016 +0000
Fix potential integer overflow issues in read/write paths
I identified these when analysing the more recent regression of AIO's
length limiting.
---
debian/changelog | 3 +
...v-do-the-same-max_rw_count-truncation-tha.patch | 137 +++++++++++++++++++++
...o-use-the-proper-rw_verify_area-area-help.patch | 104 ++++++++++++++++
debian/patches/series/48squeeze20 | 2 +
4 files changed, 246 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index e858858..2609bb9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,9 @@ linux-2.6 (2.6.32-48squeeze20) UNRELEASED; urgency=medium
* ALSA: usb-audio: avoid freeing umidi object twice (CVE-2016-2384)
* af_unix: Guard against other == sk in unix_dgram_sendmsg
(regression in 2.6.32-48squeeze17)
+ * Fix potential integer overflow issues in read/write paths:
+ - readv/writev: do the same MAX_RW_COUNT truncation that read/write does
+ - vfs: make AIO use the proper rw_verify_area() area helpers
-- Ben Hutchings <ben at decadent.org.uk> Sat, 13 Feb 2016 18:55:35 +0000
diff --git a/debian/patches/bugfix/all/readv-writev-do-the-same-max_rw_count-truncation-tha.patch b/debian/patches/bugfix/all/readv-writev-do-the-same-max_rw_count-truncation-tha.patch
new file mode 100644
index 0000000..a1677e2
--- /dev/null
+++ b/debian/patches/bugfix/all/readv-writev-do-the-same-max_rw_count-truncation-tha.patch
@@ -0,0 +1,137 @@
+From: Linus Torvalds <torvalds at linux-foundation.org>
+Date: Fri, 29 Oct 2010 10:36:49 -0700
+Subject: readv/writev: do the same MAX_RW_COUNT truncation that read/write
+ does
+Origin: https://git.kernel.org/linus/435f49a518c78eec8e2edbbadd912737246cbe20
+
+We used to protect against overflow, but rather than return an error, do
+what read/write does, namely to limit the total size to MAX_RW_COUNT.
+This is not only more consistent, but it also means that any broken
+low-level read/write routine that still keeps counts in 'int' can't
+break.
+
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+[bwh: Backported to 2.6.32: compat_rw_copy_check_uvector() doesn't exist here]
+---
+--- a/fs/read_write.c
++++ b/fs/read_write.c
+@@ -210,8 +210,6 @@ bad:
+ * them to something that fits in "int" so that others
+ * won't have to do range checks all the time.
+ */
+-#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
+-
+ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
+ {
+ struct inode *inode;
+@@ -546,65 +544,71 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
+ unsigned long nr_segs, unsigned long fast_segs,
+ struct iovec *fast_pointer,
+ struct iovec **ret_pointer)
+- {
++{
+ unsigned long seg;
+- ssize_t ret;
++ ssize_t ret;
+ struct iovec *iov = fast_pointer;
+
+- /*
+- * SuS says "The readv() function *may* fail if the iovcnt argument
+- * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
+- * traditionally returned zero for zero segments, so...
+- */
++ /*
++ * SuS says "The readv() function *may* fail if the iovcnt argument
++ * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
++ * traditionally returned zero for zero segments, so...
++ */
+ if (nr_segs == 0) {
+ ret = 0;
+- goto out;
++ goto out;
+ }
+
+- /*
+- * First get the "struct iovec" from user memory and
+- * verify all the pointers
+- */
++ /*
++ * First get the "struct iovec" from user memory and
++ * verify all the pointers
++ */
+ if (nr_segs > UIO_MAXIOV) {
+ ret = -EINVAL;
+- goto out;
++ goto out;
+ }
+ if (nr_segs > fast_segs) {
+- iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
++ iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+ if (iov == NULL) {
+ ret = -ENOMEM;
+- goto out;
++ goto out;
+ }
+- }
++ }
+ if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
+ ret = -EFAULT;
+- goto out;
++ goto out;
+ }
+
+- /*
++ /*
+ * According to the Single Unix Specification we should return EINVAL
+ * if an element length is < 0 when cast to ssize_t or if the
+ * total length would overflow the ssize_t return value of the
+ * system call.
+- */
++ *
++ * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the
++ * overflow case.
++ */
+ ret = 0;
+- for (seg = 0; seg < nr_segs; seg++) {
+- void __user *buf = iov[seg].iov_base;
+- ssize_t len = (ssize_t)iov[seg].iov_len;
++ for (seg = 0; seg < nr_segs; seg++) {
++ void __user *buf = iov[seg].iov_base;
++ ssize_t len = (ssize_t)iov[seg].iov_len;
+
+ /* see if we we're about to use an invalid len or if
+ * it's about to overflow ssize_t */
+- if (len < 0 || (ret + len < ret)) {
++ if (len < 0) {
+ ret = -EINVAL;
+- goto out;
++ goto out;
+ }
+ if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
+ ret = -EFAULT;
+- goto out;
++ goto out;
++ }
++ if (len > MAX_RW_COUNT - ret) {
++ len = MAX_RW_COUNT - ret;
++ iov[seg].iov_len = len;
+ }
+-
+ ret += len;
+- }
++ }
+ out:
+ *ret_pointer = iov;
+ return ret;
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 4d07902bc50c..7b7b507ffa1c 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -1820,6 +1820,7 @@ extern int current_umask(void);
+ /* /sys/fs */
+ extern struct kobject *fs_kobj;
+
++#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
+ extern int rw_verify_area(int, struct file *, loff_t *, size_t);
+
+ #define FLOCK_VERIFY_READ 1
diff --git a/debian/patches/bugfix/all/vfs-make-aio-use-the-proper-rw_verify_area-area-help.patch b/debian/patches/bugfix/all/vfs-make-aio-use-the-proper-rw_verify_area-area-help.patch
new file mode 100644
index 0000000..a8f9253
--- /dev/null
+++ b/debian/patches/bugfix/all/vfs-make-aio-use-the-proper-rw_verify_area-area-help.patch
@@ -0,0 +1,104 @@
+From: Linus Torvalds <torvalds at linux-foundation.org>
+Date: Mon, 21 May 2012 16:06:20 -0700
+Subject: vfs: make AIO use the proper rw_verify_area() area helpers
+Origin: https://git.kernel.org/linus/a70b52ec1aaeaf60f4739edb1b422827cb6f3893
+
+We had for some reason overlooked the AIO interface, and it didn't use
+the proper rw_verify_area() helper function that checks (for example)
+mandatory locking on the file, and that the size of the access doesn't
+cause us to overflow the provided offset limits etc.
+
+Instead, AIO did just the security_file_permission() thing (that
+rw_verify_area() also does) directly.
+
+This fixes it to do all the proper helper functions, which not only
+means that now mandatory file locking works with AIO too, we can
+actually remove lines of code.
+
+Reported-by: Manish Honap <manish_honap_vit at yahoo.co.in>
+Cc: stable at vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+[bwh: Backported to 3.2: adjust context]
+---
+ fs/aio.c | 30 ++++++++++++++----------------
+ 1 file changed, 14 insertions(+), 16 deletions(-)
+
+diff --git a/fs/aio.c b/fs/aio.c
+index 67a6db3e1b6f..e7f2fad7b4ce 100644
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -1389,6 +1389,10 @@ static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat)
+ if (ret < 0)
+ goto out;
+
++ ret = rw_verify_area(type, kiocb->ki_filp, &kiocb->ki_pos, ret);
++ if (ret < 0)
++ goto out;
++
+ kiocb->ki_nr_segs = kiocb->ki_nbytes;
+ kiocb->ki_cur_seg = 0;
+ /* ki_nbytes/left now reflect bytes instead of segs */
+@@ -1400,11 +1404,17 @@ out:
+ return ret;
+ }
+
+-static ssize_t aio_setup_single_vector(struct kiocb *kiocb)
++static ssize_t aio_setup_single_vector(int type, struct file * file, struct kiocb *kiocb)
+ {
++ int bytes;
++
++ bytes = rw_verify_area(type, file, &kiocb->ki_pos, kiocb->ki_left);
++ if (bytes < 0)
++ return bytes;
++
+ kiocb->ki_iovec = &kiocb->ki_inline_vec;
+ kiocb->ki_iovec->iov_base = kiocb->ki_buf;
+- kiocb->ki_iovec->iov_len = kiocb->ki_left;
++ kiocb->ki_iovec->iov_len = bytes;
+ kiocb->ki_nr_segs = 1;
+ kiocb->ki_cur_seg = 0;
+ return 0;
+@@ -1429,10 +1439,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
+ if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf,
+ kiocb->ki_left)))
+ break;
+- ret = security_file_permission(file, MAY_READ);
+- if (unlikely(ret))
+- break;
+- ret = aio_setup_single_vector(kiocb);
++ ret = aio_setup_single_vector(READ, file, kiocb);
+ if (ret)
+ break;
+ ret = -EINVAL;
+@@ -1447,10 +1454,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
+ if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf,
+ kiocb->ki_left)))
+ break;
+- ret = security_file_permission(file, MAY_WRITE);
+- if (unlikely(ret))
+- break;
+- ret = aio_setup_single_vector(kiocb);
++ ret = aio_setup_single_vector(WRITE, file, kiocb);
+ if (ret)
+ break;
+ ret = -EINVAL;
+@@ -1461,9 +1465,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
+ ret = -EBADF;
+ if (unlikely(!(file->f_mode & FMODE_READ)))
+ break;
+- ret = security_file_permission(file, MAY_READ);
+- if (unlikely(ret))
+- break;
+ ret = aio_setup_vectored_rw(READ, kiocb);
+ if (ret)
+ break;
+@@ -1475,9 +1476,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
+ ret = -EBADF;
+ if (unlikely(!(file->f_mode & FMODE_WRITE)))
+ break;
+- ret = security_file_permission(file, MAY_WRITE);
+- if (unlikely(ret))
+- break;
+ ret = aio_setup_vectored_rw(WRITE, kiocb);
+ if (ret)
+ break;
diff --git a/debian/patches/series/48squeeze20 b/debian/patches/series/48squeeze20
index 92985e7..5e1bd7b 100644
--- a/debian/patches/series/48squeeze20
+++ b/debian/patches/series/48squeeze20
@@ -3,3 +3,5 @@
+ bugfix/all/iw_cxgb3-Fix-incorrectly-returning-error-on-success.patch
+ bugfix/all/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch
+ bugfix/all/af_unix-guard-against-other-sk-in-unix_dgram_sendmsg.patch
++ bugfix/all/readv-writev-do-the-same-max_rw_count-truncation-tha.patch
++ bugfix/all/vfs-make-aio-use-the-proper-rw_verify_area-area-help.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git
More information about the Kernel-svn-changes
mailing list