Eric Biggers (1): ext4: reject casefold inode flag without casefold feature
Theodore Ts'o (1): ext4: improve error handling from ext4_dirhash()
fs/ext4/hash.c | 5 ++++- fs/ext4/inode.c | 5 ++++- fs/ext4/namei.c | 40 +++++++++++++++++++++++++++++++--------- 3 files changed, 39 insertions(+), 11 deletions(-)
From: Eric Biggers ebiggers@google.com
mainline inclusion from mainline-v6.6-rc1 commit 8216776ccff6fcd40e3fdaa109aa4150ebe760b3 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8WZXW
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
It is invalid for the casefold inode flag to be set without the casefold superblock feature flag also being set. e2fsck already considers this case to be invalid and handles it by offering to clear the casefold flag on the inode. __ext4_iget() also already considered this to be invalid, sort of, but it only got so far as logging an error message; it didn't actually reject the inode. Make it reject the inode so that other code doesn't have to handle this case. This matches what f2fs does.
Note: we could check 's_encoding != NULL' instead of ext4_has_feature_casefold(). This would make the check robust against the casefold feature being enabled by userspace writing to the page cache of the mounted block device. However, it's unsolvable in general for filesystems to be robust against concurrent writes to the page cache of the mounted block device. Though this very particular scenario involving the casefold feature is solvable, we should not pretend that we can support this model, so let's just check the casefold feature. tune2fs already forbids enabling casefold on a mounted filesystem.
Signed-off-by: Eric Biggers ebiggers@google.com Link: https://lore.kernel.org/r/20230814182903.37267-2-ebiggers@kernel.org Signed-off-by: Theodore Ts'o tytso@mit.edu
Conflicts: fs/ext4/inode.c
Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/ext4/inode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b493cc2b393f..f427394b96a0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5083,9 +5083,12 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, "iget: bogus i_mode (%o)", inode->i_mode); goto bad_inode; } - if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) + if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) { ext4_error_inode(inode, function, line, 0, "casefold flag without casefold feature"); + ret = -EFSCORRUPTED; + goto bad_inode; + } if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) { ext4_error_inode(inode, function, line, 0, "bad inode without EXT4_IGET_BAD flag");
From: Theodore Ts'o tytso@mit.edu
mainline inclusion from mainline-v6.4-rc2 commit 4b3cb1d108bfc2aebb0d7c8a52261a53cf7f5786 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8WZXW
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
The ext4_dirhash() will *almost* never fail, especially when the hash tree feature was first introduced. However, with the addition of support of encrypted, casefolded file names, that function can most certainly fail today.
So make sure the callers of ext4_dirhash() properly check for failures, and reflect the errors back up to their callers.
Cc: stable@kernel.org Link: https://lore.kernel.org/r/20230506142419.984260-1-tytso@mit.edu Reported-by: syzbot+394aa8a792cb99dbc837@syzkaller.appspotmail.com Reported-by: syzbot+344aaa8697ebd232bfc8@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?id=db56459ea4ac4a676ae4b4678f633e55da005a9... Signed-off-by: Theodore Ts'o tytso@mit.edu
Conflicts: fs/ext4/hash.c fs/ext4/namei.c
Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/ext4/hash.c | 5 ++++- fs/ext4/namei.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index a92eb79de0cc..dce229183b01 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -261,7 +261,10 @@ static int __ext4fs_dirhash(const char *name, int len, break; default: hinfo->hash = 0; - return -1; + hinfo->minor_hash = 0; + pr_warn("invalid/unsupported hash tree version %u", + hinfo->hash_version); + return -EINVAL; } hash = hash & ~1; if (hash == (EXT4_HTREE_EOF_32BIT << 1)) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index fb0731e0ad06..05b522b4dbee 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -681,7 +681,7 @@ static struct stats dx_show_leaf(struct inode *dir, } if (!fscrypt_has_encryption_key(dir)) { /* Directory is not encrypted */ - ext4fs_dirhash(dir, de->name, + (void) ext4fs_dirhash(dir, de->name, de->name_len, &h); printk("%*.s:(U)%x.%u ", len, name, h.hash, @@ -713,8 +713,9 @@ static struct stats dx_show_leaf(struct inode *dir, name = fname_crypto_str.name; len = fname_crypto_str.len; } - ext4fs_dirhash(dir, de->name, - de->name_len, &h); + (void) ext4fs_dirhash(dir, + de->name, + de->name_len, &h); printk("%*.s:(E)%x.%u ", len, name, h.hash, (unsigned) ((char *) de - base)); @@ -724,7 +725,8 @@ static struct stats dx_show_leaf(struct inode *dir, #else int len = de->name_len; char *name = de->name; - ext4fs_dirhash(dir, de->name, de->name_len, &h); + (void) ext4fs_dirhash(dir, de->name, + de->name_len, &h); printk("%*.s:%x.%u ", len, name, h.hash, (unsigned) ((char *) de - base)); #endif @@ -814,8 +816,14 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, if (hinfo->hash_version <= DX_HASH_TEA) hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; - if (fname && fname_name(fname)) - ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), hinfo); + if (fname && fname_name(fname)) { + int ret = ext4fs_dirhash(dir, fname_name(fname), + fname_len(fname), hinfo); + if (ret < 0) { + ret_err = ERR_PTR(ret); + goto fail; + } + } hash = hinfo->hash;
if (root->info.unused_flags & 1) { @@ -1077,7 +1085,12 @@ static int htree_dirblock_to_tree(struct file *dir_file, /* silently ignore the rest of the block */ break; } - ext4fs_dirhash(dir, de->name, de->name_len, hinfo); + err = ext4fs_dirhash(dir, de->name, + de->name_len, hinfo); + if (err < 0) { + count = err; + goto errout; + } if ((hinfo->hash < start_hash) || ((hinfo->hash == start_hash) && (hinfo->minor_hash < start_minor_hash))) @@ -1273,7 +1286,10 @@ static int dx_make_map(struct inode *dir, struct buffer_head *bh, ((char *)de) - base)) return -EFSCORRUPTED; if (de->name_len && de->inode) { - ext4fs_dirhash(dir, de->name, de->name_len, &h); + int err = ext4fs_dirhash(dir, de->name, + de->name_len, &h); + if (err < 0) + return err; map_tail--; map_tail->hash = h.hash; map_tail->offs = ((char *) de - base)>>2; @@ -2195,7 +2211,13 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, if (fname->hinfo.hash_version <= DX_HASH_TEA) fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; - ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), &fname->hinfo); + retval = ext4fs_dirhash(dir, fname_name(fname), + fname_len(fname), &fname->hinfo); + if (retval < 0) { + brelse(bh2); + brelse(bh); + return retval; + }
memset(frames, 0, sizeof(frames)); frame = frames;
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/4061 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/4061 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2...