Skip to content

Commit ad3273d

Browse files
committed
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Ted writes: Various ext4 bug fixes; primarily making ext4 more robust against maliciously crafted file systems, and some DAX fixes. * tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4, dax: set ext4_dax_aops for dax files ext4, dax: add ext4_bmap to ext4_dax_aops ext4: don't mark mmp buffer head dirty ext4: show test_dummy_encryption mount option in /proc/mounts ext4: close race between direct IO and ext4_break_layouts() ext4: fix online resizing for bigalloc file systems with a 1k block size ext4: fix online resize's handling of a too-small final block group ext4: recalucate superblock checksum after updating free blocks/inodes ext4: avoid arithemetic overflow that can trigger a BUG ext4: avoid divide by zero fault when deleting corrupted inline directories ext4: check to make sure the rename(2)'s destination is not freed ext4: add nonstring annotations to ext4.h
2 parents c0747ad + cce6c9f commit ad3273d

File tree

8 files changed

+72
-26
lines changed

8 files changed

+72
-26
lines changed

fs/ext4/dir.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
7676
else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
7777
error_msg = "rec_len is too small for name_len";
7878
else if (unlikely(((char *) de - buf) + rlen > size))
79-
error_msg = "directory entry across range";
79+
error_msg = "directory entry overrun";
8080
else if (unlikely(le32_to_cpu(de->inode) >
8181
le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
8282
error_msg = "inode out of bounds";
@@ -85,18 +85,16 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
8585

8686
if (filp)
8787
ext4_error_file(filp, function, line, bh->b_blocknr,
88-
"bad entry in directory: %s - offset=%u(%u), "
89-
"inode=%u, rec_len=%d, name_len=%d",
90-
error_msg, (unsigned) (offset % size),
91-
offset, le32_to_cpu(de->inode),
92-
rlen, de->name_len);
88+
"bad entry in directory: %s - offset=%u, "
89+
"inode=%u, rec_len=%d, name_len=%d, size=%d",
90+
error_msg, offset, le32_to_cpu(de->inode),
91+
rlen, de->name_len, size);
9392
else
9493
ext4_error_inode(dir, function, line, bh->b_blocknr,
95-
"bad entry in directory: %s - offset=%u(%u), "
96-
"inode=%u, rec_len=%d, name_len=%d",
97-
error_msg, (unsigned) (offset % size),
98-
offset, le32_to_cpu(de->inode),
99-
rlen, de->name_len);
94+
"bad entry in directory: %s - offset=%u, "
95+
"inode=%u, rec_len=%d, name_len=%d, size=%d",
96+
error_msg, offset, le32_to_cpu(de->inode),
97+
rlen, de->name_len, size);
10098

10199
return 1;
102100
}

fs/ext4/ext4.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@
4343
#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION)
4444
#include <linux/fscrypt.h>
4545

46+
#include <linux/compiler.h>
47+
48+
/* Until this gets included into linux/compiler-gcc.h */
49+
#ifndef __nonstring
50+
#if defined(GCC_VERSION) && (GCC_VERSION >= 80000)
51+
#define __nonstring __attribute__((nonstring))
52+
#else
53+
#define __nonstring
54+
#endif
55+
#endif
56+
4657
/*
4758
* The fourth extended filesystem constants/structures
4859
*/
@@ -675,6 +686,9 @@ enum {
675686
/* Max physical block we can address w/o extents */
676687
#define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF
677688

689+
/* Max logical block we can support */
690+
#define EXT4_MAX_LOGICAL_BLOCK 0xFFFFFFFF
691+
678692
/*
679693
* Structure of an inode on the disk
680694
*/
@@ -1226,7 +1240,7 @@ struct ext4_super_block {
12261240
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
12271241
/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
12281242
/*78*/ char s_volume_name[16]; /* volume name */
1229-
/*88*/ char s_last_mounted[64]; /* directory where last mounted */
1243+
/*88*/ char s_last_mounted[64] __nonstring; /* directory where last mounted */
12301244
/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
12311245
/*
12321246
* Performance hints. Directory preallocation should only
@@ -1277,13 +1291,13 @@ struct ext4_super_block {
12771291
__le32 s_first_error_time; /* first time an error happened */
12781292
__le32 s_first_error_ino; /* inode involved in first error */
12791293
__le64 s_first_error_block; /* block involved of first error */
1280-
__u8 s_first_error_func[32]; /* function where the error happened */
1294+
__u8 s_first_error_func[32] __nonstring; /* function where the error happened */
12811295
__le32 s_first_error_line; /* line number where error happened */
12821296
__le32 s_last_error_time; /* most recent time of an error */
12831297
__le32 s_last_error_ino; /* inode involved in last error */
12841298
__le32 s_last_error_line; /* line number where error happened */
12851299
__le64 s_last_error_block; /* block involved of last error */
1286-
__u8 s_last_error_func[32]; /* function where the error happened */
1300+
__u8 s_last_error_func[32] __nonstring; /* function where the error happened */
12871301
#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
12881302
__u8 s_mount_opts[64];
12891303
__le32 s_usr_quota_inum; /* inode for tracking user quota */

fs/ext4/inline.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,7 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data)
17531753
{
17541754
int err, inline_size;
17551755
struct ext4_iloc iloc;
1756+
size_t inline_len;
17561757
void *inline_pos;
17571758
unsigned int offset;
17581759
struct ext4_dir_entry_2 *de;
@@ -1780,8 +1781,9 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data)
17801781
goto out;
17811782
}
17821783

1784+
inline_len = ext4_get_inline_size(dir);
17831785
offset = EXT4_INLINE_DOTDOT_SIZE;
1784-
while (offset < dir->i_size) {
1786+
while (offset < inline_len) {
17851787
de = ext4_get_inline_entry(dir, &iloc, offset,
17861788
&inline_pos, &inline_size);
17871789
if (ext4_check_dir_entry(dir, NULL, de,

fs/ext4/inode.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3413,12 +3413,16 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
34133413
{
34143414
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
34153415
unsigned int blkbits = inode->i_blkbits;
3416-
unsigned long first_block = offset >> blkbits;
3417-
unsigned long last_block = (offset + length - 1) >> blkbits;
3416+
unsigned long first_block, last_block;
34183417
struct ext4_map_blocks map;
34193418
bool delalloc = false;
34203419
int ret;
34213420

3421+
if ((offset >> blkbits) > EXT4_MAX_LOGICAL_BLOCK)
3422+
return -EINVAL;
3423+
first_block = offset >> blkbits;
3424+
last_block = min_t(loff_t, (offset + length - 1) >> blkbits,
3425+
EXT4_MAX_LOGICAL_BLOCK);
34223426

34233427
if (flags & IOMAP_REPORT) {
34243428
if (ext4_has_inline_data(inode)) {
@@ -3948,6 +3952,7 @@ static const struct address_space_operations ext4_dax_aops = {
39483952
.writepages = ext4_dax_writepages,
39493953
.direct_IO = noop_direct_IO,
39503954
.set_page_dirty = noop_set_page_dirty,
3955+
.bmap = ext4_bmap,
39513956
.invalidatepage = noop_invalidatepage,
39523957
};
39533958

@@ -4192,9 +4197,8 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
41924197
return 0;
41934198
}
41944199

4195-
static void ext4_wait_dax_page(struct ext4_inode_info *ei, bool *did_unlock)
4200+
static void ext4_wait_dax_page(struct ext4_inode_info *ei)
41964201
{
4197-
*did_unlock = true;
41984202
up_write(&ei->i_mmap_sem);
41994203
schedule();
42004204
down_write(&ei->i_mmap_sem);
@@ -4204,23 +4208,21 @@ int ext4_break_layouts(struct inode *inode)
42044208
{
42054209
struct ext4_inode_info *ei = EXT4_I(inode);
42064210
struct page *page;
4207-
bool retry;
42084211
int error;
42094212

42104213
if (WARN_ON_ONCE(!rwsem_is_locked(&ei->i_mmap_sem)))
42114214
return -EINVAL;
42124215

42134216
do {
4214-
retry = false;
42154217
page = dax_layout_busy_page(inode->i_mapping);
42164218
if (!page)
42174219
return 0;
42184220

42194221
error = ___wait_var_event(&page->_refcount,
42204222
atomic_read(&page->_refcount) == 1,
42214223
TASK_INTERRUPTIBLE, 0, 0,
4222-
ext4_wait_dax_page(ei, &retry));
4223-
} while (error == 0 && retry);
4224+
ext4_wait_dax_page(ei));
4225+
} while (error == 0);
42244226

42254227
return error;
42264228
}
@@ -4895,6 +4897,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
48954897
* not initialized on a new filesystem. */
48964898
}
48974899
ei->i_flags = le32_to_cpu(raw_inode->i_flags);
4900+
ext4_set_inode_flags(inode);
48984901
inode->i_blocks = ext4_inode_blocks(raw_inode, ei);
48994902
ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo);
49004903
if (ext4_has_feature_64bit(sb))
@@ -5041,7 +5044,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
50415044
goto bad_inode;
50425045
}
50435046
brelse(iloc.bh);
5044-
ext4_set_inode_flags(inode);
50455047

50465048
unlock_new_inode(inode);
50475049
return inode;

fs/ext4/mmp.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
4949
*/
5050
sb_start_write(sb);
5151
ext4_mmp_csum_set(sb, mmp);
52-
mark_buffer_dirty(bh);
5352
lock_buffer(bh);
5453
bh->b_end_io = end_buffer_write_sync;
5554
get_bh(bh);

fs/ext4/namei.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3478,6 +3478,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
34783478
int credits;
34793479
u8 old_file_type;
34803480

3481+
if (new.inode && new.inode->i_nlink == 0) {
3482+
EXT4_ERROR_INODE(new.inode,
3483+
"target of rename is already freed");
3484+
return -EFSCORRUPTED;
3485+
}
3486+
34813487
if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) &&
34823488
(!projid_eq(EXT4_I(new_dir)->i_projid,
34833489
EXT4_I(old_dentry->d_inode)->i_projid)))

fs/ext4/resize.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
int ext4_resize_begin(struct super_block *sb)
2121
{
22+
struct ext4_sb_info *sbi = EXT4_SB(sb);
2223
int ret = 0;
2324

2425
if (!capable(CAP_SYS_RESOURCE))
@@ -29,7 +30,7 @@ int ext4_resize_begin(struct super_block *sb)
2930
* because the user tools have no way of handling this. Probably a
3031
* bad time to do it anyways.
3132
*/
32-
if (EXT4_SB(sb)->s_sbh->b_blocknr !=
33+
if (EXT4_B2C(sbi, sbi->s_sbh->b_blocknr) !=
3334
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
3435
ext4_warning(sb, "won't resize using backup superblock at %llu",
3536
(unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
@@ -1986,6 +1987,26 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
19861987
}
19871988
}
19881989

1990+
/*
1991+
* Make sure the last group has enough space so that it's
1992+
* guaranteed to have enough space for all metadata blocks
1993+
* that it might need to hold. (We might not need to store
1994+
* the inode table blocks in the last block group, but there
1995+
* will be cases where this might be needed.)
1996+
*/
1997+
if ((ext4_group_first_block_no(sb, n_group) +
1998+
ext4_group_overhead_blocks(sb, n_group) + 2 +
1999+
sbi->s_itb_per_group + sbi->s_cluster_ratio) >= n_blocks_count) {
2000+
n_blocks_count = ext4_group_first_block_no(sb, n_group);
2001+
n_group--;
2002+
n_blocks_count_retry = 0;
2003+
if (resize_inode) {
2004+
iput(resize_inode);
2005+
resize_inode = NULL;
2006+
}
2007+
goto retry;
2008+
}
2009+
19892010
/* extend the last group */
19902011
if (n_group == o_group)
19912012
add = n_blocks_count - o_blocks_count;

fs/ext4/super.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
21452145
SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
21462146
if (test_opt(sb, DATA_ERR_ABORT))
21472147
SEQ_OPTS_PUTS("data_err=abort");
2148+
if (DUMMY_ENCRYPTION_ENABLED(sbi))
2149+
SEQ_OPTS_PUTS("test_dummy_encryption");
21482150

21492151
ext4_show_quota_options(seq, sb);
21502152
return 0;
@@ -4378,11 +4380,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
43784380
block = ext4_count_free_clusters(sb);
43794381
ext4_free_blocks_count_set(sbi->s_es,
43804382
EXT4_C2B(sbi, block));
4383+
ext4_superblock_csum_set(sb);
43814384
err = percpu_counter_init(&sbi->s_freeclusters_counter, block,
43824385
GFP_KERNEL);
43834386
if (!err) {
43844387
unsigned long freei = ext4_count_free_inodes(sb);
43854388
sbi->s_es->s_free_inodes_count = cpu_to_le32(freei);
4389+
ext4_superblock_csum_set(sb);
43864390
err = percpu_counter_init(&sbi->s_freeinodes_counter, freei,
43874391
GFP_KERNEL);
43884392
}

0 commit comments

Comments
 (0)