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>
---

 fs/isofs/rock.c |   13 +++++++++++++
 1 files changed, 13 insertions(+)

diff -puN fs/isofs/rock.c~rock-handle-corrupted-directories fs/isofs/rock.c
--- 25/fs/isofs/rock.c~rock-handle-corrupted-directories	2005-04-26 19:27:18.001990024 -0700
+++ 25-akpm/fs/isofs/rock.c	2005-04-26 19:27:18.005989416 -0700
@@ -81,9 +81,22 @@ static void init_rock_state(struct rock_
 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;
 
_