Found by syzbot (https://syzkaller.appspot.com/bug?extid=9177d065333561cd6fd0):
EXT4-fs (loop0): encrypted files will use data=ordered instead of data journaling mode EXT4-fs (loop0): 1 truncate cleaned up EXT4-fs (loop0): mounted filesystem without journal. Quota mode: none. fscrypt: AES-256-CTS-CBC using implementation "cts-cbc-aes-aesni" ------------[ cut here ]------------ WARNING: CPU: 1 PID: 4245 at fs/crypto/fname.c:567 fscrypt_fname_siphash+0xb9/0xf0 Modules linked in: CPU: 1 PID: 4245 Comm: syz-executor375 Not tainted 6.1.116-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 RIP: 0010:fscrypt_fname_siphash+0xb9/0xf0 fs/crypto/fname.c:567 Call Trace: <TASK> __ext4fs_dirhash+0xdd2/0x14c0 fs/ext4/hash.c:268 ext4fs_dirhash+0x1b8/0x320 fs/ext4/hash.c:322 htree_dirblock_to_tree+0x723/0x10d0 fs/ext4/namei.c:1125 ext4_htree_fill_tree+0x73d/0x13f0 fs/ext4/namei.c:1220 ext4_dx_readdir fs/ext4/dir.c:605 [inline] ext4_readdir+0x2e87/0x3880 fs/ext4/dir.c:142 iterate_dir+0x224/0x560 __do_sys_getdents64 fs/readdir.c:369 [inline] __se_sys_getdents64+0x209/0x4f0 fs/readdir.c:354 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x3b/0xb0 arch/x86/entry/common.c:81 </TASK>
These patches address a warning encountered when mounting ext4 filesystems with the default hash version set to SIPHASH while the casefold feature is not enabled. The warning occurs due to incorrect error handling and setup of the default hash version.
[PATCH 1/3 ] ext4: factor out ext4_hash_info_init() Simplifies the ext4 filesystem setup by factoring out the ext4_hash_info_init function, with no functional change.
[PATCH 2/3] ext4: filesystems without casefold feature cannot be mounted with siphash Ensures that ext4 filesystems with the default hash set to SIPHASH cannot be mounted if the casefold feature is not enabled.
[PATCH 3/3] ext4: fix error message when rejecting the default hash Corrects the error message logic for rejecting filesystems with the default SIPHASH hash version, ensuring the error message doesn't incorrectly reference the casefold setup. Also moves the check to ext4_hash_info_init to ensure consistency.
From: Jason Yan yanaijie@huawei.com
[ Upstream commit db9345d9e6f075e1ec26afadf744078ead935fec ]
Factor out ext4_hash_info_init() to simplify __ext4_fill_super(). No functional change.
Signed-off-by: Jason Yan yanaijie@huawei.com Link: https://lore.kernel.org/r/20230323140517.1070239-2-yanaijie@huawei.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Vasiliy Kovalev kovalev@altlinux.org --- fs/ext4/super.c | 50 +++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3bf214d4afef5..cf2c8cf507780 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5042,6 +5042,35 @@ static int ext4_load_super(struct super_block *sb, ext4_fsblk_t *lsb, return ret; }
+static void ext4_hash_info_init(struct super_block *sb) +{ + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + unsigned int i; + + for (i = 0; i < 4; i++) + sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); + + sbi->s_def_hash_version = es->s_def_hash_version; + if (ext4_has_feature_dir_index(sb)) { + i = le32_to_cpu(es->s_flags); + if (i & EXT2_FLAGS_UNSIGNED_HASH) + sbi->s_hash_unsigned = 3; + else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { +#ifdef __CHAR_UNSIGNED__ + if (!sb_rdonly(sb)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); + sbi->s_hash_unsigned = 3; +#else + if (!sb_rdonly(sb)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); +#endif + } + } +} + static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) { struct ext4_super_block *es = NULL; @@ -5197,26 +5226,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
- for (i = 0; i < 4; i++) - sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); - sbi->s_def_hash_version = es->s_def_hash_version; - if (ext4_has_feature_dir_index(sb)) { - i = le32_to_cpu(es->s_flags); - if (i & EXT2_FLAGS_UNSIGNED_HASH) - sbi->s_hash_unsigned = 3; - else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { -#ifdef __CHAR_UNSIGNED__ - if (!sb_rdonly(sb)) - es->s_flags |= - cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); - sbi->s_hash_unsigned = 3; -#else - if (!sb_rdonly(sb)) - es->s_flags |= - cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); -#endif - } - } + ext4_hash_info_init(sb);
if (ext4_handle_clustersize(sb)) goto failed_mount;
From: Lizhi Xu lizhi.xu@windriver.com
[ Upstream commit 985b67cd86392310d9e9326de941c22fc9340eec ]
When mounting the ext4 filesystem, if the default hash version is set to DX_HASH_SIPHASH but the casefold feature is not set, exit the mounting.
Reported-by: syzbot+340581ba9dceb7e06fb3@syzkaller.appspotmail.com Signed-off-by: Lizhi Xu lizhi.xu@windriver.com Link: https://patch.msgid.link/20240605012335.44086-1-lizhi.xu@windriver.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Vasiliy Kovalev kovalev@altlinux.org --- fs/ext4/super.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index cf2c8cf507780..68070b1859803 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3559,6 +3559,14 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly) } #endif
+ if (EXT4_SB(sb)->s_es->s_def_hash_version == DX_HASH_SIPHASH && + !ext4_has_feature_casefold(sb)) { + ext4_msg(sb, KERN_ERR, + "Filesystem without casefold feature cannot be " + "mounted with siphash"); + return 0; + } + if (readonly) return 1;
From: Gabriel Krisman Bertazi krisman@suse.de
[ Upstream commit a2187431c395cdfbf144e3536f25468c64fc7cfa ]
Commit 985b67cd8639 ("ext4: filesystems without casefold feature cannot be mounted with siphash") properly rejects volumes where s_def_hash_version is set to DX_HASH_SIPHASH, but the check and the error message should not look into casefold setup - a filesystem should never have DX_HASH_SIPHASH as the default hash. Fix it and, since we are there, move the check to ext4_hash_info_init.
Fixes:985b67cd8639 ("ext4: filesystems without casefold feature cannot be mounted with siphash")
Signed-off-by: Gabriel Krisman Bertazi krisman@suse.de Link: https://patch.msgid.link/87jzg1en6j.fsf_-_@mailhost.krisman.be Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Vasiliy Kovalev kovalev@altlinux.org --- fs/ext4/ext4.h | 1 + fs/ext4/super.c | 28 +++++++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 72abb8d6caf75..d5706aedf4fef 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2449,6 +2449,7 @@ static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize) #define DX_HASH_HALF_MD4_UNSIGNED 4 #define DX_HASH_TEA_UNSIGNED 5 #define DX_HASH_SIPHASH 6 +#define DX_HASH_LAST DX_HASH_SIPHASH
static inline u32 ext4_chksum(struct ext4_sb_info *sbi, u32 crc, const void *address, unsigned int length) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 68070b1859803..3e4b9bf101454 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3559,14 +3559,6 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly) } #endif
- if (EXT4_SB(sb)->s_es->s_def_hash_version == DX_HASH_SIPHASH && - !ext4_has_feature_casefold(sb)) { - ext4_msg(sb, KERN_ERR, - "Filesystem without casefold feature cannot be " - "mounted with siphash"); - return 0; - } - if (readonly) return 1;
@@ -5050,16 +5042,27 @@ static int ext4_load_super(struct super_block *sb, ext4_fsblk_t *lsb, return ret; }
-static void ext4_hash_info_init(struct super_block *sb) +static int ext4_hash_info_init(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; unsigned int i;
+ sbi->s_def_hash_version = es->s_def_hash_version; + + if (sbi->s_def_hash_version > DX_HASH_LAST) { + ext4_msg(sb, KERN_ERR, + "Invalid default hash set in the superblock"); + return -EINVAL; + } else if (sbi->s_def_hash_version == DX_HASH_SIPHASH) { + ext4_msg(sb, KERN_ERR, + "SIPHASH is not a valid default hash value"); + return -EINVAL; + } + for (i = 0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
- sbi->s_def_hash_version = es->s_def_hash_version; if (ext4_has_feature_dir_index(sb)) { i = le32_to_cpu(es->s_flags); if (i & EXT2_FLAGS_UNSIGNED_HASH) @@ -5077,6 +5080,7 @@ static void ext4_hash_info_init(struct super_block *sb) #endif } } + return 0; }
static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) @@ -5234,7 +5238,9 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
- ext4_hash_info_init(sb); + err = ext4_hash_info_init(sb); + if (err) + goto failed_mount;
if (ext4_handle_clustersize(sb)) goto failed_mount;
linux-stable-mirror@lists.linaro.org