diff options
author | Andrew Morton <akpm@osdl.org> | 2005-06-21 17:16:50 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 19:07:38 -0700 |
commit | e595447e177b39aa6c96baaa57b30cde2d8b9df7 (patch) | |
tree | 7c6c1be2e623fc3cefb1a0afcb51247293a393eb /fs/isofs | |
parent | 9eb7f2c67c41d2cd730aedcd23e5baca09211d03 (diff) | |
download | lwn-e595447e177b39aa6c96baaa57b30cde2d8b9df7.tar.gz lwn-e595447e177b39aa6c96baaa57b30cde2d8b9df7.zip |
[PATCH] rock.c: handle corrupted directories
The bug in rock.c is that it's totally trusting of the contents of the
directories. If the directory says there's a continuation 10000 bytes into
this 4k block then we cheerily poke around in memory we don't own and oops.
So change rock_continue() to apply various sanity checks, at least ensuring
that the offset+length remain within the bounds for the header part of a
struct rock_ridge directory entry.
Note that the kernel can still overindex the buffer due to the variable size
of the rock-ridge directory entries. We cannot check that in rock_continue()
unless we go parse the directory entry's signature and work out its size.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/isofs')
-rw-r--r-- | fs/isofs/rock.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 977dd7009c07..9a81830abff8 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -81,9 +81,22 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) static int rock_continue(struct rock_state *rs) { int ret = 1; + int blocksize = 1 << rs->inode->i_blkbits; + const int min_de_size = offsetof(struct rock_ridge, u); kfree(rs->buffer); rs->buffer = NULL; + + if ((unsigned)rs->cont_offset > blocksize - min_de_size || + (unsigned)rs->cont_size > blocksize || + (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) { + printk(KERN_NOTICE "rock: corrupted directory entry. " + "extent=%d, offset=%d, size=%d\n", + rs->cont_extent, rs->cont_offset, rs->cont_size); + ret = -EIO; + goto out; + } + if (rs->cont_extent) { struct buffer_head *bh; |