All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
@ 2020-11-17 12:55 kernel test robot
  0 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2020-11-17 12:55 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 3487 bytes --]

CC: kbuild-all(a)lists.01.org
In-Reply-To: <20201117040315.28548-4-drosen@google.com>
References: <20201117040315.28548-4-drosen@google.com>
TO: Daniel Rosenberg <drosen@google.com>

Hi Daniel,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on f2fs/dev-test]
[also build test WARNING on ext4/dev linus/master v5.10-rc4 next-20201117]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Daniel-Rosenberg/Add-support-for-Encryption-and-Casefolding-in-F2FS/20201117-120753
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev-test
:::::: branch date: 9 hours ago
:::::: commit date: 9 hours ago
compiler: aarch64-linux-gcc (GCC) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


cppcheck possible warnings: (new ones prefixed by >>, may not real problems)

>> fs/f2fs/dir.c:206:3: warning: Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? [uselessAssignmentPtrArg]
     dentry_page = ERR_CAST(res);
     ^
   fs/f2fs/f2fs.h:2200:15: warning: Local variable valid_node_count shadows outer function [shadowFunction]
    unsigned int valid_node_count, user_block_count;
                 ^
   fs/f2fs/f2fs.h:2296:28: note: Shadowed declaration
   static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
                              ^
   fs/f2fs/f2fs.h:2200:15: note: Shadow variable
    unsigned int valid_node_count, user_block_count;
                 ^

vim +206 fs/f2fs/dir.c

6b4ea0160ae236a Jaegeuk Kim      2012-11-14  191  
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  192  static struct f2fs_dir_entry *find_in_block(struct inode *dir,
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  193  				struct page *dentry_page,
43c780ba26244e4 Eric Biggers     2020-05-07  194  				const struct f2fs_filename *fname,
17f930e0a649e15 Chao Yu          2020-09-26  195  				int *max_slots)
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  196  {
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  197  	struct f2fs_dentry_block *dentry_blk;
7b3cd7d6f026784 Jaegeuk Kim      2014-10-18  198  	struct f2fs_dentry_ptr d;
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  199  	struct f2fs_dir_entry *res;
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  200  
bdbc90fa55af632 Yunlong Song     2018-02-28  201  	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
7b3cd7d6f026784 Jaegeuk Kim      2014-10-18  202  
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  203  	make_dentry_ptr_block(dir, &d, dentry_blk);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  204  	res = f2fs_find_target_dentry(&d, fname, max_slots);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  205  	if (IS_ERR(res)) {
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17 @206  		dentry_page = ERR_CAST(res);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  207  		res = NULL;
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  208  	}
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  209  	return res;
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  210  }
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  211  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
  2020-11-18  6:22       ` Daniel Rosenberg
@ 2020-11-18  6:27         ` Eric Biggers
  -1 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2020-11-18  6:27 UTC (permalink / raw)
  To: Daniel Rosenberg
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
	Alexander Viro, Richard Weinberger, linux-fscrypt, linux-ext4,
	linux-f2fs-devel, linux-kernel, linux-fsdevel, linux-mtd,
	Gabriel Krisman Bertazi, kernel-team

On Tue, Nov 17, 2020 at 10:22:28PM -0800, Daniel Rosenberg wrote:
> > > @@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
> > >                       continue;
> > >               }
> > >
> > > -             if (de->hash_code == fname->hash &&
> > > -                 f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > > -                                 le16_to_cpu(de->name_len)))
> > > -                     goto found;
> > > +             if (de->hash_code == fname->hash) {
> > > +                     res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > > +                                 le16_to_cpu(de->name_len));
> > > +                     if (res < 0)
> > > +                             return ERR_PTR(res);
> > > +                     else if (res)
> > > +                             goto found;
> > > +             }
> >
> > Overly long line here.  Also 'else if' is unnecessary, just use 'if'.
> >
> > - Eric
> The 0 case is important, since that reflects that the name was not found.

I meant doing the following:

	if (res < 0)
		return ERR_PTR(res);
	if (res)
		goto found;

It doesn't really matter, but usually kernel code doesn't use 'else' after an
early return.

- Eric

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
@ 2020-11-18  6:27         ` Eric Biggers
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2020-11-18  6:27 UTC (permalink / raw)
  To: Daniel Rosenberg
  Cc: kernel-team, Theodore Y . Ts'o, Richard Weinberger, Chao Yu,
	linux-kernel, linux-f2fs-devel, linux-fscrypt, Andreas Dilger,
	Alexander Viro, linux-mtd, linux-fsdevel, Jaegeuk Kim,
	linux-ext4, Gabriel Krisman Bertazi

On Tue, Nov 17, 2020 at 10:22:28PM -0800, Daniel Rosenberg wrote:
> > > @@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
> > >                       continue;
> > >               }
> > >
> > > -             if (de->hash_code == fname->hash &&
> > > -                 f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > > -                                 le16_to_cpu(de->name_len)))
> > > -                     goto found;
> > > +             if (de->hash_code == fname->hash) {
> > > +                     res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > > +                                 le16_to_cpu(de->name_len));
> > > +                     if (res < 0)
> > > +                             return ERR_PTR(res);
> > > +                     else if (res)
> > > +                             goto found;
> > > +             }
> >
> > Overly long line here.  Also 'else if' is unnecessary, just use 'if'.
> >
> > - Eric
> The 0 case is important, since that reflects that the name was not found.

I meant doing the following:

	if (res < 0)
		return ERR_PTR(res);
	if (res)
		goto found;

It doesn't really matter, but usually kernel code doesn't use 'else' after an
early return.

- Eric

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
  2020-11-17 18:50     ` Eric Biggers
