vserver 1.9.5.x5
[linux-2.6.git] / fs / isofs / rock.c
index c09d4bd..8bdd3e4 100644 (file)
@@ -53,6 +53,7 @@
   if(LEN & 1) LEN++;                                           \
   CHR = ((unsigned char *) DE) + LEN;                          \
   LEN = *((unsigned char *) DE) - LEN;                          \
+  if (LEN<0) LEN=0;                                             \
   if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1)                \
   {                                                             \
      LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset;                \
@@ -62,7 +63,7 @@
 }                                     
 
 #define MAYBE_CONTINUE(LABEL,DEV) \
-  {if (buffer) kfree(buffer); \
+  {if (buffer) { kfree(buffer); buffer = NULL; } \
   if (cont_extent){ \
     int block, offset, offset1; \
     struct buffer_head * pbh; \
     offset1 = 0; \
     pbh = sb_bread(DEV->i_sb, block); \
     if(pbh){       \
+      if (offset > pbh->b_size || offset + cont_size > pbh->b_size){   \
+       brelse(pbh); \
+       goto out; \
+      } \
       memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
       brelse(pbh); \
       chr = (unsigned char *) buffer; \
@@ -103,12 +108,13 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
     struct rock_ridge * rr;
     int sig;
     
-    while (len > 1){ /* There may be one byte for padding somewhere */
+    while (len > 2){ /* There may be one byte for padding somewhere */
       rr = (struct rock_ridge *) chr;
-      if (rr->len == 0) goto out; /* Something got screwed up here */
+      if (rr->len < 3) goto out; /* Something got screwed up here */
       sig = isonum_721(chr);
       chr += rr->len; 
       len -= rr->len;
+      if (len < 0) goto out;   /* corrupted isofs */
 
       switch(sig){
       case SIG('R','R'):
@@ -122,6 +128,7 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
        break;
       case SIG('N','M'):
        if (truncate) break;
+       if (rr->len < 5) break;
         /*
         * If the flags are 2 or 4, this indicates '.' or '..'.
         * We don't want to do anything with this, because it
@@ -153,14 +160,17 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
     }
   }
   MAYBE_CONTINUE(repeat,inode);
+  if (buffer) kfree(buffer);
   return retnamlen; /* If 0, this file did not have a NM field */
  out:
   if(buffer) kfree(buffer);
   return 0;
 }
 
-int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
-                                   struct inode * inode,int regard_xa){
+static int
+parse_rock_ridge_inode_internal(struct iso_directory_record *de,
+                               struct inode *inode, int regard_xa)
+{
   int len;
   unsigned char * chr;
   int symlink_len = 0;
@@ -174,7 +184,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
      chr+=14;
      len-=14;
      if (len<0) len=0;
-   };
+   }
    
  repeat:
   {
@@ -183,12 +193,13 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
     struct rock_ridge * rr;
     int rootflag;
     
-    while (len > 1){ /* There may be one byte for padding somewhere */
+    while (len > 2){ /* There may be one byte for padding somewhere */
       rr = (struct rock_ridge *) chr;
-      if (rr->len == 0) goto out; /* Something got screwed up here */
+      if (rr->len < 3) goto out; /* Something got screwed up here */
       sig = isonum_721(chr);
       chr += rr->len; 
       len -= rr->len;
+      if (len < 0) goto out;   /* corrupted isofs */
       
       switch(sig){
 #ifndef CONFIG_ZISOFS          /* No flag for SF or ZF */
@@ -351,7 +362,6 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
     }
   }
   MAYBE_CONTINUE(repeat,inode);
-  return 0;
  out:
   if(buffer) kfree(buffer);
   return 0;
@@ -435,9 +445,9 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
        &&(ISOFS_SB(inode->i_sb)->s_rock==2))
      {
        result=parse_rock_ridge_inode_internal(de,inode,14);
-     };
+     }
    return result;
-};
+}
 
 /* readpage() for symlinks: reads symlink contents into the page and either
    makes it uptodate and returns 0 or returns error (-EIO) */
@@ -460,7 +470,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
        struct rock_ridge *rr;
 
        if (!ISOFS_SB(inode->i_sb)->s_rock)
-               panic ("Cannot have symlink with high sierra variant of iso filesystem\n");
+               goto error;
 
        block = ei->i_iget5_block;
        lock_kernel();
@@ -485,13 +495,15 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
        SETUP_ROCK_RIDGE(raw_inode, chr, len);
 
       repeat:
-       while (len > 1) { /* There may be one byte for padding somewhere */
+       while (len > 2) { /* There may be one byte for padding somewhere */
                rr = (struct rock_ridge *) chr;
-               if (rr->len == 0)
+               if (rr->len < 3)
                        goto out;       /* Something got screwed up here */
                sig = isonum_721(chr);
                chr += rr->len;
                len -= rr->len;
+               if (len < 0)
+                       goto out;       /* corrupted isofs */
 
                switch (sig) {
                case SIG('R', 'R'):
@@ -515,6 +527,8 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
                }
        }
        MAYBE_CONTINUE(repeat, inode);
+       if (buffer)
+               kfree(buffer);
 
        if (rpnt == link)
                goto fail;
@@ -539,6 +553,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
       fail:
        brelse(bh);
        unlock_kernel();
+      error:
        SetPageError(page);
        kunmap(page);
        unlock_page(page);