From: Konstantin Komarov <almaz.alexandrovich@xxxxxxxxxxxxxxxxxxxx> commit 91a4b1ee78cb ("fs/ntfs3: Fix shift-out-of-bounds in ntfs_fill_super") This patch is a backport and fixes an UBSAN warning about shift-out-of-bounds in ntfs_fill_super() function of the NTFS3 driver. The original code incorrectly calculated MFT record size, causing undefined behavior when performing bit shifts with values that exceed type limits. The fix has been verified by executing the syzkaller reproducer test case. After applying this patch, the system successfully handles the test case without kernel panic or UBSAN warnings. Bug: https://syzkaller.appspot.com/bug?extid=010986becd65dbf9464b Reported-by: syzbot+010986becd65dbf9464b@xxxxxxxxxxxxxxxxxxxxxxxxx Cc: <stable@xxxxxxxxxxxxxxx> Signed-off-by: Konstantin Komarov <almaz.alexandrovich@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Miguel Garcia Roman <miguelgarciaroman8@xxxxxxxxx> (cherry picked from commit 91a4b1ee78cb100b19b70f077c247f211110348f) --- fs/ntfs3/ntfs_fs.h | 2 ++ fs/ntfs3/super.c | 63 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 7b46926e920c..c5ef0e0cdf59 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -43,9 +43,11 @@ enum utf16_endian; #define MINUS_ONE_T ((size_t)(-1)) /* Biggest MFT / smallest cluster */ #define MAXIMUM_BYTES_PER_MFT 4096 +#define MAXIMUM_SHIFT_BYTES_PER_MFT 12 #define NTFS_BLOCKS_PER_MFT_RECORD (MAXIMUM_BYTES_PER_MFT / 512) #define MAXIMUM_BYTES_PER_INDEX 4096 +#define MAXIMUM_SHIFT_BYTES_PER_INDEX 12 #define NTFS_BLOCKS_PER_INODE (MAXIMUM_BYTES_PER_INDEX / 512) /* NTFS specific error code when fixup failed. */ diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 78b086527331..abab388e413f 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -680,7 +680,7 @@ static u32 true_sectors_per_clst(const struct NTFS_BOOT *boot) * ntfs_init_from_boot - Init internal info from on-disk boot sector. */ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, - u64 dev_size) + u64 dev_size) { struct ntfs_sb_info *sbi = sb->s_fs_info; int err; @@ -705,12 +705,12 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, /* 0x55AA is not mandaroty. Thanks Maxim Suhanov*/ /*if (0x55 != boot->boot_magic[0] || 0xAA != boot->boot_magic[1]) - * goto out; + * goto out; */ boot_sector_size = (u32)boot->bytes_per_sector[1] << 8; if (boot->bytes_per_sector[0] || boot_sector_size < SECTOR_SIZE || - !is_power_of_2(boot_sector_size)) { + !is_power_of_2(boot_sector_size)) { goto out; } @@ -733,15 +733,49 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, /* Check MFT record size. */ if ((boot->record_size < 0 && - SECTOR_SIZE > (2U << (-boot->record_size))) || - (boot->record_size >= 0 && !is_power_of_2(boot->record_size))) { + SECTOR_SIZE > (2U << (-boot->record_size))) || + (boot->record_size >= 0 && !is_power_of_2(boot->record_size))) { + goto out; + } + + /* Calculate cluster size */ + sbi->cluster_size = boot_sector_size * sct_per_clst; + sbi->cluster_bits = blksize_bits(sbi->cluster_size); + + if (boot->record_size >= 0) { + record_size = (u32)boot->record_size << sbi->cluster_bits; + } else if (-boot->record_size <= MAXIMUM_SHIFT_BYTES_PER_MFT) { + record_size = 1u << (-boot->record_size); + } else { + ntfs_err(sb, "%s: invalid record size %d.", "NTFS", + boot->record_size); + goto out; + } + + sbi->record_size = record_size; + sbi->record_bits = blksize_bits(record_size); + sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes + + if (record_size > MAXIMUM_BYTES_PER_MFT) { + ntfs_err(sb, "Unsupported bytes per MFT record %u.", + record_size); + goto out; + } + + if (boot->index_size >= 0) { + sbi->index_size = (u32)boot->index_size << sbi->cluster_bits; + } else if (-boot->index_size <= MAXIMUM_SHIFT_BYTES_PER_INDEX) { + sbi->index_size = 1u << (-boot->index_size); + } else { + ntfs_err(sb, "%s: invalid index size %d.", "NTFS", + boot->index_size); goto out; } /* Check index record size. */ if ((boot->index_size < 0 && - SECTOR_SIZE > (2U << (-boot->index_size))) || - (boot->index_size >= 0 && !is_power_of_2(boot->index_size))) { + SECTOR_SIZE > (2U << (-boot->index_size))) || + (boot->index_size >= 0 && !is_power_of_2(boot->index_size))) { goto out; } @@ -762,9 +796,6 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, dev_size += sector_size - 1; } - sbi->cluster_size = boot_sector_size * sct_per_clst; - sbi->cluster_bits = blksize_bits(sbi->cluster_size); - sbi->mft.lbo = mlcn << sbi->cluster_bits; sbi->mft.lbo2 = mlcn2 << sbi->cluster_bits; @@ -785,9 +816,9 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, sbi->cluster_mask = sbi->cluster_size - 1; sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask; sbi->record_size = record_size = boot->record_size < 0 - ? 1 << (-boot->record_size) - : (u32)boot->record_size - << sbi->cluster_bits; + ? 1 << (-boot->record_size) + : (u32)boot->record_size + << sbi->cluster_bits; if (record_size > MAXIMUM_BYTES_PER_MFT || record_size < SECTOR_SIZE) goto out; @@ -801,8 +832,8 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, ALIGN(sizeof(enum ATTR_TYPE), 8); sbi->index_size = boot->index_size < 0 - ? 1u << (-boot->index_size) - : (u32)boot->index_size << sbi->cluster_bits; + ? 1u << (-boot->index_size) + : (u32)boot->index_size << sbi->cluster_bits; sbi->volume.ser_num = le64_to_cpu(boot->serial_num); @@ -879,6 +910,8 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, return err; } + + /* * ntfs_fill_super - Try to mount. */ -- 2.34.1