]> git.hungrycats.org Git - linux/commitdiff
[PATCH] isofs buffer overflow fix
authorDave Jones <davej@redhat.com>
Wed, 14 Apr 2004 03:21:28 +0000 (20:21 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 14 Apr 2004 03:21:28 +0000 (20:21 -0700)
Merged in 2.4, and various vendor kernels..

  iDefense reported a buffer overflow flaw in the ISO9660 filesystem code.
  An attacker could create a malicious filesystem in such a way that they
  could gain root privileges if that filesystem is mounted. The Common
  Vulnerabilities and Exposures project (cve.mitre.org) has assigned the name
  CAN-2004-0109 to this issue.

Ernie Petrides came up with the following patch which I fixed up a slight
reject in to apply to 2.6. Otherwise, unchanged from the 2.4 patch.

fs/isofs/rock.c

index ec218349feb126fcf110c93a0b0ec498f3564ef4..088acdcc95d9bb01347da7a01963a2ef447e33cf 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
+#include <asm/page.h>
 
 #include "rock.h"
 
@@ -358,7 +359,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
   return 0;
 }
 
-static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
+static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
 {
        int slen;
        int rootflag;
@@ -370,16 +371,25 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
                rootflag = 0;
                switch (slp->flags & ~1) {
                case 0:
+                       if (slp->len > plimit - rpnt)
+                               return NULL;
                        memcpy(rpnt, slp->text, slp->len);
                        rpnt+=slp->len;
                        break;
+               case 2:
+                       if (rpnt >= plimit)
+                               return NULL;
+                       *rpnt++='.';
+                       break;
                case 4:
+                       if (2 > plimit - rpnt)
+                               return NULL;
                        *rpnt++='.';
-                       /* fallthru */
-               case 2:
                        *rpnt++='.';
                        break;
                case 8:
+                       if (rpnt >= plimit)
+                               return NULL;
                        rootflag = 1;
                        *rpnt++='/';
                        break;
@@ -396,17 +406,23 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
                         * If there is another SL record, and this component
                         * record isn't continued, then add a slash.
                         */
-                       if ((!rootflag) && (rr->u.SL.flags & 1) && !(oldslp->flags & 1))
+                       if ((!rootflag) && (rr->u.SL.flags & 1) &&
+                           !(oldslp->flags & 1)) {
+                               if (rpnt >= plimit)
+                                       return NULL;
                                *rpnt++='/';
+                       }
                        break;
                }
 
                /*
                 * If this component record isn't continued, then append a '/'.
                 */
-               if (!rootflag && !(oldslp->flags & 1))
+               if (!rootflag && !(oldslp->flags & 1)) {
+                       if (rpnt >= plimit)
+                               return NULL;
                        *rpnt++='/';
-
+               }
        }
        return rpnt;
 }
@@ -487,7 +503,10 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
                        CHECK_SP(goto out);
                        break;
                case SIG('S', 'L'):
-                       rpnt = get_symlink_chunk(rpnt, rr);
+                       rpnt = get_symlink_chunk(rpnt, rr,
+                                                link + (PAGE_SIZE - 1));
+                       if (rpnt == NULL)
+                               goto out;
                        break;
                case SIG('C', 'E'):
                        /* This tells is if there is a continuation record */