fat: add simple validation for directory inode
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Wed, 20 Jan 2016 22:59:38 +0000 (14:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Jan 2016 01:09:18 +0000 (17:09 -0800)
This detects simple corruption cases of directory, and tries to avoid
further damage to user data.

And performance impact of this validation should be very low, or not
measurable.

Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
Tested-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/fat/inode.c

index 3ac9078fde65f87ef3b434d21af0cb78211f3953..08ef5fd0d5029326430b76f0b28d34d7cd52255f 100644 (file)
@@ -449,6 +449,24 @@ static int fat_calc_dir_size(struct inode *inode)
        return 0;
 }
 
+static int fat_validate_dir(struct inode *dir)
+{
+       struct super_block *sb = dir->i_sb;
+
+       if (dir->i_nlink < 2) {
+               /* Directory should have "."/".." entries at least. */
+               fat_fs_error(sb, "corrupted directory (invalid entries)");
+               return -EIO;
+       }
+       if (MSDOS_I(dir)->i_start == 0 ||
+           MSDOS_I(dir)->i_start == MSDOS_SB(sb)->root_cluster) {
+               /* Directory should point valid cluster. */
+               fat_fs_error(sb, "corrupted directory (invalid i_start)");
+               return -EIO;
+       }
+       return 0;
+}
+
 /* doesn't deal with root inode */
 int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 {
@@ -475,6 +493,10 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
                MSDOS_I(inode)->mmu_private = inode->i_size;
 
                set_nlink(inode, fat_subdirs(inode));
+
+               error = fat_validate_dir(inode);
+               if (error < 0)
+                       return error;
        } else { /* not a directory */
                inode->i_generation |= 1;
                inode->i_mode = fat_make_mode(sbi, de->attr,