Skip to contentSkip to conversation

Simplify rejection of unexpected casefold inode flag

PATCH Applied Eric Biggers 4 participants 9 messages Aug 14, 2023 – Sep 4, 2023

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Simplify rejection of unexpected casefold inode flag

This series makes unexpected casefold flags on inodes be consistently rejected early on so that additional validation isn't needed later on during random filesystem operations. For additional context, refer to the discussion on patch 1 of
https://lore.kernel.org/linux-fsdevel/[email protected]/T/#u

Applies to v6.5-rc6

Eric Biggers (3):
ext4: reject casefold inode flag without casefold feature
ext4: remove redundant checks of s_encoding
libfs: remove redundant checks of s_encoding

 fs/ext4/hash.c  |  2 +-
 fs/ext4/inode.c |  5 ++++-
 fs/ext4/namei.c |  6 +++---
 fs/libfs.c      | 14 ++------------
 4 files changed, 10 insertions(+), 17 deletions(-)

base-commit: 2ccdd1b13c591d306f0401d98dedc4bdcd02b421

Signature · 8 lines
2.41.0



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
#1 lore raw

PATCH 1/3 ext4: reject casefold inode flag without casefold feature

From: Eric Biggers <[email protected]>

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.

---
 fs/ext4/inode.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
fs/ext4/inode.c +4 -1
index 43775a6ca505..390dedbb7e8a 100644
@@ -4940,9 +4940,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 ((err_str = check_igot_inode(inode, flags)) != NULL) {
 		ext4_error_inode(inode, function, line, 0, err_str);
 		ret = -EFSCORRUPTED;
Signature · 8 lines
2.41.0



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
#2 lore raw

Re: [PATCH 1/3] ext4: reject casefold inode flag without casefold feature

Quoted 10 lines · Eric Biggers

From: Eric Biggers <[email protected]>

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.

Quoted 9 lines

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.

just because we can't fix the general issue for the entire filesystem doesn't mean this case *must not* ever be addressed. What is the advantage of making the code less robust against the syzbot code? Just check sb->s_encoding and be safe later knowing the unicode map is available.

Quoted 24 lines
---
 fs/ext4/inode.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
fs/ext4/inode.c +4 -1
index 43775a6ca505..390dedbb7e8a 100644
@@ -4940,9 +4940,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 ((err_str = check_igot_inode(inode, flags)) != NULL) {
 		ext4_error_inode(inode, function, line, 0, err_str);
 		ret = -EFSCORRUPTED;
Signature · 7 lines
Gabriel Krisman Bertazi


_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
#3 lore raw

Re: [PATCH 1/3] ext4: reject casefold inode flag without casefold feature

Quoted 22 lines · Gabriel Krisman Bertazi
Quoted 10 lines · Eric Biggers

From: Eric Biggers <[email protected]>

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.

Quoted 9 lines

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.

Quoted 6 lines

just because we can't fix the general issue for the entire filesystem doesn't mean this case *must not* ever be addressed. What is the advantage of making the code less robust against the syzbot code? Just check sb->s_encoding and be safe later knowing the unicode map is available.

Just to make sure, it sounds like you agree that the late checks of ->s_encoding are not needed and only __ext4_iget() should handle it, right? That simplifies the code so it is obviously beneficial if we can do it.

As for whether __ext4_iget() should check the casefold feature or ->s_encoding, we should simply go with the one that makes the code clearer, as per what I've said. I think it's casefold, but it could be ->s_encoding if others prefer.

- Eric

_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

#4 lore raw

Re: [PATCH 1/3] ext4: reject casefold inode flag without casefold feature

Quoted 30 lines · Eric Biggers
Quoted 22 lines · Gabriel Krisman Bertazi
Quoted 10 lines · Eric Biggers

From: Eric Biggers <[email protected]>

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.

Quoted 9 lines

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.

Quoted 6 lines

just because we can't fix the general issue for the entire filesystem doesn't mean this case *must not* ever be addressed. What is the advantage of making the code less robust against the syzbot code? Just check sb->s_encoding and be safe later knowing the unicode map is available.

Quoted 3 lines

Just to make sure, it sounds like you agree that the late checks of ->s_encoding are not needed and only __ext4_iget() should handle it, right? That simplifies the code so it is obviously beneficial if we can do it.

Yes. After we get the inode from __ext4_iget, I think it doesn't matter if the user went behind our back straight to the block device and changed the superblock to remove the feature bit. If we already loaded ->s_encoding, it won't be unloaded, so only checking at ext4_iget should be enough, as far as I can tell.

Signature · 7 lines
Gabriel Krisman Bertazi


_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
#5 lore raw

PATCH 2/3 ext4: remove redundant checks of s_encoding

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

Now that ext4 does not allow inodes with the casefold flag to be instantiated when unsupported, it's unnecessary to repeatedly check for support later on during random filesystem operations.

---
 fs/ext4/hash.c  | 2 +-
 fs/ext4/namei.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
fs/ext4/hash.c +1 -1
index 46c3423ddfa1..deabe29da7fb 100644
@@ -300,7 +300,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
 	unsigned char *buff;
 	struct qstr qstr = {.name = name, .len = len };
 
-	if (len && IS_CASEFOLDED(dir) && um &&
+	if (len && IS_CASEFOLDED(dir) &&
 	   (!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir))) {
 		buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL);
 		if (!buff)
fs/ext4/namei.c +3 -3
index 0caf6c730ce3..f9a5663b9d23 100644
@@ -1445,7 +1445,7 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
 	struct dx_hash_info *hinfo = &name->hinfo;
 	int len;
 
-	if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding ||
+	if (!IS_CASEFOLDED(dir) ||
 	    (IS_ENCRYPTED(dir) && !fscrypt_has_encryption_key(dir))) {
 		cf_name->name = NULL;
 		return 0;
@@ -1496,7 +1496,7 @@ static bool ext4_match(struct inode *parent,
 #endif
 
 #if IS_ENABLED(CONFIG_UNICODE)
-	if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
+	if (IS_CASEFOLDED(parent) &&
 	    (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
 		if (fname->cf_name.name) {
 			struct qstr cf = {.name = fname->cf_name.name,
@@ -2393,7 +2393,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
 
 #if IS_ENABLED(CONFIG_UNICODE)
 	if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
-	    sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
+	    utf8_validate(sb->s_encoding, &dentry->d_name))
 		return -EINVAL;
 #endif
 
Signature · 8 lines
2.41.0



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
#6 lore raw

PATCH 3/3 libfs: remove redundant checks of s_encoding

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

Now that neither ext4 nor f2fs allows inodes with the casefold flag to be instantiated when unsupported, it's unnecessary to repeatedly check for support later on during random filesystem operations.

---
 fs/libfs.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)
fs/libfs.c +2 -12
index 5b851315eeed..5197ea8c66d3 100644
@@ -1381,16 +1381,6 @@ bool is_empty_dir_inode(struct inode *inode)
 }
 
 #if IS_ENABLED(CONFIG_UNICODE)
-/*
- * Determine if the name of a dentry should be casefolded.
- *
- * Return: if names will need casefolding
- */
-static bool needs_casefold(const struct inode *dir)
-{
-	return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding;
-}
-
 /**
  * generic_ci_d_compare - generic d_compare implementation for casefolding filesystems
  * @dentry:	dentry whose name we are checking against
@@ -1411,7 +1401,7 @@ static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
 	char strbuf[DNAME_INLINE_LEN];
 	int ret;
 
-	if (!dir || !needs_casefold(dir))
+	if (!dir || !IS_CASEFOLDED(dir))
 		goto fallback;
 	/*
 	 * If the dentry name is stored in-line, then it may be concurrently
@@ -1453,7 +1443,7 @@ static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
 	const struct unicode_map *um = sb->s_encoding;
 	int ret = 0;
 
-	if (!dir || !needs_casefold(dir))
+	if (!dir || !IS_CASEFOLDED(dir))
 		return 0;
 
 	ret = utf8_casefold_hash(um, dentry, str);
Signature · 8 lines
2.41.0



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
maintainer Applied
#7 lore raw
In reply to Eric Biggers
Quoted 9 lines · Eric Biggers

This series makes unexpected casefold flags on inodes be consistently rejected early on so that additional validation isn't needed later on during random filesystem operations. For additional context, refer to the discussion on patch 1 of
https://lore.kernel.org/linux-fsdevel/[email protected]/T/#u

Applies to v6.5-rc6

[...]

Applied, thanks!

[1/3] ext4: reject casefold inode flag without casefold feature

      commit: 3d0f06b5a4e6d09b4a27d701f2ec9a7de8dadbe5
[2/3] ext4: remove redundant checks of s_encoding
      commit: fe9ef4ceae694597fe7318aafd7357cc5b85724e
[3/3] libfs: remove redundant checks of s_encoding
      commit: 6d7772c4427aaa21251c629d4fabb17e5c10a463

Best regards,

Signature · 7 lines
Theodore Ts'o <[email protected]>


_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
#8 lore raw
In reply to Eric Biggers
This series was applied to jaegeuk/f2fs.git (dev) by Theodore Ts'o <[email protected]>:

Hello:

This series was applied to jaegeuk/f2fs.git (dev)
by Theodore Ts'o <[email protected]>:

Quoted 9 lines · On Mon, 14 Aug 2023 11:29:00 -0700 you wrote:

This series makes unexpected casefold flags on inodes be consistently rejected early on so that additional validation isn't needed later on during random filesystem operations. For additional context, refer to the discussion on patch 1 of
https://lore.kernel.org/linux-fsdevel/[email protected]/T/#u

Applies to v6.5-rc6

[...]

Here is the summary with links:
- [f2fs-dev,1/3] ext4: reject casefold inode flag without casefold feature

    https://git.kernel.org/jaegeuk/f2fs/c/8216776ccff6
  - [f2fs-dev,2/3] ext4: remove redundant checks of s_encoding
    https://git.kernel.org/jaegeuk/f2fs/c/b81427939590
  - [f2fs-dev,3/3] libfs: remove redundant checks of s_encoding
    https://git.kernel.org/jaegeuk/f2fs/c/af494af38580

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html