Skip to content

Commit 188943a

Browse files
committed
Merge tag 'fs-for_v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull ext2, udf, reiserfs, and quota updates from Jan Kara: - Fix for udf to make splicing work again - More disk format sanity checks for ext2 to avoid crashes found by syzbot - More quota disk format checks to avoid crashes found by fuzzing - Reiserfs & isofs cleanups * tag 'fs-for_v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: quota: Add more checking after reading from quota file quota: Replace all block number checking with helper function quota: Check next/prev free block number after reading from quota file ext2: Use kvmalloc() for group descriptor array ext2: Add sanity checks for group and filesystem size udf: Support splicing to file isofs: delete unnecessary checks before brelse() fs/reiserfs: replace ternary operator with min() and min_t()
2 parents abf625d + 191249f commit 188943a

File tree

7 files changed

+86
-30
lines changed

7 files changed

+86
-30
lines changed

fs/ext2/super.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ static void ext2_put_super (struct super_block * sb)
163163
db_count = sbi->s_gdb_count;
164164
for (i = 0; i < db_count; i++)
165165
brelse(sbi->s_group_desc[i]);
166-
kfree(sbi->s_group_desc);
166+
kvfree(sbi->s_group_desc);
167167
kfree(sbi->s_debts);
168168
percpu_counter_destroy(&sbi->s_freeblocks_counter);
169169
percpu_counter_destroy(&sbi->s_freeinodes_counter);
@@ -1052,6 +1052,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
10521052
sbi->s_blocks_per_group);
10531053
goto failed_mount;
10541054
}
1055+
/* At least inode table, bitmaps, and sb have to fit in one group */
1056+
if (sbi->s_blocks_per_group <= sbi->s_itb_per_group + 3) {
1057+
ext2_msg(sb, KERN_ERR,
1058+
"error: #blocks per group smaller than metadata size: %lu <= %lu",
1059+
sbi->s_blocks_per_group, sbi->s_inodes_per_group + 3);
1060+
goto failed_mount;
1061+
}
10551062
if (sbi->s_frags_per_group > sb->s_blocksize * 8) {
10561063
ext2_msg(sb, KERN_ERR,
10571064
"error: #fragments per group too big: %lu",
@@ -1065,9 +1072,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
10651072
sbi->s_inodes_per_group);
10661073
goto failed_mount;
10671074
}
1075+
if (sb_bdev_nr_blocks(sb) < le32_to_cpu(es->s_blocks_count)) {
1076+
ext2_msg(sb, KERN_ERR,
1077+
"bad geometry: block count %u exceeds size of device (%u blocks)",
1078+
le32_to_cpu(es->s_blocks_count),
1079+
(unsigned)sb_bdev_nr_blocks(sb));
1080+
goto failed_mount;
1081+
}
10681082

1069-
if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
1070-
goto cantfind_ext2;
10711083
sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
10721084
le32_to_cpu(es->s_first_data_block) - 1)
10731085
/ EXT2_BLOCKS_PER_GROUP(sb)) + 1;
@@ -1080,7 +1092,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
10801092
}
10811093
db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
10821094
EXT2_DESC_PER_BLOCK(sb);
1083-
sbi->s_group_desc = kmalloc_array(db_count,
1095+
sbi->s_group_desc = kvmalloc_array(db_count,
10841096
sizeof(struct buffer_head *),
10851097
GFP_KERNEL);
10861098
if (sbi->s_group_desc == NULL) {
@@ -1206,7 +1218,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
12061218
for (i = 0; i < db_count; i++)
12071219
brelse(sbi->s_group_desc[i]);
12081220
failed_mount_group_desc:
1209-
kfree(sbi->s_group_desc);
1221+
kvfree(sbi->s_group_desc);
12101222
kfree(sbi->s_debts);
12111223
failed_mount:
12121224
brelse(bh);

fs/isofs/inode.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,13 +1277,11 @@ static int isofs_read_level3_size(struct inode *inode)
12771277
} while (more_entries);
12781278
out:
12791279
kfree(tmpde);
1280-
if (bh)
1281-
brelse(bh);
1280+
brelse(bh);
12821281
return 0;
12831282

12841283
out_nomem:
1285-
if (bh)
1286-
brelse(bh);
1284+
brelse(bh);
12871285
return -ENOMEM;
12881286

12891287
out_noread:
@@ -1486,8 +1484,7 @@ static int isofs_read_inode(struct inode *inode, int relocated)
14861484
ret = 0;
14871485
out:
14881486
kfree(tmpde);
1489-
if (bh)
1490-
brelse(bh);
1487+
brelse(bh);
14911488
return ret;
14921489

14931490
out_badread:

fs/quota/quota_tree.c

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,40 @@ static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf)
7171
return ret;
7272
}
7373

