-----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmaX3kgACgkQnJ2qBz9k
 QNnvxQgAtLLYyHnK9cF0UUCyLo9BwFU7jiOBnM1NCSlUjE2Z8JTKwhDOAkQNyua5
 0q5afk5hl5uopazA2DQZgc9UvRDfo94uGhH4Qz9t1cJ08z+hGglD473NHSb6jjE8
 Ibc6iUFKlmZ5jAD1n+6RBY5YJTpFYtS4bxBegx7aw7WdAFQOrQAc0zfmj0xw/Pzc
 yQUxABw/mSIQAoGSZ3iagZ8tYWaKlTn0vm0HAcqesyZ0ruYGV4DFw8SPyBWaENvw
 ViAyZa/qntC4sfWCKqla0TluutnET9ZfoASttPNfY6bcYAJGGRAkueIMugQWcoCE
 jw2vgtaYTCiCAyCFaRHO74v7AcUSKg==
 =Ol3a
 -----END PGP SIGNATURE-----

Merge tag 'fs_for_v6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull udf, ext2, isofs fixes and cleanups from Jan Kara:

 - A few UDF cleanups and fixes for handling corrupted filesystems

 - ext2 fix for handling of corrupted filesystem

 - isofs module description

 - jbd2 module description

* tag 'fs_for_v6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  ext2: Verify bitmap and itable block numbers before using them
  udf: prevent integer overflow in udf_bitmap_free_blocks()
  udf: Avoid excessive partition lengths
  udf: Drop load_block_bitmap() wrapper
  udf: Avoid using corrupted block bitmap buffer
  udf: Fix bogus checksum computation in udf_rename()
  udf: Fix lock ordering in udf_evict_inode()
  udf: Drop pointless IS_IMMUTABLE and IS_APPEND check
  isofs: add missing MODULE_DESCRIPTION()
  jbd2: add missing MODULE_DESCRIPTION()
This commit is contained in:
Linus Torvalds 2024-07-17 13:11:42 -07:00
commit 8b0f0bb27c
8 changed files with 63 additions and 59 deletions

View File

@ -77,26 +77,33 @@ static int ext2_valid_block_bitmap(struct super_block *sb,
ext2_grpblk_t next_zero_bit; ext2_grpblk_t next_zero_bit;
ext2_fsblk_t bitmap_blk; ext2_fsblk_t bitmap_blk;
ext2_fsblk_t group_first_block; ext2_fsblk_t group_first_block;
ext2_grpblk_t max_bit;
group_first_block = ext2_group_first_block_no(sb, block_group); group_first_block = ext2_group_first_block_no(sb, block_group);
max_bit = ext2_group_last_block_no(sb, block_group) - group_first_block;
/* check whether block bitmap block number is set */ /* check whether block bitmap block number is set */
bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
offset = bitmap_blk - group_first_block; offset = bitmap_blk - group_first_block;
if (!ext2_test_bit(offset, bh->b_data)) if (offset < 0 || offset > max_bit ||
!ext2_test_bit(offset, bh->b_data))
/* bad block bitmap */ /* bad block bitmap */
goto err_out; goto err_out;
/* check whether the inode bitmap block number is set */ /* check whether the inode bitmap block number is set */
bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
offset = bitmap_blk - group_first_block; offset = bitmap_blk - group_first_block;
if (!ext2_test_bit(offset, bh->b_data)) if (offset < 0 || offset > max_bit ||
!ext2_test_bit(offset, bh->b_data))
/* bad block bitmap */ /* bad block bitmap */
goto err_out; goto err_out;
/* check whether the inode table block number is set */ /* check whether the inode table block number is set */
bitmap_blk = le32_to_cpu(desc->bg_inode_table); bitmap_blk = le32_to_cpu(desc->bg_inode_table);
offset = bitmap_blk - group_first_block; offset = bitmap_blk - group_first_block;
if (offset < 0 || offset > max_bit ||
offset + EXT2_SB(sb)->s_itb_per_group - 1 > max_bit)
goto err_out;
next_zero_bit = ext2_find_next_zero_bit(bh->b_data, next_zero_bit = ext2_find_next_zero_bit(bh->b_data,
offset + EXT2_SB(sb)->s_itb_per_group, offset + EXT2_SB(sb)->s_itb_per_group,
offset); offset);

View File

@ -1617,4 +1617,5 @@ static void __exit exit_iso9660_fs(void)
module_init(init_iso9660_fs) module_init(init_iso9660_fs)
module_exit(exit_iso9660_fs) module_exit(exit_iso9660_fs)
MODULE_DESCRIPTION("ISO 9660 CDROM file system support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -3181,6 +3181,7 @@ static void __exit journal_exit(void)
jbd2_journal_destroy_caches(); jbd2_journal_destroy_caches();
} }
MODULE_DESCRIPTION("Generic filesystem journal-writing module");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(journal_init); module_init(journal_init);
module_exit(journal_exit); module_exit(journal_exit);

View File

