Skip to content

Commit bb7c241

Browse files
committed
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 fixes from Ted Ts'o: "Some ext4 bug fixes (mostly to address Syzbot reports)" * tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: bail out of ext4_xattr_ibody_get() fails for any reason ext4: add bounds checking in get_max_inline_xattr_value_size() ext4: add indication of ro vs r/w mounts in the mount message ext4: fix deadlock when converting an inline directory in nojournal mode ext4: improve error recovery code paths in __ext4_remount() ext4: improve error handling from ext4_dirhash() ext4: don't clear SB_RDONLY when remounting r/w until quota is re-enabled ext4: check iomap type only if ext4_iomap_begin() does not fail ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum ext4: fix data races when using cached status extents ext4: avoid deadlock in fs reclaim with page writeback ext4: fix invalid free tracking in ext4_xattr_move_to_block() ext4: remove a BUG_ON in ext4_mb_release_group_pa() ext4: allow ext4_get_group_info() to fail ext4: fix lockdep warning when enabling MMP ext4: fix WARNING in mb_find_extent
2 parents adfbf65 + 2a534e1 commit bb7c241

File tree

13 files changed

+269
-104
lines changed

13 files changed

+269
-104
lines changed

fs/ext4/balloc.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,38 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
305305
return desc;
306306
}
307307