74+
static inline int do_check_range(struct super_block *sb, const char *val_name,
75+
uint val, uint min_val, uint max_val)
76+
{
77+
if (val < min_val || val > max_val) {
78+
quota_error(sb, "Getting %s %u out of range %u-%u",
79+
val_name, val, min_val, max_val);
80+
return -EUCLEAN;
81+
}
82+
83+
return 0;
84+
}
85+
86+
static int check_dquot_block_header(struct qtree_mem_dqinfo *info,
87+
struct qt_disk_dqdbheader *dh)
88+
{
89+
int err = 0;
90+
91+
err = do_check_range(info->dqi_sb, "dqdh_next_free",
92+
le32_to_cpu(dh->dqdh_next_free), 0,
93+
info->dqi_blocks - 1);
94+
if (err)
95+
return err;
96+
err = do_check_range(info->dqi_sb, "dqdh_prev_free",
97+
le32_to_cpu(dh->dqdh_prev_free), 0,
98+
info->dqi_blocks - 1);
99+
if (err)
100+
return err;
101+
err = do_check_range(info->dqi_sb, "dqdh_entries",
102+
le16_to_cpu(dh->dqdh_entries), 0,
103+
qtree_dqstr_in_blk(info));
104+
105+
return err;
106+
}
107+
74108
/* Remove empty block from list and return it */
75109
static int get_free_dqblk(struct qtree_mem_dqinfo *info)
76110
{
@@ -85,6 +119,9 @@ static int get_free_dqblk(struct qtree_mem_dqinfo *info)
85119
ret = read_blk(info, blk, buf);
86120
if (ret < 0)
87121
goto out_buf;
122+
ret = check_dquot_block_header(info, dh);
123+
if (ret)
124+
goto out_buf;
88125
info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
89126
}
90127
else {
@@ -232,6 +269,9 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
232269
*err = read_blk(info, blk, buf);
233270
if (*err < 0)
234271
goto out_buf;
272+
*err = check_dquot_block_header(info, dh);
273+
if (*err)
274+
goto out_buf;
235275
} else {
236276
blk = get_free_dqblk(info);
237277
if ((int)blk < 0) {
@@ -313,6 +353,10 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
313353
}
314354
ref = (__le32 *)buf;
315355
newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
356+
ret = do_check_range(dquot->dq_sb, "block", newblk, 0,
357+
info->dqi_blocks - 1);
358+
if (ret)
359+
goto out_buf;
316360
if (!newblk)
317361
newson = 1;
318362
if (depth == info->dqi_qtree_depth - 1) {
@@ -424,6 +468,9 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
424468
goto out_buf;
425469
}
426470
dh = (struct qt_disk_dqdbheader *)buf;
471+
ret = check_dquot_block_header(info, dh);
472+
if (ret)
473+
goto out_buf;
427474
le16_add_cpu(&dh->dqdh_entries, -1);
428475
if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
429476
ret = remove_free_dqentry(info, buf, blk);
@@ -480,12 +527,10 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
480527
goto out_buf;
481528
}
482529
newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
483-
if (newblk < QT_TREEOFF || newblk >= info->dqi_blocks) {
484-
quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)",
485-
newblk, info->dqi_blocks);
486-
ret = -EUCLEAN;
530+
ret = do_check_range(dquot->dq_sb, "block", newblk, QT_TREEOFF,
531+
info->dqi_blocks - 1);
532+
if (ret)
487533
goto out_buf;
488-
}
489534

