Commit f2966632 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] rock: handle directory overflows

Handle the case where the variable-sized part of a rock-ridge directory entry
overhangs the end of the buffer which we allocated for it.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 642217c1
...@@ -126,6 +126,66 @@ out: ...@@ -126,6 +126,66 @@ out:
return ret; return ret;
} }
/*
* We think there's a record of type `sig' at rs->chr. Parse the signature
* and make sure that there's really room for a record of that type.
*/
static int rock_check_overflow(struct rock_state *rs, int sig)
{
int len;
switch (sig) {
case SIG('S', 'P'):
len = sizeof(struct SU_SP_s);
break;
case SIG('C', 'E'):
len = sizeof(struct SU_CE_s);
break;
case SIG('E', 'R'):
len = sizeof(struct SU_ER_s);
break;
case SIG('R', 'R'):
len = sizeof(struct RR_RR_s);
break;
case SIG('P', 'X'):
len = sizeof(struct RR_PX_s);
break;
case SIG('P', 'N'):
len = sizeof(struct RR_PN_s);
break;
case SIG('S', 'L'):
len = sizeof(struct RR_SL_s);
break;
case SIG('N', 'M'):
len = sizeof(struct RR_NM_s);
break;
case SIG('C', 'L'):
len = sizeof(struct RR_CL_s);
break;
case SIG('P', 'L'):
len = sizeof(struct RR_PL_s);
break;
case SIG('T', 'F'):
len = sizeof(struct RR_TF_s);
break;
case SIG('Z', 'F'):
len = sizeof(struct RR_ZF_s);
break;
default:
len = 0;
break;
}
len += offsetof(struct rock_ridge, u);
if (len > rs->len) {
printk(KERN_NOTICE "rock: directory entry would overflow "
"storage\n");
printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n",
sig, len, rs->len);
return -EIO;
}
return 0;
}
/* /*
* return length of name field; 0: not found, -1: to be ignored * return length of name field; 0: not found, -1: to be ignored
*/ */
...@@ -152,10 +212,12 @@ repeat: ...@@ -152,10 +212,12 @@ repeat:
if (rr->len < 3) if (rr->len < 3)
goto out; /* Something got screwed up here */ goto out; /* Something got screwed up here */
sig = isonum_721(rs.chr); sig = isonum_721(rs.chr);
if (rock_check_overflow(&rs, sig))
goto eio;
rs.chr += rr->len; rs.chr += rr->len;
rs.len -= rr->len; rs.len -= rr->len;
if (rs.len < 0) if (rs.len < 0)
goto out; /* corrupted isofs */ goto eio; /* corrupted isofs */
switch (sig) { switch (sig) {
case SIG('R', 'R'): case SIG('R', 'R'):
...@@ -213,6 +275,9 @@ repeat: ...@@ -213,6 +275,9 @@ repeat:
out: out:
kfree(rs.buffer); kfree(rs.buffer);
return ret; return ret;
eio:
ret = -EIO;
goto out;
} }
static int static int
...@@ -245,10 +310,12 @@ repeat: ...@@ -245,10 +310,12 @@ repeat:
if (rr->len < 3) if (rr->len < 3)
goto out; /* Something got screwed up here */ goto out; /* Something got screwed up here */
sig = isonum_721(rs.chr); sig = isonum_721(rs.chr);
if (rock_check_overflow(&rs, sig))
goto eio;
rs.chr += rr->len; rs.chr += rr->len;
rs.len -= rr->len; rs.len -= rr->len;
if (rs.len < 0) if (rs.len < 0)
goto out; /* corrupted isofs */ goto eio; /* corrupted isofs */
switch (sig) { switch (sig) {
#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */
...@@ -479,6 +546,9 @@ repeat: ...@@ -479,6 +546,9 @@ repeat:
out: out:
kfree(rs.buffer); kfree(rs.buffer);
return ret; return ret;
eio:
ret = -EIO;
goto out;
} }
static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
...@@ -618,6 +688,8 @@ repeat: ...@@ -618,6 +688,8 @@ repeat:
if (rr->len < 3) if (rr->len < 3)
goto out; /* Something got screwed up here */ goto out; /* Something got screwed up here */
sig = isonum_721(rs.chr); sig = isonum_721(rs.chr);
if (rock_check_overflow(&rs, sig))
goto out;
rs.chr += rr->len; rs.chr += rr->len;
rs.len -= rr->len; rs.len -= rr->len;
if (rs.len < 0) if (rs.len < 0)
......
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