308+
static ext4_fsblk_t ext4_valid_block_bitmap_padding(struct super_block *sb,
309+
ext4_group_t block_group,
310+
struct buffer_head *bh)
311+
{
312+
ext4_grpblk_t next_zero_bit;
313+
unsigned long bitmap_size = sb->s_blocksize * 8;
314+
unsigned int offset = num_clusters_in_group(sb, block_group);
315+
316+
if (bitmap_size <= offset)
317+
return 0;
318+
319+
next_zero_bit = ext4_find_next_zero_bit(bh->b_data, bitmap_size, offset);
320+
321+
return (next_zero_bit < bitmap_size ? next_zero_bit : 0);
322+
}
323+
324+
struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
325+
ext4_group_t group)
326+
{
327+
struct ext4_group_info **grp_info;
328+
long indexv, indexh;
329+
330+
if (unlikely(group >= EXT4_SB(sb)->s_groups_count)) {
331+
ext4_error(sb, "invalid group %u", group);
332+
return NULL;
333+
}
334+
indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
335+
indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
336+
grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
337+
return grp_info[indexh];
338+
}
339+
308340
/*
309341
* Return the block number which was discovered to be invalid, or 0 if
310342
* the block bitmap is valid.
@@ -379,7 +411,7 @@ static int ext4_validate_block_bitmap(struct super_block *sb,
379411

380412
if (buffer_verified(bh))
381413
return 0;
382-
if (EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
414+
if (!grp || EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
383415
return -EFSCORRUPTED;
384416

385417
ext4_lock_group(sb, block_group);
@@ -402,6 +434,15 @@ static int ext4_validate_block_bitmap(struct super_block *sb,
402434
EXT4_GROUP_INFO_BBITMAP_CORRUPT);
403435
return -EFSCORRUPTED;
404436
}
437+
blk = ext4_valid_block_bitmap_padding(sb, block_group, bh);
438+
if (unlikely(blk != 0)) {
439+
ext4_unlock_group(sb, block_group);
440+
ext4_error(sb, "bg %u: block %llu: padding at end of block bitmap is not set",
441+
block_group, blk);
442+
ext4_mark_group_bitmap_corrupted(sb, block_group,
443+
EXT4_GROUP_INFO_BBITMAP_CORRUPT);
444+
return -EFSCORRUPTED;
445+
}
405446
set_buffer_verified(bh);
406447
verified:
407448
ext4_unlock_group(sb, block_group);

fs/ext4/ext4.h

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,30 @@ static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
16841684
return container_of(inode, struct ext4_inode_info, vfs_inode);
16851685
}
16861686

1687+
static inline int ext4_writepages_down_read(struct super_block *sb)
1688+
{
1689+
percpu_down_read(&EXT4_SB(sb)->s_writepages_rwsem);
1690+
return memalloc_nofs_save();
1691+
}
1692+
1693+
static inline void ext4_writepages_up_read(struct super_block *sb, int ctx)
1694+
{
1695+
memalloc_nofs_restore(ctx);
1696+
percpu_up_read(&EXT4_SB(sb)->s_writepages_rwsem);
1697+
}
1698+
1699+
static inline int ext4_writepages_down_write(struct super_block *sb)
1700+
{
1701+
percpu_down_write(&EXT4_SB(sb)->s_writepages_rwsem);
1702+
return memalloc_nofs_save();
1703+
}
1704+
1705+
static inline void ext4_writepages_up_write(struct super_block *sb, int ctx)
1706+
{
1707+
memalloc_nofs_restore(ctx);
1708+
percpu_up_write(&EXT4_SB(sb)->s_writepages_rwsem);
1709+
}
1710+
16871711
static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
16881712
{
16891713
return ino == EXT4_ROOT_INO ||
@@ -2625,6 +2649,8 @@ extern void ext4_check_blocks_bitmap(struct super_block *);
26252649
extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
26262650
ext4_group_t block_group,
26272651
struct buffer_head ** bh);
2652+
extern struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
2653+
ext4_group_t group);
26282654
extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
26292655

26302656
extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb,
@@ -3232,19 +3258,6 @@ static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size)
32323258
raw_inode->i_size_high = cpu_to_le32(i_size >> 32);
32333259
}
32343260

3235-
static inline
3236-
struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
3237-
ext4_group_t group)
3238-
{
3239-
struct ext4_group_info **grp_info;
3240-
long indexv, indexh;
3241-
BUG_ON(group >= EXT4_SB(sb)->s_groups_count);
3242-
indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
3243-
indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
3244-
grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
3245-
return grp_info[indexh];
3246-
}
3247-
32483261
/*
32493262
* Reading s_groups_count requires using smp_rmb() afterwards. See
32503263
* the locking protocol documented in the comments of ext4_group_add()

fs/ext4/extents_status.c

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,12 @@ static void __es_find_extent_range(struct inode *inode,
267267

268268
/* see if the extent has been cached */
269269
es->es_lblk = es->es_len = es->es_pblk = 0;
270-
if (tree->cache_es) {
271-
es1 = tree->cache_es;
272-
if (in_range(lblk, es1->es_lblk, es1->es_len)) {
273-
es_debug("%u cached by [%u/%u) %llu %x\n",
274-
lblk, es1->es_lblk, es1->es_len,
275-
ext4_es_pblock(es1), ext4_es_status(es1));
276-
goto out;
277-
}
270+
es1 = READ_ONCE(tree->cache_es);
271+
if (es1 && in_range(lblk, es1->es_lblk, es1->es_len)) {
272+
es_debug("%u cached by [%u/%u) %llu %x\n",
273+
lblk, es1->es_lblk, es1->es_len,
274+
ext4_es_pblock(es1), ext4_es_status(es1));
275+
goto out;
278276
}
279277

280278
es1 = __es_tree_search(&tree->root, lblk);
@@ -293,7 +291,7 @@ static void __es_find_extent_range(struct inode *inode,
293291
}
294292

295293
if (es1 && matching_fn(es1)) {
296-
tree->cache_es = es1;
294+
WRITE_ONCE(tree->cache_es, es1);
297295
es->es_lblk = es1->es_lblk;
298296
es->es_len = es1->es_len;
299297
es->es_pblk = es1->es_pblk;
@@ -931,14 +929,12 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
931929

932930
/* find extent in cache firstly */
933931
es->es_lblk = es->es_len = es->es_pblk = 0;
934-
if (tree->cache_es) {
935-
es1 = tree->cache_es;
936-
if (in_range(lblk, es1->es_lblk, es1->es_len)) {
937-
es_debug("%u cached by [%u/%u)\n",
938-
lblk, es1->es_lblk, es1->es_len);
939-
found = 1;
940-
goto out;
941-
}
932+
es1 = READ_ONCE(tree->cache_es);
933+
if (es1 && in_range(lblk, es1->es_lblk, es1->es_len)) {
934+
es_debug("%u cached by [%u/%u)\n",
935+
lblk, es1->es_lblk, es1->es_len);
936+
found = 1;
937+
goto out;
942938
}
943939

944940
node = tree->root.rb_node;

fs/ext4/hash.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,11 @@ static int __ext4fs_dirhash(const struct inode *dir, const char *name, int len,
277277
}
278278
default:
279279
hinfo->hash = 0;
280-
return -1;
280+
hinfo->minor_hash = 0;
281+
ext4_warning(dir->i_sb,
282+
"invalid/unsupported hash tree version %u",
283+
hinfo->hash_version);
284+
return -EINVAL;
281285
}
282286
hash = hash & ~1;
283287
if (hash == (EXT4_HTREE_EOF_32BIT << 1))

fs/ext4/ialloc.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static int ext4_validate_inode_bitmap(struct super_block *sb,
9191

9292
if (buffer_verified(bh))
9393
return 0;
94-
if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp))
94+
if (!grp || EXT4_MB_GRP_IBITMAP_CORRUPT(grp))
9595
return -EFSCORRUPTED;
9696

9797
ext4_lock_group(sb, block_group);
@@ -293,7 +293,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
293293
}
294294
if (!(sbi->s_mount_state & EXT4_FC_REPLAY)) {
295295
grp = ext4_get_group_info(sb, block_group);
296-
if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp))) {
296+
if (!grp || unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp))) {
297297
fatal = -EFSCORRUPTED;
298298
goto error_return;
299299
}
@@ -1046,7 +1046,7 @@ struct inode *__ext4_new_inode(struct mnt_idmap *idmap,
10461046
* Skip groups with already-known suspicious inode
10471047
* tables
10481048
*/
1049-
if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp))
1049+
if (!grp || EXT4_MB_GRP_IBITMAP_CORRUPT(grp))
10501050
goto next_group;
10511051
}
10521052