490535
if (depth == info->dqi_qtree_depth - 1) {
491536
ret = free_dqentry(info, dquot, newblk);
@@ -586,12 +631,10 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
586631
blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
587632
if (!blk) /* No reference? */
588633
goto out_buf;
589-
if (blk < QT_TREEOFF || blk >= info->dqi_blocks) {
590-
quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)",
591-
blk, info->dqi_blocks);
592-
ret = -EUCLEAN;
634+
ret = do_check_range(dquot->dq_sb, "block", blk, QT_TREEOFF,
635+
info->dqi_blocks - 1);
636+
if (ret)
593637
goto out_buf;
594-
}
595638

596639
if (depth < info->dqi_qtree_depth - 1)
597640
ret = find_tree_dqentry(info, dquot, blk, depth+1);
@@ -705,15 +748,21 @@ static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id,
705748
goto out_buf;
706749
}
707750
for (i = __get_index(info, *id, depth); i < epb; i++) {
708-
if (ref[i] == cpu_to_le32(0)) {
751+
uint blk_no = le32_to_cpu(ref[i]);
752+
753+
if (blk_no == 0) {
709754
*id += level_inc;
710755
continue;
711756
}
757+
ret = do_check_range(info->dqi_sb, "block", blk_no, 0,
758+
info->dqi_blocks - 1);
759+
if (ret)
760+
goto out_buf;
712761
if (depth == info->dqi_qtree_depth - 1) {
713762
ret = 0;
714763
goto out_buf;
715764
}
716-
ret = find_next_id(info, id, le32_to_cpu(ref[i]), depth + 1);
765+
ret = find_next_id(info, id, blk_no, depth + 1);
717766
if (ret != -ENOENT)
718767
break;
719768
}

fs/reiserfs/prints.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ static int print_internal(struct buffer_head *bh, int first, int last)
456456
to = B_NR_ITEMS(bh);
457457
} else {
458458
from = first;
459-
to = last < B_NR_ITEMS(bh) ? last : B_NR_ITEMS(bh);
459+
to = min_t(int, last, B_NR_ITEMS(bh));
460460
}
461461

462462
reiserfs_printk("INTERNAL NODE (%ld) contains %z\n", bh->b_blocknr, bh);

fs/reiserfs/resize.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
9797
* using the copy_size var below allows this code to work for
9898
* both shrinking and expanding the FS.
9999
*/
100-
copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr;
100+
copy_size = min(bmap_nr_new, bmap_nr);
101101
copy_size =
102102
copy_size * sizeof(struct reiserfs_list_bitmap_node *);
103103
for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {

fs/reiserfs/super.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,9 +2504,7 @@ static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,
25042504
len = i_size - off;
25052505
toread = len;
25062506
while (toread > 0) {
2507-
tocopy =
2508-
sb->s_blocksize - offset <
2509-
toread ? sb->s_blocksize - offset : toread;
2507+
tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread);
25102508
tmp_bh.b_state = 0;
25112509
/*
25122510
* Quota files are without tails so we can safely
@@ -2554,8 +2552,7 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
25542552
return -EIO;
25552553
}
25562554
while (towrite > 0) {
2557-
tocopy = sb->s_blocksize - offset < towrite ?
2558-
sb->s_blocksize - offset : towrite;
2555+
tocopy = min_t(unsigned long, sb->s_blocksize - offset, towrite);
25592556
tmp_bh.b_state = 0;
25602557
reiserfs_write_lock(sb);
25612558
err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);

fs/udf/file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ const struct file_operations udf_file_operations = {
252252
.release = udf_release_file,
253253
.fsync = generic_file_fsync,
254254
.splice_read = generic_file_splice_read,
255+
.splice_write = iter_file_splice_write,
255256
.llseek = generic_file_llseek,
256257
};
257258

0 commit comments

Comments
 (0)