@ -18,6 +18,7 @@
#include "udfdecl.h" #include "udfdecl.h"
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/overflow.h>
#include "udf_i.h" #include "udf_i.h"
#include "udf_sb.h" #include "udf_sb.h"
@ -64,14 +65,18 @@ static int read_block_bitmap(struct super_block *sb,
} }
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
if (udf_test_bit(i + off, bh->b_data)) if (udf_test_bit(i + off, bh->b_data)) {
bitmap->s_block_bitmap[bitmap_nr] =
ERR_PTR(-EFSCORRUPTED);
brelse(bh);
return -EFSCORRUPTED; return -EFSCORRUPTED;
}
return 0; return 0;
} }
static int __load_block_bitmap(struct super_block *sb, static int load_block_bitmap(struct super_block *sb,
struct udf_bitmap *bitmap, struct udf_bitmap *bitmap,
unsigned int block_group) unsigned int block_group)
{ {
int retval = 0; int retval = 0;
int nr_groups = bitmap->s_nr_groups; int nr_groups = bitmap->s_nr_groups;
@ -81,8 +86,15 @@ static int __load_block_bitmap(struct super_block *sb,
block_group, nr_groups); block_group, nr_groups);
} }
if (bitmap->s_block_bitmap[block_group]) if (bitmap->s_block_bitmap[block_group]) {
/*
* The bitmap failed verification in the past. No point in
* trying again.
*/
if (IS_ERR(bitmap->s_block_bitmap[block_group]))
return PTR_ERR(bitmap->s_block_bitmap[block_group]);
return block_group; return block_group;
}
retval = read_block_bitmap(sb, bitmap, block_group, block_group); retval = read_block_bitmap(sb, bitmap, block_group, block_group);
if (retval < 0) if (retval < 0)
@ -91,23 +103,6 @@ static int __load_block_bitmap(struct super_block *sb,
return block_group; return block_group;
} }
static inline int load_block_bitmap(struct super_block *sb,
struct udf_bitmap *bitmap,
unsigned int block_group)
{
int slot;
slot = __load_block_bitmap(sb, bitmap, block_group);
if (slot < 0)
return slot;
if (!bitmap->s_block_bitmap[slot])
return -EIO;
return slot;
}
static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt) static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
{ {
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
@ -129,7 +124,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
{ {
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct udf_part_map *partmap;
unsigned long block; unsigned long block;
unsigned long block_group; unsigned long block_group;
unsigned long bit; unsigned long bit;
@ -138,19 +132,9 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
unsigned long overflow; unsigned long overflow;
mutex_lock(&sbi->s_alloc_mutex); mutex_lock(&sbi->s_alloc_mutex);
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; /* We make sure this cannot overflow when mounting the filesystem */
if (bloc->logicalBlockNum + count < count ||
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
udf_debug("%u < %d || %u + %u > %u\n",
bloc->logicalBlockNum, 0,
bloc->logicalBlockNum, count,
partmap->s_partition_len);
goto error_return;
}
block = bloc->logicalBlockNum + offset + block = bloc->logicalBlockNum + offset +
(sizeof(struct spaceBitmapDesc) << 3); (sizeof(struct spaceBitmapDesc) << 3);
do { do {
overflow = 0; overflow = 0;
block_group = block >> (sb->s_blocksize_bits + 3); block_group = block >> (sb->s_blocksize_bits + 3);
@ -380,7 +364,6 @@ static void udf_table_free_blocks(struct super_block *sb,
uint32_t count) uint32_t count)
{ {
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *partmap;
uint32_t start, end; uint32_t start, end;
uint32_t elen; uint32_t elen;
struct kernel_lb_addr eloc; struct kernel_lb_addr eloc;
@ -389,16 +372,6 @@ static void udf_table_free_blocks(struct super_block *sb,
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
mutex_lock(&sbi->s_alloc_mutex); mutex_lock(&sbi->s_alloc_mutex);
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
if (bloc->logicalBlockNum + count < count ||
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
udf_debug("%u < %d || %u + %u > %u\n",
bloc->logicalBlockNum, 0,
bloc->logicalBlockNum, count,
partmap->s_partition_len);
goto error_return;
}
iinfo = UDF_I(table); iinfo = UDF_I(table);
udf_add_free_space(sb, sbi->s_partition, count); udf_add_free_space(sb, sbi->s_partition, count);
@ -673,6 +646,17 @@ void udf_free_blocks(struct super_block *sb, struct inode *inode,
{ {
uint16_t partition = bloc->partitionReferenceNum; uint16_t partition = bloc->partitionReferenceNum;
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
uint32_t blk;
if (check_add_overflow(bloc->logicalBlockNum, offset, &blk) ||
check_add_overflow(blk, count, &blk) ||
bloc->logicalBlockNum + count > map->s_partition_len) {
udf_debug("Invalid request to free blocks: (%d, %u), off %u, "
"len %u, partition len %u\n",
partition, bloc->logicalBlockNum, offset, count,
map->s_partition_len);
return;
}
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) { if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap, udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,

View File

@ -232,7 +232,9 @@ static int udf_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
if ((attr->ia_valid & ATTR_SIZE) && if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) { attr->ia_size != i_size_read(inode)) {
filemap_invalidate_lock(inode->i_mapping);
error = udf_setsize(inode, attr->ia_size); error = udf_setsize(inode, attr->ia_size);
filemap_invalidate_unlock(inode->i_mapping);
if (error) if (error)
return error; return error;
} }

View File

@ -1247,10 +1247,7 @@ int udf_setsize(struct inode *inode, loff_t newsize)
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode))) S_ISLNK(inode->i_mode)))
return -EINVAL; return -EINVAL;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return -EPERM;
filemap_invalidate_lock(inode->i_mapping);
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
if (newsize > inode->i_size) { if (newsize > inode->i_size) {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
@ -1263,11 +1260,11 @@ int udf_setsize(struct inode *inode, loff_t newsize)
} }
err = udf_expand_file_adinicb(inode); err = udf_expand_file_adinicb(inode);
if (err) if (err)
goto out_unlock; return err;
} }
err = udf_extend_file(inode, newsize); err = udf_extend_file(inode, newsize);
if (err) if (err)
goto out_unlock; return err;
set_size: set_size:
truncate_setsize(inode, newsize); truncate_setsize(inode, newsize);
} else { } else {
@ -1285,14 +1282,14 @@ set_size:
err = block_truncate_page(inode->i_mapping, newsize, err = block_truncate_page(inode->i_mapping, newsize,
udf_get_block); udf_get_block);
if (err) if (err)
goto out_unlock; return err;
truncate_setsize(inode, newsize); truncate_setsize(inode, newsize);
down_write(&iinfo->i_data_sem); down_write(&iinfo->i_data_sem);
udf_clear_extent_cache(inode); udf_clear_extent_cache(inode);
err = udf_truncate_extents(inode); err = udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
if (err) if (err)
goto out_unlock; return err;
} }
update_time: update_time:
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
@ -1300,8 +1297,6 @@ update_time:
udf_sync_inode(inode); udf_sync_inode(inode);
else else
mark_inode_dirty(inode); mark_inode_dirty(inode);
out_unlock:
filemap_invalidate_unlock(inode->i_mapping);
return err; return err;
} }

