[PATCH] isofs: Handle corupted rock-ridge info slightly better.

Linux Kernel Mailing List <[email protected]> Fri, 25 Mar 2005 23:50:06 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1483, 2005/03/25 20:50:06-03:00, [email protected]

	[PATCH] isofs: Handle corupted rock-ridge info slightly better.
	
	Michal Zalewski <[email protected]> discovers range checking flaws in
	iso9660 filesystem.
	
	http://marc.theaimsgroup.com/?l=bugtraq&m=111110067304783&w=2
	
	CAN-2005-0815 is assigned to this issue.
	
	From: Linus Torvalds <[email protected]>
	
	isofs: Handle corupted rock-ridge info slightly better.
	
	Keyword here being 'slightly'. The code is a mess.
	
	Signed-off-by: Chris Wright <[email protected]>



 rock.c |   21 ++++++++++++++-------
 1 files changed, 14 insertions(+), 7 deletions(-)


diff -Nru a/fs/isofs/rock.c b/fs/isofs/rock.c
--- a/fs/isofs/rock.c	2005-03-26 13:02:48 -08:00
+++ b/fs/isofs/rock.c	2005-03-26 13:02:48 -08:00
@@ -52,6 +52,7 @@
   if(LEN & 1) LEN++;						\
   CHR = ((unsigned char *) DE) + LEN;				\
   LEN = *((unsigned char *) DE) - LEN;                          \
+  if (LEN<0) LEN=0;                                             \
   if (inode->i_sb->u.isofs_sb.s_rock_offset!=-1)                \
   {                                                             \
      LEN-=inode->i_sb->u.isofs_sb.s_rock_offset;                \
@@ -172,12 +173,13 @@
     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'):
@@ -191,6 +193,7 @@
 	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
@@ -252,12 +255,13 @@
     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 */
@@ -523,7 +527,7 @@
 	struct rock_ridge *rr;
 
 	if (!inode->i_sb->u.isofs_sb.s_rock)
-		panic ("Cannot have symlink with high sierra variant of iso filesystem\n");
+		goto error;
 
 	block = inode->i_ino >> bufbits;
 	lock_kernel();
@@ -547,13 +551,15 @@
 	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'):
@@ -601,6 +607,7 @@
       fail:
 	brelse(bh);
 	unlock_kernel();
+      error:
 	SetPageError(page);
 	kunmap(page);
 	UnlockPage(page);