@@ -1183,6 +1183,10 @@ struct inode *__ext4_new_inode(struct mnt_idmap *idmap,
11831183

11841184
if (!(sbi->s_mount_state & EXT4_FC_REPLAY)) {
11851185
grp = ext4_get_group_info(sb, group);
1186+
if (!grp) {
1187+
err = -EFSCORRUPTED;
1188+
goto out;
1189+
}
11861190
down_read(&grp->alloc_sem); /*
11871191
* protect vs itable
11881192
* lazyinit
@@ -1526,7 +1530,7 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
15261530
}
15271531

15281532
gdp = ext4_get_group_desc(sb, group, &group_desc_bh);
1529-
if (!gdp)
1533+
if (!gdp || !grp)
15301534
goto out;
15311535

15321536
/*

fs/ext4/inline.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode,
3434
struct ext4_xattr_ibody_header *header;
3535
struct ext4_xattr_entry *entry;
3636
struct ext4_inode *raw_inode;
37+
void *end;
3738
int free, min_offs;
3839

3940
if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
@@ -57,14 +58,23 @@ static int get_max_inline_xattr_value_size(struct inode *inode,
5758
raw_inode = ext4_raw_inode(iloc);
5859
header = IHDR(inode, raw_inode);
5960
entry = IFIRST(header);
61+
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
6062

6163
/* Compute min_offs. */
62-
for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
64+
while (!IS_LAST_ENTRY(entry)) {
65+
void *next = EXT4_XATTR_NEXT(entry);
66+
67+
if (next >= end) {
68+
EXT4_ERROR_INODE(inode,
69+
"corrupt xattr in inline inode");
70+
return 0;
71+
}
6372
if (!entry->e_value_inum && entry->e_value_size) {
6473
size_t offs = le16_to_cpu(entry->e_value_offs);
6574
if (offs < min_offs)
6675
min_offs = offs;
6776
}
77+
entry = next;
6878
}
6979
free = min_offs -
7080
((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);
@@ -350,7 +360,7 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
350360

351361
error = ext4_xattr_ibody_get(inode, i.name_index, i.name,
352362
value, len);
353-
if (error == -ENODATA)
363+
if (error < 0)
354364
goto out;
355365

356366
BUFFER_TRACE(is.iloc.bh, "get_write_access");
@@ -1175,6 +1185,7 @@ static int ext4_finish_convert_inline_dir(handle_t *handle,
11751185
ext4_initialize_dirent_tail(dir_block,
11761186
inode->i_sb->s_blocksize);
11771187
set_buffer_uptodate(dir_block);
1188+
unlock_buffer(dir_block);
11781189
err = ext4_handle_dirty_dirblock(handle, inode, dir_block);
11791190
if (err)
11801191
return err;
@@ -1249,14 +1260,14 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,
12491260
if (!S_ISDIR(inode->i_mode)) {
12501261
memcpy(data_bh->b_data, buf, inline_size);
12511262
set_buffer_uptodate(data_bh);
1263+
unlock_buffer(data_bh);
12521264
error = ext4_handle_dirty_metadata(handle,
12531265
inode, data_bh);
12541266
} else {
12551267
error = ext4_finish_convert_inline_dir(handle, inode, data_bh,
12561268
buf, inline_size);
12571269
}
12581270

1259-
unlock_buffer(data_bh);
12601271
out_restore:
12611272
if (error)
12621273
ext4_restore_inline_data(handle, inode, iloc, buf, inline_size);

fs/ext4/inode.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2783,11 +2783,12 @@ static int ext4_writepages(struct address_space *mapping,
27832783
.can_map = 1,
27842784
};
27852785
int ret;
2786+
int alloc_ctx;
27862787

27872788
if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
27882789
return -EIO;
27892790

2790-
percpu_down_read(&EXT4_SB(sb)->s_writepages_rwsem);
2791+
alloc_ctx = ext4_writepages_down_read(sb);
27912792
ret = ext4_do_writepages(&mpd);
27922793
/*
27932794
* For data=journal writeback we could have come across pages marked
@@ -2796,7 +2797,7 @@ static int ext4_writepages(struct address_space *mapping,
27962797
*/
27972798
if (!ret && mpd.journalled_more_data)
27982799
ret = ext4_do_writepages(&mpd);
2799-
percpu_up_read(&EXT4_SB(sb)->s_writepages_rwsem);
2800+
ext4_writepages_up_read(sb, alloc_ctx);
28002801

28012802
return ret;
28022803
}
@@ -2824,17 +2825,18 @@ static int ext4_dax_writepages(struct address_space *mapping,
28242825
long nr_to_write = wbc->nr_to_write;
28252826
struct inode *inode = mapping->host;
28262827
struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
2828+
int alloc_ctx;
28272829

28282830
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
28292831
return -EIO;
28302832

2831-
percpu_down_read(&sbi->s_writepages_rwsem);
2833+
alloc_ctx = ext4_writepages_down_read(inode->i_sb);
28322834
trace_ext4_writepages(inode, wbc);
28332835

28342836
ret = dax_writeback_mapping_range(mapping, sbi->s_daxdev, wbc);
28352837
trace_ext4_writepages_result(inode, wbc, ret,
28362838
nr_to_write - wbc->nr_to_write);
2837-
percpu_up_read(&sbi->s_writepages_rwsem);
2839+
ext4_writepages_up_read(inode->i_sb, alloc_ctx);
28382840
return ret;
28392841
}
28402842

@@ -3375,7 +3377,7 @@ static int ext4_iomap_overwrite_begin(struct inode *inode, loff_t offset,
33753377
*/
33763378
flags &= ~IOMAP_WRITE;
33773379
ret = ext4_iomap_begin(inode, offset, length, flags, iomap, srcmap);
3378-
WARN_ON_ONCE(iomap->type != IOMAP_MAPPED);
3380+
WARN_ON_ONCE(!ret && iomap->type != IOMAP_MAPPED);
33793381
return ret;
33803382
}
33813383

@@ -5928,7 +5930,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
59285930
journal_t *journal;
59295931
handle_t *handle;
59305932
int err;
5931-
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
5933+
int alloc_ctx;
59325934

59335935
/*
59345936
* We have to be very careful here: changing a data block's
@@ -5966,7 +5968,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
59665968
}
59675969
}
59685970

5969-
percpu_down_write(&sbi->s_writepages_rwsem);
5971+
alloc_ctx = ext4_writepages_down_write(inode->i_sb);
59705972
jbd2_journal_lock_updates(journal);
59715973

59725974
/*
@@ -5983,15 +5985,15 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
59835985
err = jbd2_journal_flush(journal, 0);
59845986
if (err < 0) {
59855987
jbd2_journal_unlock_updates(journal);
5986-
percpu_up_write(&sbi->s_writepages_rwsem);
5988+
ext4_writepages_up_write(inode->i_sb, alloc_ctx);
59875989
return err;
59885990
}
59895991
ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
59905992
}
59915993
ext4_set_aops(inode);
59925994

59935995
jbd2_journal_unlock_updates(journal);
5994-
percpu_up_write(&sbi->s_writepages_rwsem);
5996+
ext4_writepages_up_write(inode->i_sb, alloc_ctx);
59955997

59965998
if (val)
59975999
filemap_invalidate_unlock(inode->i_mapping);

0 commit comments

Comments
 (0)