Commit 6b4e4b90 authored by Dave Jones's avatar Dave Jones Committed by Linus Torvalds

[PATCH] isofs buffer overflow fix

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.
parent 51af77db
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <asm/page.h>
#include "rock.h" #include "rock.h"
...@@ -358,7 +359,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de, ...@@ -358,7 +359,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
return 0; 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 slen;
int rootflag; int rootflag;
...@@ -370,16 +371,25 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr) ...@@ -370,16 +371,25 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
rootflag = 0; rootflag = 0;
switch (slp->flags & ~1) { switch (slp->flags & ~1) {
case 0: case 0:
if (slp->len > plimit - rpnt)
return NULL;
memcpy(rpnt, slp->text, slp->len); memcpy(rpnt, slp->text, slp->len);
rpnt+=slp->len; rpnt+=slp->len;
break; break;
case 2:
if (rpnt >= plimit)
return NULL;
*rpnt++='.';
break;
case 4: case 4:
if (2 > plimit - rpnt)
return NULL;
*rpnt++='.'; *rpnt++='.';
/* fallthru */
case 2:
*rpnt++='.'; *rpnt++='.';
break; break;
case 8: case 8:
if (rpnt >= plimit)
return NULL;
rootflag = 1; rootflag = 1;
*rpnt++='/'; *rpnt++='/';
break; break;
...@@ -396,17 +406,23 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr) ...@@ -396,17 +406,23 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
* If there is another SL record, and this component * If there is another SL record, and this component
* record isn't continued, then add a slash. * 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++='/'; *rpnt++='/';
}
break; break;
} }
/* /*
* If this component record isn't continued, then append a '/'. * 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++='/'; *rpnt++='/';
}
} }
return rpnt; return rpnt;
} }
...@@ -487,7 +503,10 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) ...@@ -487,7 +503,10 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
CHECK_SP(goto out); CHECK_SP(goto out);
break; break;
case SIG('S', 'L'): 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; break;
case SIG('C', 'E'): case SIG('C', 'E'):
/* This tells is if there is a continuation record */ /* This tells is if there is a continuation record */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment