Re: [PATCH v2 02/20] fscrypt: add flag allowing partially-encrypted directories

Anand Jain
2022-09-13T10:07:59Z

On 06/09/2022 08:35, Sweet Tea Dorminy wrote:
> From: Omar Sandoval <osandov@osandov.com>
>
> Creating several new subvolumes out of snapshots of another subvolume,
> each for a different VM's storage, is a important usecase for btrfs.

> We
> would like to give each VM a unique encryption key to use for new writes
> to its subvolume, so that secure deletion of the VM's data is as simple
> as securely deleting the key; to avoid needing multiple keys in each VM,
> we envision the initial subvolume being unencrypted.

In this usecase, you didn't mention if the original subvolume is
encrypted, assuming it is not, so this usecase is the same as mentioned
in the design document. Now, in this usecase, what happens if the
original subvolume is encrypted? Can we still avoid the multiple keys?
How is that going to work? Or we don't yet support subvolumes out of
snapshots of another encrypted subvolume?

Thanks,
-Anand

> However, this means
> that the snapshot's directories would have a mix of encrypted and
> unencrypted files. During lookup with a key, both unencrypted and
> encrypted forms of the desired name must be queried.
>
> To allow this, add another FS_CFLG to allow filesystems to opt into
> partially encrypted directories.
>
> Signed-off-by: Omar Sandoval <osandov@osandov.com>
> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> ---
> fs/crypto/fname.c | 17 ++++++++++++++++-
> include/linux/fscrypt.h | 2 ++
> 2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
> index 6c092a1533f7..3bdece33e14d 100644
> --- a/fs/crypto/fname.c
> +++ b/fs/crypto/fname.c
> @@ -414,6 +414,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
> fname->usr_fname = iname;
>
> if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) {
> +unencrypted:
> fname->disk_name.name = (unsigned char *)iname->name;
> fname->disk_name.len = iname->len;
> return 0;
> @@ -448,8 +449,16 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
> * user-supplied name
> */
>
> - if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED)
> + if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED) {
> + /*
> + * This isn't a valid nokey name, but it could be an unencrypted
> + * name if the filesystem allows partially encrypted
> + * directories.
> + */
> + if (dir->i_sb->s_cop->flags & FS_CFLG_ALLOW_PARTIAL)
> + goto unencrypted;
> return -ENOENT;
> + }
>
> fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL);
> if (fname->crypto_buf.name == NULL)
> @@ -460,6 +469,12 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
> if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
> (ret > offsetof(struct fscrypt_nokey_name, sha256) &&
> ret != FSCRYPT_NOKEY_NAME_MAX)) {
> + /* Again, this could be an unencrypted name. */
> + if (dir->i_sb->s_cop->flags & FS_CFLG_ALLOW_PARTIAL) {
> + kfree(fname->crypto_buf.name);
> + fname->crypto_buf.name = NULL;
> + goto unencrypted;
> + }
> ret = -ENOENT;
> goto errout;
> }
> diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
> index a236d8c6d0da..a4e00314c91b 100644
> --- a/include/linux/fscrypt.h
> +++ b/include/linux/fscrypt.h
> @@ -102,6 +102,8 @@ struct fscrypt_nokey_name {
> * pages for writes and therefore won't need the fscrypt bounce page pool.
> */
> #define FS_CFLG_OWN_PAGES (1U << 1)
> +/* The filesystem allows partially encrypted directories/files. */
> +#define FS_CFLG_ALLOW_PARTIAL (1U << 2)
>
> /* Crypto operations for filesystems */
> struct fscrypt_operations {