@ 2020-11-18  6:22       ` Daniel Rosenberg
  -1 siblings, 0 replies; 11+ messages in thread
From: Daniel Rosenberg @ 2020-11-18  6:22 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
	Alexander Viro, Richard Weinberger, linux-fscrypt, linux-ext4,
	linux-f2fs-devel, linux-kernel, linux-fsdevel, linux-mtd,
	Gabriel Krisman Bertazi, kernel-team

On Tue, Nov 17, 2020 at 10:50 AM Eric Biggers <ebiggers@kernel.org> wrote:
>
>
> What is the assignment to dentry_page supposed to be accomplishing?  It looks
> like it's meant to pass up errors from f2fs_find_target_dentry(), but it doesn't
> do that.

Woops. Fixed that for the next version.

>
> > @@ -222,14 +250,20 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
> >                * fall back to treating them as opaque byte sequences.
> >                */
> >               if (sb_has_strict_encoding(sb) || name->len != entry.len)
> > -                     return false;
> > -             return !memcmp(name->name, entry.name, name->len);
> > +                     res = 0;
> > +             else
> > +                     res = memcmp(name->name, entry.name, name->len) == 0;
> > +     } else {
> > +             /* utf8_strncasecmp_folded returns 0 on match */
> > +             res = (res == 0);
> >       }
>
> The following might be easier to understand:
>
>         /*
>          * In strict mode, ignore invalid names.  In non-strict mode, fall back
>          * to treating them as opaque byte sequences.
>          */
>         if (res < 0 && !sb_has_strict_encoding(sb)) {
>                 res = name->len == entry.len &&
>                       memcmp(name->name, entry.name, name->len) == 0;
>         } else {
>                 /* utf8_strncasecmp_folded returns 0 on match */
>                 res = (res == 0);
>         }
>
Thanks, that is a fair bit nicer.

> > @@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
> >                       continue;
> >               }
> >
> > -             if (de->hash_code == fname->hash &&
> > -                 f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > -                                 le16_to_cpu(de->name_len)))
> > -                     goto found;
> > +             if (de->hash_code == fname->hash) {
> > +                     res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > +                                 le16_to_cpu(de->name_len));
> > +                     if (res < 0)
> > +                             return ERR_PTR(res);
> > +                     else if (res)
> > +                             goto found;
> > +             }
>
> Overly long line here.  Also 'else if' is unnecessary, just use 'if'.
>
> - Eric
The 0 case is important, since that reflects that the name was not found.
-Daniel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
@ 2020-11-18  6:22       ` Daniel Rosenberg
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Rosenberg @ 2020-11-18  6:22 UTC (permalink / raw)
  To: Eric Biggers
  Cc: kernel-team, Theodore Y . Ts'o, Richard Weinberger, Chao Yu,
	linux-kernel, linux-f2fs-devel, linux-fscrypt, Andreas Dilger,
	Alexander Viro, linux-mtd, linux-fsdevel, Jaegeuk Kim,
	linux-ext4, Gabriel Krisman Bertazi

On Tue, Nov 17, 2020 at 10:50 AM Eric Biggers <ebiggers@kernel.org> wrote:
>
>
> What is the assignment to dentry_page supposed to be accomplishing?  It looks
> like it's meant to pass up errors from f2fs_find_target_dentry(), but it doesn't
> do that.

Woops. Fixed that for the next version.

>
> > @@ -222,14 +250,20 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
> >                * fall back to treating them as opaque byte sequences.
> >                */
> >               if (sb_has_strict_encoding(sb) || name->len != entry.len)
> > -                     return false;
> > -             return !memcmp(name->name, entry.name, name->len);
> > +                     res = 0;
> > +             else
> > +                     res = memcmp(name->name, entry.name, name->len) == 0;
> > +     } else {
> > +             /* utf8_strncasecmp_folded returns 0 on match */
> > +             res = (res == 0);
> >       }
>
> The following might be easier to understand:
>
>         /*
>          * In strict mode, ignore invalid names.  In non-strict mode, fall back
>          * to treating them as opaque byte sequences.
>          */
>         if (res < 0 && !sb_has_strict_encoding(sb)) {
>                 res = name->len == entry.len &&
>                       memcmp(name->name, entry.name, name->len) == 0;
>         } else {
>                 /* utf8_strncasecmp_folded returns 0 on match */
>                 res = (res == 0);
>         }
>
Thanks, that is a fair bit nicer.

> > @@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
> >                       continue;
> >               }
> >
> > -             if (de->hash_code == fname->hash &&
> > -                 f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > -                                 le16_to_cpu(de->name_len)))
> > -                     goto found;
> > +             if (de->hash_code == fname->hash) {
> > +                     res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> > +                                 le16_to_cpu(de->name_len));
> > +                     if (res < 0)
> > +                             return ERR_PTR(res);
> > +                     else if (res)
> > +                             goto found;
> > +             }
>
> Overly long line here.  Also 'else if' is unnecessary, just use 'if'.
>
> - Eric
The 0 case is important, since that reflects that the name was not found.
-Daniel

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
  2020-11-17  4:03   ` Daniel Rosenberg
                     ` (2 preceding siblings ...)
  (?)
