From 1cca4d60367c89bcdeb2ee6f1d54ab6f393f289d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 5 May 2001 05:12:14 +0000 Subject: [PATCH] ChangeLog, dirblock.c: dirblock.c (ext2fs_read_dir_block): Check for an directory record length which isn't a multiple four, and treat that as an invalid. Scan the directory and return an error (EXT2_ET_DIR_CORRUPTED) if the directory records are orrupted. (ext2fs_write_dir_block): If while byte-swapping the directory block, if there's an error, abort and return EXT2_ET_DIR_CORRUPTED. --- lib/ext2fs/ChangeLog | 11 +++++++++++ lib/ext2fs/dirblock.c | 37 +++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 13d7299..3dfc275 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,14 @@ +2001-05-04 Theodore Tso + + * dirblock.c (ext2fs_read_dir_block): Check for an directory + record length which isn't a multiple four, and treat that + as an invalid. Scan the directory and return an error + (EXT2_ET_DIR_CORRUPTED) if the directory records are + corrupted. + (ext2fs_write_dir_block): If while byte-swapping the + directory block, if there's an error, abort and return + EXT2_ET_DIR_CORRUPTED. + 2001-05-02 Theodore Tso * ext2fs.h (EXT2_FLAG_IMAGE_FILE): Add new flag, and add diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c index cb274b7..dd9fe5f 100644 --- a/lib/ext2fs/dirblock.c +++ b/lib/ext2fs/dirblock.c @@ -30,23 +30,34 @@ errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, errcode_t retval; char *p, *end; struct ext2_dir_entry *dirent; + struct ext2_dir_entry_2 *dirent2; + unsigned int rec_len, do_swap; retval = io_channel_read_blk(fs->io, block, 1, buf); if (retval) return retval; - if ((fs->flags & (EXT2_FLAG_SWAP_BYTES| - EXT2_FLAG_SWAP_BYTES_READ)) == 0) - return 0; + do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES| + EXT2_FLAG_SWAP_BYTES_READ)) != 0; p = (char *) buf; end = (char *) buf + fs->blocksize; while (p < end-8) { - dirent = (struct ext2_dir_entry *) p; - dirent->inode = ext2fs_swab32(dirent->inode); - dirent->rec_len = ext2fs_swab16(dirent->rec_len); - dirent->name_len = ext2fs_swab16(dirent->name_len); - p += (dirent->rec_len < 8) ? 8 : dirent->rec_len; + dirent = (struct ext2_dir_entry_2 *) p; + if (do_swap) { + dirent->inode = ext2fs_swab32(dirent->inode); + dirent->rec_len = ext2fs_swab16(dirent->rec_len); + dirent->name_len = ext2fs_swab16(dirent->name_len); + } + rec_len = dirent->rec_len; + if ((rec_len < 8) || (rec_len % 4)) { + rec_len = 8; + retval = EXT2_ET_DIR_CORRUPTED; + } + dirent2 = dirent; + if ((dirent2->name_len +8) > dirent2->rec_len) + retval = EXT2_ET_DIR_CORRUPTED; + p += rec_len; } - return 0; + return retval; } errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, @@ -68,7 +79,12 @@ errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, end = buf + fs->blocksize; while (p < end) { dirent = (struct ext2_dir_entry *) p; - p += (dirent->rec_len < 8) ? 8 : dirent->rec_len; + if ((dirent->rec_len < 8) || + (dirent->rec_len % 4)) { + retval = EXT2_ET_DIR_CORRUPTED; + goto errout; + } + p += dirent->rec_len; dirent->inode = ext2fs_swab32(dirent->inode); dirent->rec_len = ext2fs_swab16(dirent->rec_len); dirent->name_len = ext2fs_swab16(dirent->name_len); @@ -76,6 +92,7 @@ errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, } else write_buf = (char *) inbuf; retval = io_channel_write_blk(fs->io, block, 1, write_buf); +errout: if (buf) ext2fs_free_mem((void **) &buf); return retval; -- 1.8.3.1