First Last Prev Next    No search results available      Search page      Enter new bug
Bug#: 81295
Alias:
Product:
Component:
Status: RESOLVED
Resolution: FIXED
Assigned To: Gentoo Security <security@gentoo.org>
Hardware:
OS:
Version:
Priority:
Severity:
Reporter: Sune Kloppenborg Jeppesen <jaervosz@gentoo.org>
Add CC:
CC:
Remove selected CCs
URL:
Summary:
Status Whiteboard:
Keywords:
Flags: Requestee:
 
 
  ()

Filename Description Type Creator Created Size Actions
2.4-81295.patch Patch patch Tim Yamin (RETIRED) 2005-04-15 13:56 0000 8.33 KB Details | Diff
Create a New Attachment (proposed patch, testcase, etc.) View All

Bug 81295 depends on: Show dependency tree
Show dependency graph
Bug 81295 blocks:

Additional Comments: (this is where you put emerge --info)







View Bug Activity   |   Format For Printing   |   XML   |   Clone This Bug


Description:   Opened: 2005-02-08 13:17 0000
This is a pretty straight backport of Linus f_maxcount plus ppos+count range
verification code which has been added to v2.6. 

Even though the known sign handling problems in v2.6 are not present in v2.4,
this change makes it very hard for unknown sign handling bugs in VFS read/write
methods to be exploited.

This will go in v2.4.30-pre1 which is going out ASAP.


diff -Nur --exclude=cscope.out linux-2.4.29.orig/arch/mips64/kernel/linux32.c linux-2.4.29/arch/mips64/kernel/linux32.c
--- linux-2.4.29.orig/arch/mips64/kernel/linux32.c      2005-02-07 14:34:22.000000000 -0200
+++ linux-2.4.29/arch/mips64/kernel/linux32.c   2005-02-07 17:39:42.952855072 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/arch/parisc/kernel/sys_parisc32.c linux-2.4.29/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.29.orig/arch/parisc/kernel/sys_parisc32.c 2005-02-07 14:34:22.000000000 -0200
+++ linux-2.4.29/arch/parisc/kernel/sys_parisc32.c      2005-02-07 17:39:59.097400728 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/arch/ppc64/kernel/sys_ppc32.c linux-2.4.29/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.29.orig/arch/ppc64/kernel/sys_ppc32.c     2005-02-07 14:34:22.000000000 -0200
+++ linux-2.4.29/arch/ppc64/kernel/sys_ppc32.c  2005-02-07 17:40:23.377709560 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/arch/s390x/kernel/linux32.c linux-2.4.29/arch/s390x/kernel/linux32.c
--- linux-2.4.29.orig/arch/s390x/kernel/linux32.c       2005-02-07 14:34:22.000000000 -0200
+++ linux-2.4.29/arch/s390x/kernel/linux32.c    2005-02-07 17:41:11.429404592 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/arch/sparc64/kernel/sys_sparc32.c linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.29.orig/arch/sparc64/kernel/sys_sparc32.c 2005-02-07 14:34:22.000000000 -0200
+++ linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c      2005-02-07 17:41:42.027752936 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/fs/file_table.c linux-2.4.29/fs/file_table.c
--- linux-2.4.29.orig/fs/file_table.c   2005-02-07 14:34:21.000000000 -0200
+++ linux-2.4.29/fs/file_table.c        2005-02-07 15:35:27.000000000 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/fs/read_write.c linux-2.4.29/fs/read_write.c
--- linux-2.4.29.orig/fs/read_write.c   2005-02-07 14:34:21.000000000 -0200
+++ linux-2.4.29/fs/read_write.c        2005-02-07 17:35:32.965858872 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/include/linux/fs.h linux-2.4.29/include/linux/fs.h
--- linux-2.4.29.orig/include/linux/fs.h        2005-02-07 14:34:25.000000000 -0200
+++ linux-2.4.29/include/linux/fs.h     2005-02-07 16:30:59.323741984 -0200
@@ -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 -Nur --exclude=cscope.out linux-2.4.29.orig/mm/filemap.c linux-2.4.29/mm/filemap.c
--- linux-2.4.29.orig/mm/filemap.c      2005-02-07 14:34:21.000000000 -0200
+++ linux-2.4.29/mm/filemap.c   2005-02-07 17:26:33.927805112 -0200
@@ -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;

------- Comment #1 From Thierry Carrez (RETIRED) 2005-03-08 08:25:35 0000 -------
Public from Connectiva CLA-2005:930

Original 2.6 patch here:
http://linux.bkbits.net:8080/linux-2.6/patch@1.1966.1.67
http://linux.bkbits.net:8080/linux-2.6/patch@1.1966.1.68

From Alan Cox: 
Actually I think [this patch] raises bigger problems that it fixes. It can break
existing applications and it may leave 64bit machines without posix compliance in the 2.4 case.

------- Comment #2 From Thierry Carrez (RETIRED) 2005-03-08 08:29:33 0000 -------
In fact these fixes were introduced by Linux as a higher-level protection
against flaws discovered by Georgi Guninski treated in bug 82141.

------- Comment #3 From Thierry Carrez (RETIRED) 2005-03-16 03:16:46 0000 -------
Mass-Ccing kern-sec@gentoo.org to make sure Kernel Security guys know about all
of these...

------- Comment #4 From Tim Yamin (RETIRED) 2005-04-15 13:56:41 0000 -------
Created an attachment (id=56379) [edit]
Patch

------- Comment #5 From Joshua Kinard 2005-04-23 22:31:22 0000 -------
mips-sources fixed.

------- Comment #6 From Tim Yamin (RETIRED) 2005-08-20 11:27:45 0000 -------
All fixed, closing bug.

First Last Prev Next    No search results available      Search page      Enter new bug