@ 2020-11-18  1:03   ` kernel test robot
  -1 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2020-11-18  1:03 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 3307 bytes --]

Hi Daniel,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on f2fs/dev-test]
[also build test WARNING on ext4/dev linus/master v5.10-rc4 next-20201117]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Daniel-Rosenberg/Add-support-for-Encryption-and-Casefolding-in-F2FS/20201117-120753
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev-test
:::::: branch date: 9 hours ago
:::::: commit date: 9 hours ago
compiler: aarch64-linux-gcc (GCC) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <rong.a.chen@intel.com>


cppcheck possible warnings: (new ones prefixed by >>, may not real problems)

>> fs/f2fs/dir.c:206:3: warning: Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? [uselessAssignmentPtrArg]
     dentry_page = ERR_CAST(res);
     ^
   fs/f2fs/f2fs.h:2200:15: warning: Local variable valid_node_count shadows outer function [shadowFunction]
    unsigned int valid_node_count, user_block_count;
                 ^
   fs/f2fs/f2fs.h:2296:28: note: Shadowed declaration
   static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
                              ^
   fs/f2fs/f2fs.h:2200:15: note: Shadow variable
    unsigned int valid_node_count, user_block_count;
                 ^

vim +206 fs/f2fs/dir.c

6b4ea0160ae236a Jaegeuk Kim      2012-11-14  191  
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  192  static struct f2fs_dir_entry *find_in_block(struct inode *dir,
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  193  				struct page *dentry_page,
43c780ba26244e4 Eric Biggers     2020-05-07  194  				const struct f2fs_filename *fname,
17f930e0a649e15 Chao Yu          2020-09-26  195  				int *max_slots)
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  196  {
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  197  	struct f2fs_dentry_block *dentry_blk;
7b3cd7d6f026784 Jaegeuk Kim      2014-10-18  198  	struct f2fs_dentry_ptr d;
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  199  	struct f2fs_dir_entry *res;
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  200  
bdbc90fa55af632 Yunlong Song     2018-02-28  201  	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
7b3cd7d6f026784 Jaegeuk Kim      2014-10-18  202  
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  203  	make_dentry_ptr_block(dir, &d, dentry_blk);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  204  	res = f2fs_find_target_dentry(&d, fname, max_slots);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  205  	if (IS_ERR(res)) {
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17 @206  		dentry_page = ERR_CAST(res);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  207  		res = NULL;
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  208  	}
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  209  	return res;
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  210  }
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  211  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
  2020-11-17  4:03   ` Daniel Rosenberg
@ 2020-11-17 18:50     ` Eric Biggers
  -1 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2020-11-17 18:50 UTC (permalink / raw)
  To: Daniel Rosenberg
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
	Alexander Viro, Richard Weinberger, linux-fscrypt, linux-ext4,
	linux-f2fs-devel, linux-kernel, linux-fsdevel, linux-mtd,
	Gabriel Krisman Bertazi, kernel-team

On Tue, Nov 17, 2020 at 04:03:15AM +0000, Daniel Rosenberg wrote:
> Expand f2fs's casefolding support to include encrypted directories.  To
> index casefolded+encrypted directories, we use the SipHash of the
> casefolded name, keyed by a key derived from the directory's fscrypt
> master key.  This ensures that the dirhash doesn't leak information
> about the plaintext filenames.
> 
> Encryption keys are unavailable during roll-forward recovery, so we
> can't compute the dirhash when recovering a new dentry in an encrypted +
> casefolded directory.  To avoid having to force a checkpoint when a new
> file is fsync'ed, store the dirhash on-disk appended to i_name.
> 
> This patch incorporates work by Eric Biggers <ebiggers@google.com>
> and Jaegeuk Kim <jaegeuk@kernel.org>.
> 
> Co-developed-by: Eric Biggers <ebiggers@google.com>
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> Signed-off-by: Daniel Rosenberg <drosen@google.com>
> ---
>  fs/f2fs/dir.c      | 89 +++++++++++++++++++++++++++++++++++++---------
>  fs/f2fs/f2fs.h     |  8 +++--
>  fs/f2fs/hash.c     | 11 +++++-
>  fs/f2fs/inline.c   |  4 +++
>  fs/f2fs/recovery.c | 12 ++++++-
>  fs/f2fs/super.c    |  6 ----
>  6 files changed, 103 insertions(+), 27 deletions(-)
> 
> diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
> index 71fdf5076461..0adc6bcfb5c0 100644
> --- a/fs/f2fs/dir.c
> +++ b/fs/f2fs/dir.c
> @@ -5,6 +5,7 @@
>   * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>   *             http://www.samsung.com/
>   */
> +#include <asm/unaligned.h>
>  #include <linux/fs.h>
>  #include <linux/f2fs_fs.h>
>  #include <linux/sched/signal.h>
> @@ -195,26 +196,53 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
>  {
>  	struct f2fs_dentry_block *dentry_blk;
>  	struct f2fs_dentry_ptr d;
> +	struct f2fs_dir_entry *res;
>  
>  	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
>  
>  	make_dentry_ptr_block(dir, &d, dentry_blk);
> -	return f2fs_find_target_dentry(&d, fname, max_slots);
> +	res = f2fs_find_target_dentry(&d, fname, max_slots);
> +	if (IS_ERR(res)) {
> +		dentry_page = ERR_CAST(res);
> +		res = NULL;
> +	}
> +	return res;
>  }

What is the assignment to dentry_page supposed to be accomplishing?  It looks
like it's meant to pass up errors from f2fs_find_target_dentry(), but it doesn't
do that.

> @@ -222,14 +250,20 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
>  		 * fall back to treating them as opaque byte sequences.
>  		 */
>  		if (sb_has_strict_encoding(sb) || name->len != entry.len)
> -			return false;
> -		return !memcmp(name->name, entry.name, name->len);
> +			res = 0;
> +		else
> +			res = memcmp(name->name, entry.name, name->len) == 0;
> +	} else {
> +		/* utf8_strncasecmp_folded returns 0 on match */
> +		res = (res == 0);
>  	}

The following might be easier to understand:

	/*
	 * In strict mode, ignore invalid names.  In non-strict mode, fall back
	 * to treating them as opaque byte sequences.
	 */
	if (res < 0 && !sb_has_strict_encoding(sb)) {
		res = name->len == entry.len &&
		      memcmp(name->name, entry.name, name->len) == 0;
	} else {
		/* utf8_strncasecmp_folded returns 0 on match */
		res = (res == 0);
	}

> @@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
>  			continue;
>  		}
>  
> -		if (de->hash_code == fname->hash &&
> -		    f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> -				    le16_to_cpu(de->name_len)))
> -			goto found;
> +		if (de->hash_code == fname->hash) {
> +			res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> +				    le16_to_cpu(de->name_len));
> +			if (res < 0)
> +				return ERR_PTR(res);
> +			else if (res)
> +				goto found;
> +		}

Overly long line here.  Also 'else if' is unnecessary, just use 'if'.

- Eric

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
@ 2020-11-17 18:50     ` Eric Biggers
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Biggers @ 2020-11-17 18:50 UTC (permalink / raw)
  To: Daniel Rosenberg
  Cc: kernel-team, Theodore Y . Ts'o, Richard Weinberger, Chao Yu,
	linux-kernel, linux-f2fs-devel, linux-fscrypt, Andreas Dilger,
	Alexander Viro, linux-mtd, linux-fsdevel, Jaegeuk Kim,
	linux-ext4, Gabriel Krisman Bertazi

