[RFC PATCH 06/25] fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl

Michael Halcrow mhalcrow at google.com
Fri Oct 27 13:14:46 PDT 2017


On Mon, Oct 23, 2017 at 02:40:39PM -0700, Eric Biggers wrote:
> By having an API to add a key to the *filesystem* we'll be able to
> eliminate all the above hacks and better express the intended semantics:
> the "locked/unlocked" status of an encrypted directory is global.  And
> orthogonally to encryption, existing mechanisms such as file permissions
> and LSMs can and should continue to be used for the purpose of *access
> control*.

At some point I'd like to try to tackle the problem of making the
encryption policy somehow *reflect* the access control policy.

For now this change cleans up a real mess and makes things much more
manageable and predictable.

> Signed-off-by: Eric Biggers <ebiggers at google.com>

Reviewed-by: Michael Halcrow <mhalcrow at google.com>

> ---
>  fs/crypto/crypto.c              |  12 +-
>  fs/crypto/fscrypt_private.h     |   3 +
>  fs/crypto/keyinfo.c             | 351 +++++++++++++++++++++++++++++++++++++++-
>  include/linux/fscrypt_notsupp.h |   5 +
>  include/linux/fscrypt_supp.h    |   1 +
>  include/uapi/linux/fscrypt.h    |  41 +++--
>  6 files changed, 397 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
> index 608f6bbe0f31..489c504ac20d 100644
> --- a/fs/crypto/crypto.c
> +++ b/fs/crypto/crypto.c
> @@ -24,6 +24,7 @@
>  #include <linux/module.h>
>  #include <linux/scatterlist.h>
>  #include <linux/ratelimit.h>
> +#include <linux/key-type.h>
>  #include <linux/dcache.h>
>  #include <linux/namei.h>
>  #include <crypto/aes.h>
> @@ -449,6 +450,8 @@ int fscrypt_initialize(unsigned int cop_flags)
>   */
>  static int __init fscrypt_init(void)
>  {
> +	int err = -ENOMEM;
> +
>  	fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
>  							WQ_HIGHPRI, 0);
>  	if (!fscrypt_read_workqueue)
> @@ -462,14 +465,20 @@ static int __init fscrypt_init(void)
>  	if (!fscrypt_info_cachep)
>  		goto fail_free_ctx;
>  
> +	err = register_key_type(&key_type_fscrypt_mk);
> +	if (err)
> +		goto fail_free_info;
> +
>  	return 0;
>  
> +fail_free_info:
> +	kmem_cache_destroy(fscrypt_info_cachep);
>  fail_free_ctx:
>  	kmem_cache_destroy(fscrypt_ctx_cachep);
>  fail_free_queue:
>  	destroy_workqueue(fscrypt_read_workqueue);
>  fail:
> -	return -ENOMEM;
> +	return err;
>  }
>  module_init(fscrypt_init)
>  
> @@ -484,6 +493,7 @@ static void __exit fscrypt_exit(void)
>  		destroy_workqueue(fscrypt_read_workqueue);
>  	kmem_cache_destroy(fscrypt_ctx_cachep);
>  	kmem_cache_destroy(fscrypt_info_cachep);
> +	unregister_key_type(&key_type_fscrypt_mk);
>  
>  	fscrypt_essiv_cleanup();
>  }
> diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
> index 5cb80a2d39ea..b2fad12eeedb 100644
> --- a/fs/crypto/fscrypt_private.h
> +++ b/fs/crypto/fscrypt_private.h
> @@ -27,6 +27,8 @@
>  
>  #define FS_KEY_DERIVATION_NONCE_SIZE		16
>  
> +#define FSCRYPT_MIN_KEY_SIZE		16
> +
>  /**
>   * Encryption context for inode
>   *
> @@ -93,6 +95,7 @@ extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
>  					      gfp_t gfp_flags);
>  
>  /* keyinfo.c */
> +extern struct key_type key_type_fscrypt_mk;
>  extern void __exit fscrypt_essiv_cleanup(void);
>  
>  #endif /* _FSCRYPT_PRIVATE_H */
> diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
> index d3a97c2cd4dd..3f1cb8bbc1e5 100644
> --- a/fs/crypto/keyinfo.c
> +++ b/fs/crypto/keyinfo.c
> @@ -9,14 +9,307 @@
>   */
>  
>  #include <keys/user-type.h>
> -#include <linux/scatterlist.h>
> +#include <linux/key-type.h>
>  #include <linux/ratelimit.h>
> +#include <linux/scatterlist.h>
> +#include <linux/seq_file.h>
>  #include <crypto/aes.h>
>  #include <crypto/sha.h>
>  #include "fscrypt_private.h"
>  
>  static struct crypto_shash *essiv_hash_tfm;
>  
> +/*
> + * fscrypt_master_key_secret - secret key material of an in-use master key
> + */
> +struct fscrypt_master_key_secret {
> +
> +	/* Size of the raw key in bytes */
> +	u32			size;
> +
> +	/* The raw key */
> +	u8			raw[FSCRYPT_MAX_KEY_SIZE];
> +};

With structs fscrypt introduces, I suggest __randomize_layout wherever
feasible.

> +#define FSCRYPT_FS_KEYRING_DESCRIPTION_SIZE	\
> +	(sizeof("fscrypt-") - 1 + sizeof(((struct super_block
> *)0)->s_id) + 1)

What function do the " - 1" and " + 1" parts serve here?  Readability?

> +	key = find_master_key(inode->i_sb, &mk_spec);
> +	if (IS_ERR(key)) {
> +		if (key != ERR_PTR(-ENOKEY))
> +			return PTR_ERR(key);
> +		/*
> +		 * As a legacy fallback, we search the current task's subscribed
> +		 * keyrings in addition to ->s_master_keys.

Please add an explicit comment that it's important for security that
the ordering of these two searches be preserved.

> +		 */
> +		return find_and_derive_key_legacy(inode, ctx, derived_key,
> +						  derived_keysize);
> +	}
> +	mk = key->payload.data[0];
> +
> +	/*
> +	 * Require that the master key be at least as long as the derived key.
> +	 * Otherwise, the derived key cannot possibly contain as much entropy as
> +	 * that required by the encryption mode it will be used for.
> +	 */
> +	if (mk->mk_secret.size < derived_keysize) {

As I've mentioned in a previous patch in this set, if we're going to
get opinionated about source entropy, there's more we could
measure/estimate than just the length.



More information about the linux-mtd mailing list