[2/4] ext2: fix rec_len overflow
- prevent rec_len from overflow with 64KB blocksize
Signed-off-by: Takashi Sato [EMAIL PROTECTED]
Signed-off-by: Mingming Cao [EMAIL PROTECTED]
Signed-off-by: Christoph Lameter [EMAIL PROTECTED]
---
fs/ext2/dir.c | 46 --
include/linux/ext2_fs.h | 13 +
2 files changed, 49 insertions(+), 10 deletions(-)
Index: linux-2.6.23-rc8-mm1/fs/ext2/dir.c
===
--- linux-2.6.23-rc8-mm1.orig/fs/ext2/dir.c 2007-09-25 15:59:34.0
-0700
+++ linux-2.6.23-rc8-mm1/fs/ext2/dir.c 2007-09-25 16:02:51.0 -0700
@@ -105,9 +105,9 @@ static void ext2_check_page(struct page
goto out;
}
for (offs = 0; offs = limit - EXT2_DIR_REC_LEN(1); offs += rec_len) {
+ offs = EXT2_DIR_ADJUST_TAIL_OFFS(offs, chunk_size);
p = (ext2_dirent *)(kaddr + offs);
rec_len = le16_to_cpu(p-rec_len);
-
if (rec_len EXT2_DIR_REC_LEN(1))
goto Eshort;
if (rec_len 3)
@@ -119,6 +119,7 @@ static void ext2_check_page(struct page
if (le32_to_cpu(p-inode) max_inumber)
goto Einumber;
}
+ offs = EXT2_DIR_ADJUST_TAIL_OFFS(offs, chunk_size);
if (offs != limit)
goto Eend;
out:
@@ -294,6 +295,7 @@ ext2_readdir (struct file * filp, void *
de = (ext2_dirent *)(kaddr+offset);
limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1);
for ( ;(char*)de = limit; de = ext2_next_entry(de)) {
+ de = EXT2_DIR_ADJUST_TAIL_ADDR(kaddr, de,
sb-s_blocksize);
if (de-rec_len == 0) {
ext2_error(sb, __FUNCTION__,
zero-length directory entry);
@@ -316,8 +318,10 @@ ext2_readdir (struct file * filp, void *
return 0;
}
}
+ filp-f_pos = EXT2_DIR_ADJUST_TAIL_OFFS(filp-f_pos,
sb-s_blocksize);
filp-f_pos += le16_to_cpu(de-rec_len);
}
+ filp-f_pos = EXT2_DIR_ADJUST_TAIL_OFFS(filp-f_pos,
sb-s_blocksize);
ext2_put_page(page);
}
return 0;
@@ -354,13 +358,14 @@ struct ext2_dir_entry_2 * ext2_find_entr
start = 0;
n = start;
do {
- char *kaddr;
+ char *kaddr, *page_start;
page = ext2_get_page(dir, n);
if (!IS_ERR(page)) {
- kaddr = page_address(page);
+ kaddr = page_start = page_address(page);
de = (ext2_dirent *) kaddr;
kaddr += ext2_last_byte(dir, n) - reclen;
while ((char *) de = kaddr) {
+ de = EXT2_DIR_ADJUST_TAIL_ADDR(page_start, de,
dir-i_sb-s_blocksize);
if (de-rec_len == 0) {
ext2_error(dir-i_sb, __FUNCTION__,
zero-length directory entry);
@@ -428,6 +433,7 @@ void ext2_set_link(struct inode *dir, st
unsigned len = le16_to_cpu(de-rec_len);
int err;
+ len = EXT2_DIR_ADJUST_TAIL_OFFS(pos, len);
lock_page(page);
err = __ext2_write_begin(NULL, page-mapping, pos, len,
AOP_FLAG_UNINTERRUPTIBLE, page, NULL);
@@ -459,6 +465,7 @@ int ext2_add_link (struct dentry *dentry
char *kaddr;
loff_t pos;
int err;
+ char *page_start = NULL;
/*
* We take care of directory expansion in the same loop.
@@ -473,16 +480,29 @@ int ext2_add_link (struct dentry *dentry
if (IS_ERR(page))
goto out;
lock_page(page);
- kaddr = page_address(page);
+ kaddr = page_start = page_address(page);
dir_end = kaddr + ext2_last_byte(dir, n);
de = (ext2_dirent *)kaddr;
- kaddr += PAGE_CACHE_SIZE - reclen;
+ if (chunk_size EXT2_DIR_MAX_REC_LEN)
+ kaddr += PAGE_CACHE_SIZE - reclen;
+ else
+ kaddr += PAGE_CACHE_SIZE -
+ (chunk_size - EXT2_DIR_MAX_REC_LEN) - reclen;
+
while ((char *)de = kaddr) {
+ de = EXT2_DIR_ADJUST_TAIL_ADDR(page_start, de,
chunk_size);
if ((char *)de == dir_end) {
/* We hit i_size */
name_len = 0;
- rec_len = chunk_size;
- de-rec_len =