On Tue, Nov 17, 2020 at 04:03:15AM +0000, Daniel Rosenberg wrote:
> Expand f2fs's casefolding support to include encrypted directories.  To
> index casefolded+encrypted directories, we use the SipHash of the
> casefolded name, keyed by a key derived from the directory's fscrypt
> master key.  This ensures that the dirhash doesn't leak information
> about the plaintext filenames.
> 
> Encryption keys are unavailable during roll-forward recovery, so we
> can't compute the dirhash when recovering a new dentry in an encrypted +
> casefolded directory.  To avoid having to force a checkpoint when a new
> file is fsync'ed, store the dirhash on-disk appended to i_name.
> 
> This patch incorporates work by Eric Biggers <ebiggers@google.com>
> and Jaegeuk Kim <jaegeuk@kernel.org>.
> 
> Co-developed-by: Eric Biggers <ebiggers@google.com>
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> Signed-off-by: Daniel Rosenberg <drosen@google.com>
> ---
>  fs/f2fs/dir.c      | 89 +++++++++++++++++++++++++++++++++++++---------
>  fs/f2fs/f2fs.h     |  8 +++--
>  fs/f2fs/hash.c     | 11 +++++-
>  fs/f2fs/inline.c   |  4 +++
>  fs/f2fs/recovery.c | 12 ++++++-
>  fs/f2fs/super.c    |  6 ----
>  6 files changed, 103 insertions(+), 27 deletions(-)
> 
> diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
> index 71fdf5076461..0adc6bcfb5c0 100644
> --- a/fs/f2fs/dir.c
> +++ b/fs/f2fs/dir.c
> @@ -5,6 +5,7 @@
>   * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>   *             http://www.samsung.com/
>   */
> +#include <asm/unaligned.h>
>  #include <linux/fs.h>
>  #include <linux/f2fs_fs.h>
>  #include <linux/sched/signal.h>
> @@ -195,26 +196,53 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
>  {
>  	struct f2fs_dentry_block *dentry_blk;
>  	struct f2fs_dentry_ptr d;
> +	struct f2fs_dir_entry *res;
>  
>  	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
>  
>  	make_dentry_ptr_block(dir, &d, dentry_blk);
> -	return f2fs_find_target_dentry(&d, fname, max_slots);
> +	res = f2fs_find_target_dentry(&d, fname, max_slots);
> +	if (IS_ERR(res)) {
> +		dentry_page = ERR_CAST(res);
> +		res = NULL;
> +	}
> +	return res;
>  }

What is the assignment to dentry_page supposed to be accomplishing?  It looks
like it's meant to pass up errors from f2fs_find_target_dentry(), but it doesn't
do that.

> @@ -222,14 +250,20 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
>  		 * fall back to treating them as opaque byte sequences.
>  		 */
>  		if (sb_has_strict_encoding(sb) || name->len != entry.len)
> -			return false;
> -		return !memcmp(name->name, entry.name, name->len);
> +			res = 0;
> +		else
> +			res = memcmp(name->name, entry.name, name->len) == 0;
> +	} else {
> +		/* utf8_strncasecmp_folded returns 0 on match */
> +		res = (res == 0);
>  	}

The following might be easier to understand:

	/*
	 * In strict mode, ignore invalid names.  In non-strict mode, fall back
	 * to treating them as opaque byte sequences.
	 */
	if (res < 0 && !sb_has_strict_encoding(sb)) {
		res = name->len == entry.len &&
		      memcmp(name->name, entry.name, name->len) == 0;
	} else {
		/* utf8_strncasecmp_folded returns 0 on match */
		res = (res == 0);
	}

> @@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
>  			continue;
>  		}
>  
> -		if (de->hash_code == fname->hash &&
> -		    f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> -				    le16_to_cpu(de->name_len)))
> -			goto found;
> +		if (de->hash_code == fname->hash) {
> +			res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
> +				    le16_to_cpu(de->name_len));
> +			if (res < 0)
> +				return ERR_PTR(res);
> +			else if (res)
> +				goto found;
> +		}

Overly long line here.  Also 'else if' is unnecessary, just use 'if'.

- Eric

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
  2020-11-17  4:03   ` Daniel Rosenberg
  (?)
@ 2020-11-17 14:06   ` Dan Carpenter
  -1 siblings, 0 replies; 11+ messages in thread
From: Dan Carpenter @ 2020-11-17 14:06 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 3013 bytes --]

Hi Daniel,

url:    https://github.com/0day-ci/linux/commits/Daniel-Rosenberg/Add-support-for-Encryption-and-Casefolding-in-F2FS/20201117-120753 
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git  dev-test
compiler: aarch64-linux-gcc (GCC) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

cppcheck possible warnings: (new ones prefixed by >>, may not real problems)

>> fs/f2fs/dir.c:206:3: warning: Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? [uselessAssignmentPtrArg]
     dentry_page = ERR_CAST(res);
     ^
   fs/f2fs/f2fs.h:2200:15: warning: Local variable valid_node_count shadows outer function [shadowFunction]
    unsigned int valid_node_count, user_block_count;
                 ^
   fs/f2fs/f2fs.h:2296:28: note: Shadowed declaration
   static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
                              ^
   fs/f2fs/f2fs.h:2200:15: note: Shadow variable
    unsigned int valid_node_count, user_block_count;
                 ^

vim +206 fs/f2fs/dir.c

2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  192  static struct f2fs_dir_entry *find_in_block(struct inode *dir,
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  193  				struct page *dentry_page,
43c780ba26244e4 Eric Biggers     2020-05-07  194  				const struct f2fs_filename *fname,
17f930e0a649e15 Chao Yu          2020-09-26  195  				int *max_slots)
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  196  {
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  197  	struct f2fs_dentry_block *dentry_blk;
7b3cd7d6f026784 Jaegeuk Kim      2014-10-18  198  	struct f2fs_dentry_ptr d;
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  199  	struct f2fs_dir_entry *res;
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  200  
bdbc90fa55af632 Yunlong Song     2018-02-28  201  	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
7b3cd7d6f026784 Jaegeuk Kim      2014-10-18  202  
2c2eb7a300cd7c6 Daniel Rosenberg 2019-07-23  203  	make_dentry_ptr_block(dir, &d, dentry_blk);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  204  	res = f2fs_find_target_dentry(&d, fname, max_slots);
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  205  	if (IS_ERR(res)) {
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17 @206  		dentry_page = ERR_CAST(res);
                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  207  		res = NULL;
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  208  	}
6f0a1d1d8d24e7e Daniel Rosenberg 2020-11-17  209  	return res;
4e6ebf6d4935914 Jaegeuk Kim      2014-10-13  210  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org 
_______________________________________________
kbuild mailing list -- kbuild(a)lists.01.org
To unsubscribe send an email to kbuild-leave(a)lists.01.org

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
  2020-11-17  4:03 [PATCH v2 0/3] Add support for Encryption and Casefolding in F2FS Daniel Rosenberg
@ 2020-11-17  4:03   ` Daniel Rosenberg
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Rosenberg @ 2020-11-17  4:03 UTC (permalink / raw)
  To: Theodore Y . Ts'o, Jaegeuk Kim, Eric Biggers, Andreas Dilger,
	Chao Yu, Alexander Viro, Richard Weinberger, linux-fscrypt,
	linux-ext4, linux-f2fs-devel
  Cc: linux-kernel, linux-fsdevel, linux-mtd, Gabriel Krisman Bertazi,
	kernel-team, Daniel Rosenberg, Eric Biggers

Expand f2fs's casefolding support to include encrypted directories.  To
index casefolded+encrypted directories, we use the SipHash of the
casefolded name, keyed by a key derived from the directory's fscrypt
master key.  This ensures that the dirhash doesn't leak information
about the plaintext filenames.

Encryption keys are unavailable during roll-forward recovery, so we
can't compute the dirhash when recovering a new dentry in an encrypted +
casefolded directory.  To avoid having to force a checkpoint when a new
file is fsync'ed, store the dirhash on-disk appended to i_name.

This patch incorporates work by Eric Biggers <ebiggers@google.com>
and Jaegeuk Kim <jaegeuk@kernel.org>.

Co-developed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Daniel Rosenberg <drosen@google.com>
---
 fs/f2fs/dir.c      | 89 +++++++++++++++++++++++++++++++++++++---------
 fs/f2fs/f2fs.h     |  8 +++--
 fs/f2fs/hash.c     | 11 +++++-
 fs/f2fs/inline.c   |  4 +++
 fs/f2fs/recovery.c | 12 ++++++-
 fs/f2fs/super.c    |  6 ----
 6 files changed, 103 insertions(+), 27 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 71fdf5076461..0adc6bcfb5c0 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  */
+#include <asm/unaligned.h>
 #include <linux/fs.h>
 #include <linux/f2fs_fs.h>
 #include <linux/sched/signal.h>
@@ -195,26 +196,53 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
 {
 	struct f2fs_dentry_block *dentry_blk;
 	struct f2fs_dentry_ptr d;
+	struct f2fs_dir_entry *res;
 
 	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
 
 	make_dentry_ptr_block(dir, &d, dentry_blk);
-	return f2fs_find_target_dentry(&d, fname, max_slots);
+	res = f2fs_find_target_dentry(&d, fname, max_slots);
+	if (IS_ERR(res)) {
+		dentry_page = ERR_CAST(res);
+		res = NULL;
+	}
+	return res;
 }
 
 #ifdef CONFIG_UNICODE
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.
+ *
+ * Returns 1 for a match, 0 for no match, and -errno on an error.
  */
-static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
+static int f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
 			       const u8 *de_name, u32 de_name_len)
 {
 	const struct super_block *sb = dir->i_sb;
 	const struct unicode_map *um = sb->s_encoding;
+	struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
 	struct qstr entry = QSTR_INIT(de_name, de_name_len);
 	int res;
 
+	if (IS_ENCRYPTED(dir)) {
+		const struct fscrypt_str encrypted_name =
+			FSTR_INIT((u8 *)de_name, de_name_len);
+
+		if (WARN_ON_ONCE(!fscrypt_has_encryption_key(dir)))
+			return -EINVAL;
+
+		decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
+		if (!decrypted_name.name)
+			return -ENOMEM;
+		res = fscrypt_fname_disk_to_usr(dir, 0, 0, &encrypted_name,
+						&decrypted_name);
+		if (res < 0)
+			goto out;
+		entry.name = decrypted_name.name;
+		entry.len = decrypted_name.len;
+	}
+
 	res = utf8_strncasecmp_folded(um, name, &entry);
 	if (res < 0) {
 		/*
@@ -222,14 +250,20 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
 		 * fall back to treating them as opaque byte sequences.
 		 */
 		if (sb_has_strict_encoding(sb) || name->len != entry.len)
-			return false;
-		return !memcmp(name->name, entry.name, name->len);
+			res = 0;
+		else
+			res = memcmp(name->name, entry.name, name->len) == 0;
+	} else {
+		/* utf8_strncasecmp_folded returns 0 on match */
+		res = (res == 0);
 	}
-	return res == 0;
+out:
+	kfree(decrypted_name.name);
+	return res;
 }
 #endif /* CONFIG_UNICODE */
 
-static inline bool f2fs_match_name(const struct inode *dir,
+static inline int f2fs_match_name(const struct inode *dir,
 				   const struct f2fs_filename *fname,
 				   const u8 *de_name, u32 de_name_len)
 {
@@ -256,6 +290,7 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
 	struct f2fs_dir_entry *de;
 	unsigned long bit_pos = 0;
 	int max_len = 0;
+	int res = 0;
 
 	if (max_slots)
 		*max_slots = 0;
@@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
 			continue;
 		}
 
-		if (de->hash_code == fname->hash &&
-		    f2fs_match_name(d->inode, fname, d->filename[bit_pos],
-				    le16_to_cpu(de->name_len)))
-			goto found;
+		if (de->hash_code == fname->hash) {
+			res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
+				    le16_to_cpu(de->name_len));
+			if (res < 0)
+				return ERR_PTR(res);
+			else if (res)
+				goto found;
+		}
 
 		if (max_slots && max_len > *max_slots)
 			*max_slots = max_len;
@@ -448,17 +487,39 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
 	f2fs_put_page(page, 1);
 }
 
-static void init_dent_inode(const struct f2fs_filename *fname,
+static void init_dent_inode(struct inode *dir, struct inode *inode,
+			    const struct f2fs_filename *fname,
 			    struct page *ipage)
 {
 	struct f2fs_inode *ri;
 
+	if (!fname) /* tmpfile case? */
+		return;
+
 	f2fs_wait_on_page_writeback(ipage, NODE, true, true);
 
 	/* copy name info. to this inode page */
 	ri = F2FS_INODE(ipage);
 	ri->i_namelen = cpu_to_le32(fname->disk_name.len);
 	memcpy(ri->i_name, fname->disk_name.name, fname->disk_name.len);
+	if (IS_ENCRYPTED(dir)) {
+		file_set_enc_name(inode);
+		/*
+		 * Roll-forward recovery doesn't have encryption keys available,
+		 * so it can't compute the dirhash for encrypted+casefolded
+		 * filenames.  Append it to i_name if possible.  Else, disable
+		 * roll-forward recovery of the dentry (i.e., make fsync'ing the
+		 * file force a checkpoint) by setting LOST_PINO.
+		 */
+		if (IS_CASEFOLDED(dir)) {
+			if (fname->disk_name.len + sizeof(f2fs_hash_t) <=
+			    F2FS_NAME_LEN)
+				put_unaligned(fname->hash, (f2fs_hash_t *)
+					&ri->i_name[fname->disk_name.len]);
+			else
+				file_lost_pino(inode);
+		}
+	}
 	set_page_dirty(ipage);
 }
 
@@ -541,11 +602,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
 			return page;
 	}
 
-	if (fname) {
-		init_dent_inode(fname, page);
-		if (IS_ENCRYPTED(dir))
-			file_set_enc_name(inode);
-	}
+	init_dent_inode(dir, inode, fname, page);
 
 	/*
 	 * This file should be checkpointed during fsync.
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 62b4f31d30e2..878308736761 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -533,9 +533,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 or if the filesystem is
-	 * doing an internal operation where usr_fname is also NULL.  In these
-	 * cases we fall back to treating the name as an opaque byte sequence.
+	 * 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.
 	 */
 	struct fscrypt_str cf_name;
 #endif
diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c
index de841aaf3c43..e3beac546c63 100644
--- a/fs/f2fs/hash.c
+++ b/fs/f2fs/hash.c
@@ -111,7 +111,9 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
 		 * 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.
+		 * 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) {
@@ -121,6 +123,13 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
 			name = fname->usr_fname->name;
 			len = fname->usr_fname->len;
 		}
+		if (IS_ENCRYPTED(dir)) {
+			struct qstr tmp = QSTR_INIT(name, len);
+
+			fname->hash =
+				cpu_to_le32(fscrypt_fname_siphash(dir, &tmp));
+			return;
+		}
 	}
 #endif
 	fname->hash = cpu_to_le32(TEA_hash_name(name, len));
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 70384e31788d..92e9852d316a 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -332,6 +332,10 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
 	make_dentry_ptr_inline(dir, &d, inline_dentry);
 	de = f2fs_find_target_dentry(&d, fname, NULL);
 	unlock_page(ipage);
+	if (IS_ERR(de)) {
+		*res_page = ERR_CAST(de);
+		de = NULL;
+	}
 	if (de)
 		*res_page = ipage;
 	else
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 4f12ade6410a..0947d36af1a8 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  */
+#include <asm/unaligned.h>
 #include <linux/fs.h>
 #include <linux/f2fs_fs.h>
 #include "f2fs.h"
@@ -128,7 +129,16 @@ static int init_recovered_filename(const struct inode *dir,
 	}
 
 	/* Compute the hash of the filename */
-	if (IS_CASEFOLDED(dir)) {
+	if (IS_ENCRYPTED(dir) && IS_CASEFOLDED(dir)) {
+		/*
+		 * In this case the hash isn't computable without the key, so it
+		 * was saved on-disk.
+		 */
+		if (fname->disk_name.len + sizeof(f2fs_hash_t) > F2FS_NAME_LEN)
+			return -EINVAL;
+		fname->hash = get_unaligned((f2fs_hash_t *)
+				&raw_inode->i_name[fname->disk_name.len]);
+	} else if (IS_CASEFOLDED(dir)) {
 		err = f2fs_init_casefolded_name(dir, fname);
 		if (err)
 			return err;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index f51d52591c99..42293b7ceaf2 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3399,12 +3399,6 @@ static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
 		struct unicode_map *encoding;
 		__u16 encoding_flags;
 
-		if (f2fs_sb_has_encrypt(sbi)) {
-			f2fs_err(sbi,
-				"Can't mount with encoding and encryption");
-			return -EINVAL;
-		}
-
 		if (f2fs_sb_read_encoding(sbi->raw_super, &encoding_info,
 					  &encoding_flags)) {
 			f2fs_err(sbi,
-- 
2.29.2.299.gdc1121823c-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/3] f2fs: Handle casefolding with Encryption
@ 2020-11-17  4:03   ` Daniel Rosenberg
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Rosenberg @ 2020-11-17  4:03 UTC (permalink / raw)
  To: Theodore Y . Ts'o, Jaegeuk Kim, Eric Biggers, Andreas Dilger,
	Chao Yu, Alexander Viro, Richard Weinberger, linux-fscrypt,
	linux-ext4, linux-f2fs-devel
  Cc: Daniel Rosenberg, Eric Biggers, kernel-team, linux-kernel,
	linux-mtd, linux-fsdevel, Gabriel Krisman Bertazi

Expand f2fs's casefolding support to include encrypted directories.  To
index casefolded+encrypted directories, we use the SipHash of the
casefolded name, keyed by a key derived from the directory's fscrypt
master key.  This ensures that the dirhash doesn't leak information
about the plaintext filenames.

Encryption keys are unavailable during roll-forward recovery, so we
can't compute the dirhash when recovering a new dentry in an encrypted +
casefolded directory.  To avoid having to force a checkpoint when a new
file is fsync'ed, store the dirhash on-disk appended to i_name.

This patch incorporates work by Eric Biggers <ebiggers@google.com>
and Jaegeuk Kim <jaegeuk@kernel.org>.

Co-developed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Daniel Rosenberg <drosen@google.com>
---
 fs/f2fs/dir.c      | 89 +++++++++++++++++++++++++++++++++++++---------
 fs/f2fs/f2fs.h     |  8 +++--
 fs/f2fs/hash.c     | 11 +++++-
 fs/f2fs/inline.c   |  4 +++
 fs/f2fs/recovery.c | 12 ++++++-
 fs/f2fs/super.c    |  6 ----
 6 files changed, 103 insertions(+), 27 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 71fdf5076461..0adc6bcfb5c0 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  */
+#include <asm/unaligned.h>
 #include <linux/fs.h>
 #include <linux/f2fs_fs.h>
 #include <linux/sched/signal.h>
@@ -195,26 +196,53 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
 {
 	struct f2fs_dentry_block *dentry_blk;
 	struct f2fs_dentry_ptr d;
+	struct f2fs_dir_entry *res;
 
 	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
 
 	make_dentry_ptr_block(dir, &d, dentry_blk);
-	return f2fs_find_target_dentry(&d, fname, max_slots);
+	res = f2fs_find_target_dentry(&d, fname, max_slots);
+	if (IS_ERR(res)) {
+		dentry_page = ERR_CAST(res);
+		res = NULL;
+	}
+	return res;
 }
 
 #ifdef CONFIG_UNICODE
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.
+ *
+ * Returns 1 for a match, 0 for no match, and -errno on an error.
  */
-static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
+static int f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
 			       const u8 *de_name, u32 de_name_len)
 {
 	const struct super_block *sb = dir->i_sb;
 	const struct unicode_map *um = sb->s_encoding;
+	struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
 	struct qstr entry = QSTR_INIT(de_name, de_name_len);
 	int res;
 
+	if (IS_ENCRYPTED(dir)) {
+		const struct fscrypt_str encrypted_name =
+			FSTR_INIT((u8 *)de_name, de_name_len);
+
+		if (WARN_ON_ONCE(!fscrypt_has_encryption_key(dir)))
+			return -EINVAL;
+
+		decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
+		if (!decrypted_name.name)
+			return -ENOMEM;
+		res = fscrypt_fname_disk_to_usr(dir, 0, 0, &encrypted_name,
+						&decrypted_name);
+		if (res < 0)
+			goto out;
+		entry.name = decrypted_name.name;
+		entry.len = decrypted_name.len;
+	}
+
 	res = utf8_strncasecmp_folded(um, name, &entry);
 	if (res < 0) {
 		/*
@@ -222,14 +250,20 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
 		 * fall back to treating them as opaque byte sequences.
 		 */
 		if (sb_has_strict_encoding(sb) || name->len != entry.len)
-			return false;
-		return !memcmp(name->name, entry.name, name->len);
+			res = 0;
+		else
+			res = memcmp(name->name, entry.name, name->len) == 0;
+	} else {
+		/* utf8_strncasecmp_folded returns 0 on match */
+		res = (res == 0);
 	}
-	return res == 0;
+out:
+	kfree(decrypted_name.name);
+	return res;
 }
 #endif /* CONFIG_UNICODE */
 
