aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2020-02-15 19:10:01 -0500
committerTheodore Ts'o <tytso@mit.edu>2020-02-15 19:10:01 -0500
commit750bae1542b2acc374fcefbdaa7ff203e0ca0f9e (patch)
treeeb454a49112a6d35ca8079c057d854926084577b
parent7d25ea4628c0743a1b62e1884305fa283f2eb6e2 (diff)
downloade2fsprogs-750bae1542b2acc374fcefbdaa7ff203e0ca0f9e.tar.gz
libext2fs: avoid array buffer overruns caused by insane directory blocks
Reported-by: canardo909@gmx.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--lib/ext2fs/swapfs.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index e795278d8..a3d5d16ae 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -416,10 +416,11 @@ errcode_t ext2fs_dirent_swab_in2(ext2_filsys fs, char *buf,
errcode_t retval;
char *p, *end;
struct ext2_dir_entry *dirent;
- unsigned int name_len, rec_len;
+ unsigned int name_len, rec_len, left;
p = (char *) buf;
end = (char *) buf + size;
+ left = size;
while (p < end-8) {
dirent = (struct ext2_dir_entry *) p;
dirent->inode = ext2fs_swab32(dirent->inode);
@@ -436,6 +437,9 @@ errcode_t ext2fs_dirent_swab_in2(ext2_filsys fs, char *buf,
retval = EXT2_ET_DIR_CORRUPTED;
} else if (((name_len & 0xFF) + 8) > rec_len)
retval = EXT2_ET_DIR_CORRUPTED;
+ if (rec_len > left)
+ return EXT2_ET_DIR_CORRUPTED;
+ left -= rec_len;
p += rec_len;
}
@@ -452,11 +456,12 @@ errcode_t ext2fs_dirent_swab_out2(ext2_filsys fs, char *buf,
{
errcode_t retval;
char *p, *end;
- unsigned int rec_len;
+ unsigned int rec_len, left;
struct ext2_dir_entry *dirent;
p = buf;
end = buf + size;
+ left = size;
while (p < end) {
dirent = (struct ext2_dir_entry *) p;
retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
@@ -471,6 +476,9 @@ errcode_t ext2fs_dirent_swab_out2(ext2_filsys fs, char *buf,
dirent->inode = ext2fs_swab32(dirent->inode);
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
dirent->name_len = ext2fs_swab16(dirent->name_len);
+ if (rec_len > size)
+ return EXT2_ET_DIR_CORRUPTED;
+ size -= rec_len;
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
dirent->name_len = ext2fs_swab16(dirent->name_len);