eCryptfs: Do not allocate hash tfm in NORECLAIM context
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 16 Apr 2016 07:01:09 +0000 (15:01 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Wed, 20 Apr 2016 09:50:01 +0000 (17:50 +0800)
You cannot allocate crypto tfm objects in NORECLAIM or NOFS contexts.
The ecryptfs code currently does exactly that for the MD5 tfm.

This patch fixes it by preallocating the MD5 tfm in a safe context.

The MD5 tfm is also reentrant so this patch removes the superfluous
cs_hash_tfm_mutex.

Reported-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/inode.c
fs/ecryptfs/super.c

index 64026e53722a2f20c9aef8e2bda6f73087b87b6b..56004965d3516557b80828e5b2e5ba9d11ee89ab 100644 (file)
@@ -105,19 +105,7 @@ static int ecryptfs_calculate_md5(char *dst,
        struct crypto_shash *tfm;
        int rc = 0;
 
-       mutex_lock(&crypt_stat->cs_hash_tfm_mutex);
        tfm = crypt_stat->hash_tfm;
-       if (!tfm) {
-               tfm = crypto_alloc_shash(ECRYPTFS_DEFAULT_HASH, 0, 0);
-               if (IS_ERR(tfm)) {
-                       rc = PTR_ERR(tfm);
-                       ecryptfs_printk(KERN_ERR, "Error attempting to "
-                                       "allocate crypto context; rc = [%d]\n",
-                                       rc);
-                       goto out;
-               }
-               crypt_stat->hash_tfm = tfm;
-       }
        rc = ecryptfs_hash_digest(tfm, src, len, dst);
        if (rc) {
                printk(KERN_ERR
@@ -126,7 +114,6 @@ static int ecryptfs_calculate_md5(char *dst,
                goto out;
        }
 out:
-       mutex_unlock(&crypt_stat->cs_hash_tfm_mutex);
        return rc;
 }
 
@@ -207,16 +194,29 @@ out:
  *
  * Initialize the crypt_stat structure.
  */
-void
-ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+int ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
 {
+       struct crypto_shash *tfm;
+       int rc;
+
+       tfm = crypto_alloc_shash(ECRYPTFS_DEFAULT_HASH, 0, 0);
+       if (IS_ERR(tfm)) {
+               rc = PTR_ERR(tfm);
+               ecryptfs_printk(KERN_ERR, "Error attempting to "
+                               "allocate crypto context; rc = [%d]\n",
+                               rc);
+               return rc;
+       }
+
        memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
        INIT_LIST_HEAD(&crypt_stat->keysig_list);
        mutex_init(&crypt_stat->keysig_list_mutex);
        mutex_init(&crypt_stat->cs_mutex);
        mutex_init(&crypt_stat->cs_tfm_mutex);
-       mutex_init(&crypt_stat->cs_hash_tfm_mutex);
+       crypt_stat->hash_tfm = tfm;
        crypt_stat->flags |= ECRYPTFS_STRUCT_INITIALIZED;
+
+       return 0;
 }
 
 /**
index d123fbaa28e000246cfab9829e444f60e49a6843..c7761a91cc2ca636b048f7d67165d46aa2a9818e 100644 (file)
@@ -242,7 +242,6 @@ struct ecryptfs_crypt_stat {
        struct list_head keysig_list;
        struct mutex keysig_list_mutex;
        struct mutex cs_tfm_mutex;
-       struct mutex cs_hash_tfm_mutex;
        struct mutex cs_mutex;
 };
 
@@ -577,7 +576,7 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
                        int sg_size);
 int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
 void ecryptfs_rotate_iv(unsigned char *iv);
-void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
 void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
 void ecryptfs_destroy_mount_crypt_stat(
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
index 121114e9a464318c1a9b97668d4348a995d9f338..0caec70a8f1798b1e3308dcc004df4a2db58d06c 100644 (file)
@@ -898,8 +898,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
        struct ecryptfs_crypt_stat *crypt_stat;
 
        crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
-       if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED))
-               ecryptfs_init_crypt_stat(crypt_stat);
+       if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)) {
+               rc = ecryptfs_init_crypt_stat(crypt_stat);
+               if (rc)
+                       return rc;
+       }
        inode = d_inode(dentry);
        lower_inode = ecryptfs_inode_to_lower(inode);
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
index 77a486d3a51b600265a0fc1a1a0134ae74ff5ab9..85411ceb0508bbd2af9286a300377fc243efd994 100644 (file)
@@ -55,7 +55,10 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
        inode_info = kmem_cache_alloc(ecryptfs_inode_info_cache, GFP_KERNEL);
        if (unlikely(!inode_info))
                goto out;
-       ecryptfs_init_crypt_stat(&inode_info->crypt_stat);
+       if (ecryptfs_init_crypt_stat(&inode_info->crypt_stat)) {
+               kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
+               goto out;
+       }
        mutex_init(&inode_info->lower_file_mutex);
        atomic_set(&inode_info->lower_file_count, 0);
        inode_info->lower_file = NULL;