-static inline bool f2fs_match_name(const struct inode *dir,
+static inline int f2fs_match_name(const struct inode *dir,
 				   const struct f2fs_filename *fname,
 				   const u8 *de_name, u32 de_name_len)
 {
@@ -256,6 +290,7 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
 	struct f2fs_dir_entry *de;
 	unsigned long bit_pos = 0;
 	int max_len = 0;
+	int res = 0;
 
 	if (max_slots)
 		*max_slots = 0;
@@ -273,10 +308,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
 			continue;
 		}
 
-		if (de->hash_code == fname->hash &&
-		    f2fs_match_name(d->inode, fname, d->filename[bit_pos],
-				    le16_to_cpu(de->name_len)))
-			goto found;
+		if (de->hash_code == fname->hash) {
+			res = f2fs_match_name(d->inode, fname, d->filename[bit_pos],
+				    le16_to_cpu(de->name_len));
+			if (res < 0)
+				return ERR_PTR(res);
+			else if (res)
+				goto found;
+		}
 
 		if (max_slots && max_len > *max_slots)
 			*max_slots = max_len;
@@ -448,17 +487,39 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
 	f2fs_put_page(page, 1);
 }
 
-static void init_dent_inode(const struct f2fs_filename *fname,
+static void init_dent_inode(struct inode *dir, struct inode *inode,
+			    const struct f2fs_filename *fname,
 			    struct page *ipage)
 {
 	struct f2fs_inode *ri;
 
+	if (!fname) /* tmpfile case? */
+		return;
+
 	f2fs_wait_on_page_writeback(ipage, NODE, true, true);
 
 	/* copy name info. to this inode page */
 	ri = F2FS_INODE(ipage);
 	ri->i_namelen = cpu_to_le32(fname->disk_name.len);
 	memcpy(ri->i_name, fname->disk_name.name, fname->disk_name.len);
+	if (IS_ENCRYPTED(dir)) {
+		file_set_enc_name(inode);
+		/*
+		 * Roll-forward recovery doesn't have encryption keys available,
+		 * so it can't compute the dirhash for encrypted+casefolded
+		 * filenames.  Append it to i_name if possible.  Else, disable
+		 * roll-forward recovery of the dentry (i.e., make fsync'ing the
+		 * file force a checkpoint) by setting LOST_PINO.
+		 */
+		if (IS_CASEFOLDED(dir)) {
+			if (fname->disk_name.len + sizeof(f2fs_hash_t) <=
+			    F2FS_NAME_LEN)
+				put_unaligned(fname->hash, (f2fs_hash_t *)
+					&ri->i_name[fname->disk_name.len]);
+			else
+				file_lost_pino(inode);
+		}
+	}
 	set_page_dirty(ipage);
 }
 
@@ -541,11 +602,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
 			return page;
 	}
 
