Skip to content

Commit b5639bb

Browse files
ebiggersJaegeuk Kim
authored andcommitted
f2fs: don't use casefolded comparison for "." and ".."
Tryng to rename a directory that has all following properties fails with EINVAL and triggers the 'WARN_ON_ONCE(!fscrypt_has_encryption_key(dir))' in f2fs_match_ci_name(): - The directory is casefolded - The directory is encrypted - The directory's encryption key is not yet set up - The parent directory is *not* encrypted The problem is incorrect handling of the lookup of ".." to get the parent reference to update. fscrypt_setup_filename() treats ".." (and ".") specially, as it's never encrypted. It's passed through as-is, and setting up the directory's key is not attempted. As the name isn't a no-key name, f2fs treats it as a "normal" name and attempts a casefolded comparison. That breaks the assumption of the WARN_ON_ONCE() in f2fs_match_ci_name() which assumes that for encrypted directories, casefolded comparisons only happen when the directory's key is set up. We could just remove this WARN_ON_ONCE(). However, since casefolding is always a no-op on "." and ".." anyway, let's instead just not casefold these names. This results in the standard bytewise comparison. Fixes: 7ad08a5 ("f2fs: Handle casefolding with Encryption") Cc: <[email protected]> # v5.11+ Signed-off-by: Eric Biggers <[email protected]> Reviewed-by: Gabriel Krisman Bertazi <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent c81d5ba commit b5639bb

File tree

3 files changed

+13
-11
lines changed

3 files changed

+13
-11
lines changed

fs/f2fs/dir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ int f2fs_init_casefolded_name(const struct inode *dir,
8282
#if IS_ENABLED(CONFIG_UNICODE)
8383
struct super_block *sb = dir->i_sb;
8484

85-
if (IS_CASEFOLDED(dir)) {
85+
if (IS_CASEFOLDED(dir) &&
86+
!is_dot_dotdot(fname->usr_fname->name, fname->usr_fname->len)) {
8687
fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
8788
GFP_NOFS, false, F2FS_SB(sb));
8889
if (!fname->cf_name.name)

fs/f2fs/f2fs.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,11 @@ struct f2fs_filename {
508508
#if IS_ENABLED(CONFIG_UNICODE)
509509
/*
510510
* For casefolded directories: the casefolded name, but it's left NULL
511-
* if the original name is not valid Unicode, if the directory is both
512-
* casefolded and encrypted and its encryption key is unavailable, or if
513-
* the filesystem is doing an internal operation where usr_fname is also
514-
* NULL. In all these cases we fall back to treating the name as an
515-
* opaque byte sequence.
511+
* if the original name is not valid Unicode, if the original name is
512+
* "." or "..", if the directory is both casefolded and encrypted and
513+
* its encryption key is unavailable, or if the filesystem is doing an
514+
* internal operation where usr_fname is also NULL. In all these cases
515+
* we fall back to treating the name as an opaque byte sequence.
516516
*/
517517
struct fscrypt_str cf_name;
518518
#endif

fs/f2fs/hash.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static u32 TEA_hash_name(const u8 *p, size_t len)
9191
/*
9292
* Compute @fname->hash. For all directories, @fname->disk_name must be set.
9393
* For casefolded directories, @fname->usr_fname must be set, and also
94-
* @fname->cf_name if the filename is valid Unicode.
94+
* @fname->cf_name if the filename is valid Unicode and is not "." or "..".
9595
*/
9696
void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
9797
{
@@ -110,10 +110,11 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
110110
/*
111111
* If the casefolded name is provided, hash it instead of the
112112
* on-disk name. If the casefolded name is *not* provided, that
113-
* should only be because the name wasn't valid Unicode, so fall
114-
* back to treating the name as an opaque byte sequence. Note
115-
* that to handle encrypted directories, the fallback must use
116-
* usr_fname (plaintext) rather than disk_name (ciphertext).
113+
* should only be because the name wasn't valid Unicode or was
114+
* "." or "..", so fall back to treating the name as an opaque
115+
* byte sequence. Note that to handle encrypted directories,
116+
* the fallback must use usr_fname (plaintext) rather than
117+
* disk_name (ciphertext).
117118
*/
118119
WARN_ON_ONCE(!fname->usr_fname->name);
119120
if (fname->cf_name.name) {

0 commit comments

Comments
 (0)