View File

@ -876,8 +876,6 @@ static int udf_rename(struct mnt_idmap *idmap, struct inode *old_dir,
if (has_diriter) { if (has_diriter) {
diriter.fi.icb.extLocation = diriter.fi.icb.extLocation =
cpu_to_lelb(UDF_I(new_dir)->i_location); cpu_to_lelb(UDF_I(new_dir)->i_location);
udf_update_tag((char *)&diriter.fi,
udf_dir_entry_len(&diriter.fi));
udf_fiiter_write_fi(&diriter, NULL); udf_fiiter_write_fi(&diriter, NULL);
udf_fiiter_release(&diriter); udf_fiiter_release(&diriter);
} }

View File

@ -336,7 +336,8 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
int nr_groups = bitmap->s_nr_groups; int nr_groups = bitmap->s_nr_groups;
for (i = 0; i < nr_groups; i++) for (i = 0; i < nr_groups; i++)
brelse(bitmap->s_block_bitmap[i]); if (!IS_ERR_OR_NULL(bitmap->s_block_bitmap[i]))
brelse(bitmap->s_block_bitmap[i]);
kvfree(bitmap); kvfree(bitmap);
} }
@ -1110,12 +1111,19 @@ static int udf_fill_partdesc_info(struct super_block *sb,
struct udf_part_map *map; struct udf_part_map *map;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct partitionHeaderDesc *phd; struct partitionHeaderDesc *phd;
u32 sum;
int err; int err;
map = &sbi->s_partmaps[p_index]; map = &sbi->s_partmaps[p_index];
map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
if (check_add_overflow(map->s_partition_root, map->s_partition_len,
&sum)) {
udf_err(sb, "Partition %d has invalid location %u + %u\n",
p_index, map->s_partition_root, map->s_partition_len);
return -EFSCORRUPTED;
}
if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
@ -1171,6 +1179,14 @@ static int udf_fill_partdesc_info(struct super_block *sb,
bitmap->s_extPosition = le32_to_cpu( bitmap->s_extPosition = le32_to_cpu(
phd->unallocSpaceBitmap.extPosition); phd->unallocSpaceBitmap.extPosition);
map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
/* Check whether math over bitmap won't overflow. */
if (check_add_overflow(map->s_partition_len,
sizeof(struct spaceBitmapDesc) << 3,
&sum)) {
udf_err(sb, "Partition %d is too long (%u)\n", p_index,
map->s_partition_len);
return -EFSCORRUPTED;
}
udf_debug("unallocSpaceBitmap (part %d) @ %u\n", udf_debug("unallocSpaceBitmap (part %d) @ %u\n",
p_index, bitmap->s_extPosition); p_index, bitmap->s_extPosition);
} }