Re: [RFC v3 1/1] eCryptfs: Use the ablkcipher crypto API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Tyler,

The patch works well, except the use of
wait_for_completion_interruptible() which can cause crashes.
In case a signal is sent, the request is freed before the processing was
finished.
So, the driver can attempt to access a request that was already freed.

I think that regular wait_for_completion() should be used.

Zeev

On 4/9/13 10:07 PM, "Tyler Hicks" <tyhicks@xxxxxxxxxxxxx> wrote:

>Make the switch from the blkcipher kernel crypto interface to the
>ablkcipher interface.
>
>encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher
>interface but, from the eCryptfs standpoint, still treat the crypto
>operation as a synchronous operation. They submit the async request and
>then wait until the operation is finished before they return. Most of
>the changes are contained inside those two functions.
>
>Despite waiting for the completion of the crypto operation, the
>ablkcipher interface provides performance increases in most cases when
>used on AES-NI capable hardware. However, sequential I/O with one or two
>threads on slow storage media does exhibit a sizeable decrease in
>performance.
>
>Signed-off-by: Tyler Hicks <tyhicks@xxxxxxxxxxxxx>
>Cc: Colin King <colin.king@xxxxxxxxxxxxx>
>Cc: Dustin Kirkland <dustin.kirkland@xxxxxxxxxxx>
>Cc: Tim Chen <tim.c.chen@xxxxxxxxx>
>Cc: Ying Huang <ying.huang@xxxxxxxxx>
>Cc: Thieu Le <thieule@xxxxxxxxxx>
>Cc: Li Wang <dragonylffly@xxxxxxx>
>Cc: Zeev Zilberman <zeev@xxxxxxxxxxxxxxxxx>
>Cc: Jarkko Sakkinen <jarkko.sakkinen@xxxxxx>
>---
>
>* I only made the changes mentioned in RFC v2 to encrypt_scatterlist().
>This
>  patch also makes those same changes to decrypt_scatterlist():
>  - Unlock cs_tfm_mutex if ablkcipher_request_alloc() fails
>  - Add CRYPTO_TFM_REQ_MAY_SLEEP flag to the
>ablkcipher_request_set_callback()
>    parameters
>
>I won't have a chance to gather new performance numbers until later
>tonight or
>tomorrow morning.
>
> fs/ecryptfs/crypto.c          | 143
>++++++++++++++++++++++++++++++------------
> fs/ecryptfs/ecryptfs_kernel.h |   3 +-
> 2 files changed, 105 insertions(+), 41 deletions(-)
>
>diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
>index d5c25db..eb50bce 100644
>--- a/fs/ecryptfs/crypto.c
>+++ b/fs/ecryptfs/crypto.c
>@@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct
>ecryptfs_crypt_stat *crypt_stat)
> 	struct ecryptfs_key_sig *key_sig, *key_sig_tmp;
> 
> 	if (crypt_stat->tfm)
>-		crypto_free_blkcipher(crypt_stat->tfm);
>+		crypto_free_ablkcipher(crypt_stat->tfm);
> 	if (crypt_stat->hash_tfm)
> 		crypto_free_hash(crypt_stat->hash_tfm);
> 	list_for_each_entry_safe(key_sig, key_sig_tmp,
>@@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size,
>struct scatterlist *sg,
> 	return i;
> }
> 
>+struct extent_crypt_result {
>+	struct completion completion;
>+	int rc;
>+};
>+
>+static void extent_crypt_complete(struct crypto_async_request *req, int
>rc)
>+{
>+	struct extent_crypt_result *ecr = req->data;
>+
>+	if (rc == -EINPROGRESS)
>+		return;
>+
>+	ecr->rc = rc;
>+	complete(&ecr->completion);
>+}
>+
> /**
>  * encrypt_scatterlist
>  * @crypt_stat: Pointer to the crypt_stat struct to initialize.
>@@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct
>ecryptfs_crypt_stat *crypt_stat,
> 			       struct scatterlist *src_sg, int size,
> 			       unsigned char *iv)
> {
>-	struct blkcipher_desc desc = {
>-		.tfm = crypt_stat->tfm,
>-		.info = iv,
>-		.flags = CRYPTO_TFM_REQ_MAY_SLEEP
>-	};
>+	struct ablkcipher_request *req = NULL;
>+	struct extent_crypt_result ecr;
> 	int rc = 0;
> 
> 	BUG_ON(!crypt_stat || !crypt_stat->tfm
>@@ -349,24 +362,48 @@ static int encrypt_scatterlist(struct
>ecryptfs_crypt_stat *crypt_stat,
> 		ecryptfs_dump_hex(crypt_stat->key,
> 				  crypt_stat->key_size);
> 	}
>-	/* Consider doing this once, when the file is opened */
>+
>+	init_completion(&ecr.completion);
>+
> 	mutex_lock(&crypt_stat->cs_tfm_mutex);
>-	if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
>-		rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
>-					     crypt_stat->key_size);
>-		crypt_stat->flags |= ECRYPTFS_KEY_SET;
>-	}
>-	if (rc) {
>-		ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
>-				rc);
>+	req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
>+	if (!req) {
> 		mutex_unlock(&crypt_stat->cs_tfm_mutex);
>-		rc = -EINVAL;
>+		rc = -ENOMEM;
> 		goto out;
> 	}
>-	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
>-	crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size);
>+
>+	ablkcipher_request_set_callback(req,
>+			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
>+			extent_crypt_complete, &ecr);
>+	/* Consider doing this once, when the file is opened */
>+	if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
>+		rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
>+					      crypt_stat->key_size);
>+		if (rc) {
>+			ecryptfs_printk(KERN_ERR,
>+					"Error setting key; rc = [%d]\n",
>+					rc);
>+			mutex_unlock(&crypt_stat->cs_tfm_mutex);
>+			rc = -EINVAL;
>+			goto out;
>+		}
>+		crypt_stat->flags |= ECRYPTFS_KEY_SET;
>+	}
> 	mutex_unlock(&crypt_stat->cs_tfm_mutex);
>+	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
>+	ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
>+	rc = crypto_ablkcipher_encrypt(req);
>+	if (rc == -EINPROGRESS || rc == -EBUSY) {
>+		struct extent_crypt_result *ecr = req->base.data;
>+
>+		rc = wait_for_completion_interruptible(&ecr->completion);
>+		if (!rc)
>+			rc = ecr->rc;
>+		INIT_COMPLETION(ecr->completion);
>+	}
> out:
>+	ablkcipher_request_free(req);
> 	return rc;
> }
> 
>@@ -624,35 +661,62 @@ static int decrypt_scatterlist(struct
>ecryptfs_crypt_stat *crypt_stat,
> 			       struct scatterlist *src_sg, int size,
> 			       unsigned char *iv)
> {
>-	struct blkcipher_desc desc = {
>-		.tfm = crypt_stat->tfm,
>-		.info = iv,
>-		.flags = CRYPTO_TFM_REQ_MAY_SLEEP
>-	};
>+	struct ablkcipher_request *req = NULL;
>+	struct extent_crypt_result ecr;
> 	int rc = 0;
> 
>-	/* Consider doing this once, when the file is opened */
>+	BUG_ON(!crypt_stat || !crypt_stat->tfm
>+	       || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
>+	if (unlikely(ecryptfs_verbosity > 0)) {
>+		ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
>+				crypt_stat->key_size);
>+		ecryptfs_dump_hex(crypt_stat->key,
>+				  crypt_stat->key_size);
>+	}
>+
>+	init_completion(&ecr.completion);
>+
> 	mutex_lock(&crypt_stat->cs_tfm_mutex);
>-	rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
>-				     crypt_stat->key_size);
>-	if (rc) {
>-		ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
>-				rc);
>+	req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
>+	if (!req) {
> 		mutex_unlock(&crypt_stat->cs_tfm_mutex);
>-		rc = -EINVAL;
>+		rc = -ENOMEM;
> 		goto out;
> 	}
>-	ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
>-	rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size);
>+
>+	ablkcipher_request_set_callback(req,
>+			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
>+			extent_crypt_complete, &ecr);
>+	/* Consider doing this once, when the file is opened */
>+	if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
>+		rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
>+					      crypt_stat->key_size);
>+		if (rc) {
>+			ecryptfs_printk(KERN_ERR,
>+					"Error setting key; rc = [%d]\n",
>+					rc);
>+			mutex_unlock(&crypt_stat->cs_tfm_mutex);
>+			rc = -EINVAL;
>+			goto out;
>+		}
>+		crypt_stat->flags |= ECRYPTFS_KEY_SET;
>+	}
> 	mutex_unlock(&crypt_stat->cs_tfm_mutex);
>-	if (rc) {
>-		ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n",
>-				rc);
>-		goto out;
>+	ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
>+	ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
>+	rc = crypto_ablkcipher_decrypt(req);
>+	if (rc == -EINPROGRESS || rc == -EBUSY) {
>+		struct extent_crypt_result *ecr = req->base.data;
>+
>+		rc = wait_for_completion_interruptible(&ecr->completion);
>+		if (!rc)
>+			rc = ecr->rc;
>+		INIT_COMPLETION(ecr->completion);
> 	}
>-	rc = size;
> out:
>+	ablkcipher_request_free(req);
> 	return rc;
>+
> }
> 
> /**
>@@ -746,8 +810,7 @@ int ecryptfs_init_crypt_ctx(struct
>ecryptfs_crypt_stat *crypt_stat)
> 						    crypt_stat->cipher, "cbc");
> 	if (rc)
> 		goto out_unlock;
>-	crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0,
>-						 CRYPTO_ALG_ASYNC);
>+	crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0);
> 	kfree(full_alg_name);
> 	if (IS_ERR(crypt_stat->tfm)) {
> 		rc = PTR_ERR(crypt_stat->tfm);
>@@ -757,7 +820,7 @@ int ecryptfs_init_crypt_ctx(struct
>ecryptfs_crypt_stat *crypt_stat)
> 				crypt_stat->cipher);
> 		goto out_unlock;
> 	}
>-	crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
>+	crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
> 	rc = 0;
> out_unlock:
> 	mutex_unlock(&crypt_stat->cs_tfm_mutex);
>diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
>index dd299b3..f622a73 100644
>--- a/fs/ecryptfs/ecryptfs_kernel.h
>+++ b/fs/ecryptfs/ecryptfs_kernel.h
>@@ -38,6 +38,7 @@
> #include <linux/nsproxy.h>
> #include <linux/backing-dev.h>
> #include <linux/ecryptfs.h>
>+#include <linux/crypto.h>
> 
> #define ECRYPTFS_DEFAULT_IV_BYTES 16
> #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
>@@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat {
> 	size_t extent_shift;
> 	unsigned int extent_mask;
> 	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
>-	struct crypto_blkcipher *tfm;
>+	struct crypto_ablkcipher *tfm;
> 	struct crypto_hash *hash_tfm; /* Crypto context for generating
> 				       * the initialization vectors */
> 	unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
>-- 
>1.8.1.2
>
>--
>To unsubscribe from this list: send the line "unsubscribe ecryptfs" in
>the body of a message to majordomo@xxxxxxxxxxxxxxx
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


--
To unsubscribe from this list: send the line "unsubscribe ecryptfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Crypto]     [Device Mapper Crypto]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux