mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-19 04:14:49 +08:00
Various ext4 bug fixes; primarily making ext4 more robust against
maliciously crafted file systems, and some DAX fixes. -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAlufGncACgkQ8vlZVpUN gaPwuQf9FKp9yRvjBkjtnH3+s4Ps8do9r067+90y1k2DJMxKoaBUhGSW2MJJ04j+ 5F6Ndp/TZHw+LfPnzsqlrAAoP3CG5+kacfJ7xeVKR0umvACm6rLMsCUct7/rFoSl PgzCALFIJvQ9+9shuO9qrgmjJrfrlTVUgR9Mu3WUNEvMFbMjk3FMI8gi5kjjWemE G9TDYH2lMH2sL0cWF51I2gOyNXOXrihxe+vP7j6i/rUkV+YLpKZhE1ss3Sfn6pR2 p/KjnXdupLJpgYLJne9kMrq2r8xYmDfA0S+Dec7nkox5FUOFUHssl3+q8C7cDwO9 zl6VyVFwybjFRJ/Y59wox6eqVPlIWw== =1P1w -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ad3273d5f1
@ -76,7 +76,7 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
|
||||
else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
|
||||
error_msg = "rec_len is too small for name_len";
|
||||
else if (unlikely(((char *) de - buf) + rlen > size))
|
||||
error_msg = "directory entry across range";
|
||||
error_msg = "directory entry overrun";
|
||||
else if (unlikely(le32_to_cpu(de->inode) >
|
||||
le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
|
||||
error_msg = "inode out of bounds";
|
||||
@ -85,18 +85,16 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
|
||||
|
||||
if (filp)
|
||||
ext4_error_file(filp, function, line, bh->b_blocknr,
|
||||
"bad entry in directory: %s - offset=%u(%u), "
|
||||
"inode=%u, rec_len=%d, name_len=%d",
|
||||
error_msg, (unsigned) (offset % size),
|
||||
offset, le32_to_cpu(de->inode),
|
||||
rlen, de->name_len);
|
||||
"bad entry in directory: %s - offset=%u, "
|
||||
"inode=%u, rec_len=%d, name_len=%d, size=%d",
|
||||
error_msg, offset, le32_to_cpu(de->inode),
|
||||
rlen, de->name_len, size);
|
||||
else
|
||||
ext4_error_inode(dir, function, line, bh->b_blocknr,
|
||||
"bad entry in directory: %s - offset=%u(%u), "
|
||||
"inode=%u, rec_len=%d, name_len=%d",
|
||||
error_msg, (unsigned) (offset % size),
|
||||
offset, le32_to_cpu(de->inode),
|
||||
rlen, de->name_len);
|
||||
"bad entry in directory: %s - offset=%u, "
|
||||
"inode=%u, rec_len=%d, name_len=%d, size=%d",
|
||||
error_msg, offset, le32_to_cpu(de->inode),
|
||||
rlen, de->name_len, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -43,6 +43,17 @@
|
||||
#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION)
|
||||
#include <linux/fscrypt.h>
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/* Until this gets included into linux/compiler-gcc.h */
|
||||
#ifndef __nonstring
|
||||
#if defined(GCC_VERSION) && (GCC_VERSION >= 80000)
|
||||
#define __nonstring __attribute__((nonstring))
|
||||
#else
|
||||
#define __nonstring
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The fourth extended filesystem constants/structures
|
||||
*/
|
||||
@ -675,6 +686,9 @@ enum {
|
||||
/* Max physical block we can address w/o extents */
|
||||
#define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF
|
||||
|
||||
/* Max logical block we can support */
|
||||
#define EXT4_MAX_LOGICAL_BLOCK 0xFFFFFFFF
|
||||
|
||||
/*
|
||||
* Structure of an inode on the disk
|
||||
*/
|
||||
@ -1226,7 +1240,7 @@ struct ext4_super_block {
|
||||
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
|
||||
/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
|
||||
/*78*/ char s_volume_name[16]; /* volume name */
|
||||
/*88*/ char s_last_mounted[64]; /* directory where last mounted */
|
||||
/*88*/ char s_last_mounted[64] __nonstring; /* directory where last mounted */
|
||||
/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
|
||||
/*
|
||||
* Performance hints. Directory preallocation should only
|
||||
@ -1277,13 +1291,13 @@ struct ext4_super_block {
|
||||
__le32 s_first_error_time; /* first time an error happened */
|
||||
__le32 s_first_error_ino; /* inode involved in first error */
|
||||
__le64 s_first_error_block; /* block involved of first error */
|
||||
__u8 s_first_error_func[32]; /* function where the error happened */
|
||||
__u8 s_first_error_func[32] __nonstring; /* function where the error happened */
|
||||
__le32 s_first_error_line; /* line number where error happened */
|
||||
__le32 s_last_error_time; /* most recent time of an error */
|
||||
__le32 s_last_error_ino; /* inode involved in last error */
|
||||
__le32 s_last_error_line; /* line number where error happened */
|
||||
__le64 s_last_error_block; /* block involved of last error */
|
||||
__u8 s_last_error_func[32]; /* function where the error happened */
|
||||
__u8 s_last_error_func[32] __nonstring; /* function where the error happened */
|
||||
#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
|
||||
__u8 s_mount_opts[64];
|
||||
__le32 s_usr_quota_inum; /* inode for tracking user quota */
|
||||
|
@ -1753,6 +1753,7 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data)
|
||||
{
|
||||
int err, inline_size;
|
||||
struct ext4_iloc iloc;
|
||||
size_t inline_len;
|
||||
void *inline_pos;
|
||||
unsigned int offset;
|
||||
struct ext4_dir_entry_2 *de;
|
||||
@ -1780,8 +1781,9 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data)
|
||||
goto out;
|
||||
}
|
||||
|
||||
inline_len = ext4_get_inline_size(dir);
|
||||
offset = EXT4_INLINE_DOTDOT_SIZE;
|
||||
while (offset < dir->i_size) {
|
||||
while (offset < inline_len) {
|
||||
de = ext4_get_inline_entry(dir, &iloc, offset,
|
||||
&inline_pos, &inline_size);
|
||||
if (ext4_check_dir_entry(dir, NULL, de,
|
||||
|
@ -3413,12 +3413,16 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
unsigned int blkbits = inode->i_blkbits;
|
||||
unsigned long first_block = offset >> blkbits;
|
||||
unsigned long last_block = (offset + length - 1) >> blkbits;
|
||||
unsigned long first_block, last_block;
|
||||
struct ext4_map_blocks map;
|
||||
bool delalloc = false;
|
||||
int ret;
|
||||
|
||||
if ((offset >> blkbits) > EXT4_MAX_LOGICAL_BLOCK)
|
||||
return -EINVAL;
|
||||
first_block = offset >> blkbits;
|
||||
last_block = min_t(loff_t, (offset + length - 1) >> blkbits,
|
||||
EXT4_MAX_LOGICAL_BLOCK);
|
||||
|
||||
if (flags & IOMAP_REPORT) {
|
||||
if (ext4_has_inline_data(inode)) {
|
||||
@ -3948,6 +3952,7 @@ static const struct address_space_operations ext4_dax_aops = {
|
||||
.writepages = ext4_dax_writepages,
|
||||
.direct_IO = noop_direct_IO,
|
||||
.set_page_dirty = noop_set_page_dirty,
|
||||
.bmap = ext4_bmap,
|
||||
.invalidatepage = noop_invalidatepage,
|
||||
};
|
||||
|
||||
@ -4192,9 +4197,8 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ext4_wait_dax_page(struct ext4_inode_info *ei, bool *did_unlock)
|
||||
static void ext4_wait_dax_page(struct ext4_inode_info *ei)
|
||||
{
|
||||
*did_unlock = true;
|
||||
up_write(&ei->i_mmap_sem);
|
||||
schedule();
|
||||
down_write(&ei->i_mmap_sem);
|
||||
@ -4204,14 +4208,12 @@ int ext4_break_layouts(struct inode *inode)
|
||||
{
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
struct page *page;
|
||||
bool retry;
|
||||
int error;
|
||||
|
||||
if (WARN_ON_ONCE(!rwsem_is_locked(&ei->i_mmap_sem)))
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
retry = false;
|
||||
page = dax_layout_busy_page(inode->i_mapping);
|
||||
if (!page)
|
||||
return 0;
|
||||
@ -4219,8 +4221,8 @@ int ext4_break_layouts(struct inode *inode)
|
||||
error = ___wait_var_event(&page->_refcount,
|
||||
atomic_read(&page->_refcount) == 1,
|
||||
TASK_INTERRUPTIBLE, 0, 0,
|
||||
ext4_wait_dax_page(ei, &retry));
|
||||
} while (error == 0 && retry);
|
||||
ext4_wait_dax_page(ei));
|
||||
} while (error == 0);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -4895,6 +4897,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||||
* not initialized on a new filesystem. */
|
||||
}
|
||||
ei->i_flags = le32_to_cpu(raw_inode->i_flags);
|
||||
ext4_set_inode_flags(inode);
|
||||
inode->i_blocks = ext4_inode_blocks(raw_inode, ei);
|
||||
ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo);
|
||||
if (ext4_has_feature_64bit(sb))
|
||||
@ -5041,7 +5044,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||||
goto bad_inode;
|
||||
}
|
||||
brelse(iloc.bh);
|
||||
ext4_set_inode_flags(inode);
|
||||
|
||||
unlock_new_inode(inode);
|
||||
return inode;
|
||||
|
@ -49,7 +49,6 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
|
||||
*/
|
||||
sb_start_write(sb);
|
||||
ext4_mmp_csum_set(sb, mmp);
|
||||
mark_buffer_dirty(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_write_sync;
|
||||
get_bh(bh);
|
||||
|
@ -3478,6 +3478,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
int credits;
|
||||
u8 old_file_type;
|
||||
|
||||
if (new.inode && new.inode->i_nlink == 0) {
|
||||
EXT4_ERROR_INODE(new.inode,
|
||||
"target of rename is already freed");
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) &&
|
||||
(!projid_eq(EXT4_I(new_dir)->i_projid,
|
||||
EXT4_I(old_dentry->d_inode)->i_projid)))
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
int ext4_resize_begin(struct super_block *sb)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
int ret = 0;
|
||||
|
||||
if (!capable(CAP_SYS_RESOURCE))
|
||||
@ -29,7 +30,7 @@ int ext4_resize_begin(struct super_block *sb)
|
||||
* because the user tools have no way of handling this. Probably a
|
||||
* bad time to do it anyways.
|
||||
*/
|
||||
if (EXT4_SB(sb)->s_sbh->b_blocknr !=
|
||||
if (EXT4_B2C(sbi, sbi->s_sbh->b_blocknr) !=
|
||||
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
|
||||
ext4_warning(sb, "won't resize using backup superblock at %llu",
|
||||
(unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
|
||||
@ -1986,6 +1987,26 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the last group has enough space so that it's
|
||||
* guaranteed to have enough space for all metadata blocks
|
||||
* that it might need to hold. (We might not need to store
|
||||
* the inode table blocks in the last block group, but there
|
||||
* will be cases where this might be needed.)
|
||||
*/
|
||||
if ((ext4_group_first_block_no(sb, n_group) +
|
||||
ext4_group_overhead_blocks(sb, n_group) + 2 +
|
||||
sbi->s_itb_per_group + sbi->s_cluster_ratio) >= n_blocks_count) {
|
||||
n_blocks_count = ext4_group_first_block_no(sb, n_group);
|
||||
n_group--;
|
||||
n_blocks_count_retry = 0;
|
||||
if (resize_inode) {
|
||||
iput(resize_inode);
|
||||
resize_inode = NULL;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* extend the last group */
|
||||
if (n_group == o_group)
|
||||
add = n_blocks_count - o_blocks_count;
|
||||
|
@ -2145,6 +2145,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
|
||||
SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
|
||||
if (test_opt(sb, DATA_ERR_ABORT))
|
||||
SEQ_OPTS_PUTS("data_err=abort");
|
||||
if (DUMMY_ENCRYPTION_ENABLED(sbi))
|
||||
SEQ_OPTS_PUTS("test_dummy_encryption");
|
||||
|
||||
ext4_show_quota_options(seq, sb);
|
||||
return 0;
|
||||
@ -4378,11 +4380,13 @@ no_journal:
|
||||
block = ext4_count_free_clusters(sb);
|
||||
ext4_free_blocks_count_set(sbi->s_es,
|
||||
EXT4_C2B(sbi, block));
|
||||
ext4_superblock_csum_set(sb);
|
||||
err = percpu_counter_init(&sbi->s_freeclusters_counter, block,
|
||||
GFP_KERNEL);
|
||||
if (!err) {
|
||||
unsigned long freei = ext4_count_free_inodes(sb);
|
||||
sbi->s_es->s_free_inodes_count = cpu_to_le32(freei);
|
||||
ext4_superblock_csum_set(sb);
|
||||
err = percpu_counter_init(&sbi->s_freeinodes_counter, freei,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user