-	if (fname) {
-		init_dent_inode(fname, page);
-		if (IS_ENCRYPTED(dir))
-			file_set_enc_name(inode);
-	}
+	init_dent_inode(dir, inode, fname, page);
 
 	/*
 	 * This file should be checkpointed during fsync.
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 62b4f31d30e2..878308736761 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -533,9 +533,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 or if the filesystem is
-	 * doing an internal operation where usr_fname is also NULL.  In these
-	 * cases we fall back to treating the name as an opaque byte sequence.
+	 * 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.
 	 */
 	struct fscrypt_str cf_name;
 #endif
diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c
index de841aaf3c43..e3beac546c63 100644
--- a/fs/f2fs/hash.c
+++ b/fs/f2fs/hash.c
@@ -111,7 +111,9 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
 		 * 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.
+		 * 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) {
@@ -121,6 +123,13 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
 			name = fname->usr_fname->name;
 			len = fname->usr_fname->len;
 		}
+		if (IS_ENCRYPTED(dir)) {
+			struct qstr tmp = QSTR_INIT(name, len);
+
+			fname->hash =
+				cpu_to_le32(fscrypt_fname_siphash(dir, &tmp));
+			return;
+		}
 	}
 #endif
 	fname->hash = cpu_to_le32(TEA_hash_name(name, len));
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 70384e31788d..92e9852d316a 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -332,6 +332,10 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
 	make_dentry_ptr_inline(dir, &d, inline_dentry);
 	de = f2fs_find_target_dentry(&d, fname, NULL);
 	unlock_page(ipage);
