lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 522/667] f2fs: dont use casefolded comparison for "." and ".."
    Date
    From: Eric Biggers <ebiggers@google.com>

    commit b5639bb4313b9d455fc9fc4768d23a5e4ca8cb9d upstream.

    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: 7ad08a58bf67 ("f2fs: Handle casefolding with Encryption")
    Cc: <stable@vger.kernel.org> # v5.11+
    Signed-off-by: Eric Biggers <ebiggers@google.com>
    Reviewed-by: Gabriel Krisman Bertazi <krisman@collabora.com>
    Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/f2fs/dir.c | 3 ++-
    fs/f2fs/f2fs.h | 10 +++++-----
    fs/f2fs/hash.c | 11 ++++++-----
    3 files changed, 13 insertions(+), 11 deletions(-)

    --- a/fs/f2fs/dir.c
    +++ b/fs/f2fs/dir.c
    @@ -82,7 +82,8 @@ int f2fs_init_casefolded_name(const stru
    #ifdef CONFIG_UNICODE
    struct super_block *sb = dir->i_sb;

    - if (IS_CASEFOLDED(dir)) {
    + if (IS_CASEFOLDED(dir) &&
    + !is_dot_dotdot(fname->usr_fname->name, fname->usr_fname->len)) {
    fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
    GFP_NOFS, false, F2FS_SB(sb));
    if (!fname->cf_name.name)
    --- a/fs/f2fs/f2fs.h
    +++ b/fs/f2fs/f2fs.h
    @@ -488,11 +488,11 @@ struct f2fs_filename {
    #ifdef CONFIG_UNICODE
    /*
    * For casefolded directories: the casefolded name, but it's left NULL
    - * if the original name is not valid Unicode, if the directory is both
    - * casefolded and encrypted and its encryption key is unavailable, or if
    - * the filesystem is doing an internal operation where usr_fname is also
    - * NULL. In all these cases we fall back to treating the name as an
    - * opaque byte sequence.
    + * if the original name is not valid Unicode, if the original name is
    + * "." or "..", if the directory is both casefolded and encrypted and
    + * its encryption key is unavailable, or if the filesystem is doing an
    + * internal operation where usr_fname is also NULL. In all these cases
    + * we fall back to treating the name as an opaque byte sequence.
    */
    struct fscrypt_str cf_name;
    #endif
    --- a/fs/f2fs/hash.c
    +++ b/fs/f2fs/hash.c
    @@ -91,7 +91,7 @@ static u32 TEA_hash_name(const u8 *p, si
    /*
    * Compute @fname->hash. For all directories, @fname->disk_name must be set.
    * For casefolded directories, @fname->usr_fname must be set, and also
    - * @fname->cf_name if the filename is valid Unicode.
    + * @fname->cf_name if the filename is valid Unicode and is not "." or "..".
    */
    void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
    {
    @@ -110,10 +110,11 @@ void f2fs_hash_filename(const struct ino
    /*
    * If the casefolded name is provided, hash it instead of the
    * on-disk name. If the casefolded name is *not* provided, that
    - * should only be because the name wasn't valid Unicode, so fall
    - * back to treating the name as an opaque byte sequence. Note
    - * that to handle encrypted directories, the fallback must use
    - * usr_fname (plaintext) rather than disk_name (ciphertext).
    + * should only be because the name wasn't valid Unicode or was
    + * "." or "..", so fall back to treating the name as an opaque
    + * byte sequence. Note that to handle encrypted directories,
    + * the fallback must use usr_fname (plaintext) rather than
    + * disk_name (ciphertext).
    */
    WARN_ON_ONCE(!fname->usr_fname->name);
    if (fname->cf_name.name) {

    \
     
     \ /
      Last update: 2022-06-07 21:49    [W:3.455 / U:0.172 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site