+	if (IS_ERR(de)) {
+		*res_page = ERR_CAST(de);
+		de = NULL;
+	}
 	if (de)
 		*res_page = ipage;
 	else
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 4f12ade6410a..0947d36af1a8 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  */
+#include <asm/unaligned.h>
 #include <linux/fs.h>
 #include <linux/f2fs_fs.h>
 #include "f2fs.h"
@@ -128,7 +129,16 @@ static int init_recovered_filename(const struct inode *dir,
 	}
 
 	/* Compute the hash of the filename */
-	if (IS_CASEFOLDED(dir)) {
+	if (IS_ENCRYPTED(dir) && IS_CASEFOLDED(dir)) {
+		/*
+		 * In this case the hash isn't computable without the key, so it
+		 * was saved on-disk.
+		 */
+		if (fname->disk_name.len + sizeof(f2fs_hash_t) > F2FS_NAME_LEN)
+			return -EINVAL;
+		fname->hash = get_unaligned((f2fs_hash_t *)
+				&raw_inode->i_name[fname->disk_name.len]);
+	} else if (IS_CASEFOLDED(dir)) {
 		err = f2fs_init_casefolded_name(dir, fname);
 		if (err)
 			return err;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index f51d52591c99..42293b7ceaf2 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3399,12 +3399,6 @@ static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
 		struct unicode_map *encoding;
 		__u16 encoding_flags;
 
-		if (f2fs_sb_has_encrypt(sbi)) {
-			f2fs_err(sbi,
-				"Can't mount with encoding and encryption");
-			return -EINVAL;
-		}
-
 		if (f2fs_sb_read_encoding(sbi->raw_super, &encoding_info,
 					  &encoding_flags)) {
 			f2fs_err(sbi,
-- 
2.29.2.299.gdc1121823c-goog


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-11-18  6:28 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-17 12:55 [PATCH v2 3/3] f2fs: Handle casefolding with Encryption kernel test robot
  -- strict thread matches above, loose matches on Subject: below --
2020-11-17  4:03 [PATCH v2 0/3] Add support for Encryption and Casefolding in F2FS Daniel Rosenberg
2020-11-17  4:03 ` [PATCH v2 3/3] f2fs: Handle casefolding with Encryption Daniel Rosenberg
2020-11-17  4:03   ` Daniel Rosenberg
2020-11-17 14:06   ` Dan Carpenter
2020-11-17 18:50   ` Eric Biggers
2020-11-17 18:50     ` Eric Biggers
2020-11-18  6:22     ` Daniel Rosenberg
2020-11-18  6:22       ` Daniel Rosenberg
2020-11-18  6:27       ` Eric Biggers
2020-11-18  6:27         ` Eric Biggers
2020-11-18  1:03   ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.