Re: [PATCH v2 2/3] ima: introduce multi-page collect buffers

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

 



On Tue, 2014-07-01 at 23:12 +0300, Dmitry Kasatkin wrote: 
> Use of multiple-page collect buffers reduces:
> 1) the number of block IO requests
> 2) the number of asynchronous hash update requests
> 
> Second is important for HW accelerated hashing, because significant
> amount of time is spent for preparation of hash update operation,
> which includes configuring acceleration HW, DMA engine, etc...
> Thus, HW accelerators are more efficient when working on large
> chunks of data.
> 
> This patch introduces usage of multi-page collect buffers. Buffer size
> can be specified by providing additional option to the 'ima_ahash='
> kernel parameter. 'ima_ahash=2048,16384' specifies that minimal file
> size to use ahash is 2048 byes and buffer size is 16384 bytes.
> Default buffer size is 4096 bytes.
> 
> Signed-off-by: Dmitry Kasatkin <d.kasatkin@xxxxxxxxxxx>
> ---
>  Documentation/kernel-parameters.txt |  3 +-
>  security/integrity/ima/ima_crypto.c | 85 ++++++++++++++++++++++++++++++++++---
>  2 files changed, 81 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index b406f5c..529ba58 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1292,9 +1292,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>  			Set number of hash buckets for inode cache.
> 
>  	ima_ahash=	[IMA] Asynchronous hash usage parameters
> -			Format: <min_file_size>
> +			Format: <min_file_size>[,<bufsize>]
>  			Set the minimal file size when use asynchronous hash.
>  			If ima_ahash is not provided, ahash usage is disabled.
> +			bufsize - hashing buffer size. 4k if not specified.
> 
>  	ima_appraise=	[IMA] appraise integrity measurements
>  			Format: { "off" | "enforce" | "fix" }
> diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
> index 5eb19b4..41f2695 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -25,7 +25,6 @@
>  #include <crypto/hash_info.h>
>  #include "ima.h"
> 
> -
>  struct ahash_completion {
>  	struct completion completion;
>  	int err;
> @@ -36,14 +35,24 @@ static struct crypto_ahash *ima_ahash_tfm;
> 
>  /* minimal file size for ahash use */
>  static loff_t ima_ahash_size;
> +/* default is 0 - 1 page. */
> +static int ima_max_order;
> 
>  static int __init ima_ahash_setup(char *str)
>  {
> -	int rc;
> +	int ints[3] = { 0, };
> +
> +	str = get_options(str, ARRAY_SIZE(ints), ints);
> +	if (!ints[0])
> +		return 0;
> +
> +	ima_ahash_size = ints[1];
> +	ima_max_order = get_order(ints[2]);

get_options() returns the number of options processed in ints[0].
Before assigning ima_max_order, we normally check to see if it exists.
I guess in this case it doesn't matter since it would return 0 anyway.

Should there be any value checking here?  Should the values be some
multiple of 1024?

> 
> -	rc = kstrtoll(str, 10, &ima_ahash_size);
> +	pr_info("ima_ahash: minsize=%lld, bufsize=%lu\n",
> +		ima_ahash_size, (PAGE_SIZE << ima_max_order));
> 
> -	return !rc;
> +	return 1;
>  }
>  __setup("ima_ahash=", ima_ahash_setup);
> 
> @@ -166,6 +175,65 @@ static int ahash_wait(int err, struct ahash_completion *res)
>  	return err;
>  }
> 
> +/**
> + * ima_alloc_pages() - Allocated contiguous pages.
> + * @max_size:       Maximum amount of memory to allocate.
> + * @allocated_size: Returned size of actual allocation.
> + * @last_warn:      Should the min_size allocation warn or not.
> + *
> + * Tries to do opportunistic allocation for memory first trying to allocate
> + * max_size amount of memory and then splitting that until zero order is
> + * reached. Allocation is tried without generating allocation warnings unless
> + * last_warn is set. Last_warn set affects only last allocation of zero order.
> + *
> + * Return pointer to allocated memory, or NULL on failure.
> + */
> +static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size,
> +			     int last_warn)
> +{
> +	void *ptr;
> +	unsigned int order;
> +	gfp_t gfp_mask = __GFP_NOWARN | __GFP_WAIT | __GFP_NORETRY;
> +
> +	order = min(get_order(max_size), ima_max_order);
> +
> +	for (; order; order--) {
> +		ptr = (void *)__get_free_pages(gfp_mask, order);
> +		if (ptr) {
> +			*allocated_size = PAGE_SIZE << order;
> +			return ptr;
> +		}
> +	}
> +
> +	/* order is zero - one page */
> +
> +	gfp_mask = GFP_KERNEL;
> +
> +	if (!last_warn)
> +		gfp_mask |= __GFP_NOWARN;
> +
> +	ptr = (void *)__get_free_pages(gfp_mask, 0);
> +	if (ptr) {
> +		*allocated_size = PAGE_SIZE;
> +		return ptr;
> +	}
> +
> +	*allocated_size = 0;
> +	return NULL;
> +}
> +
> +/**
> + * ima_free_pages() - Free pages allocated by ima_alloc_pages().
> + * @ptr:  Pointer to allocated pages.
> + * @size: Size of allocated buffer.
> + */
> +static void ima_free_pages(void *ptr, size_t size)
> +{
> +	if (!ptr)
> +		return;
> +	free_pages((unsigned long)ptr, get_order(size));
> +}
> +
>  static int ima_calc_file_hash_atfm(struct file *file,
>  				   struct ima_digest_data *hash,
>  				   struct crypto_ahash *tfm)
> @@ -176,6 +244,7 @@ static int ima_calc_file_hash_atfm(struct file *file,
>  	struct ahash_request *req;
>  	struct scatterlist sg[1];
>  	struct ahash_completion res;
> +	size_t rbuf_size;
> 
>  	hash->length = crypto_ahash_digestsize(tfm);
> 
> @@ -197,7 +266,11 @@ static int ima_calc_file_hash_atfm(struct file *file,
>  	if (i_size == 0)
>  		goto out2;
> 
> -	rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +	/*
> +	 * Try to allocate maximum size of memory, fail if not even single
> +	 * page cannot be allocated.
> +	 */

The comment is nice explanation, but might be unnecessary if there was a
function comment.

Mimi

> +	rbuf = ima_alloc_pages(i_size, &rbuf_size, 1);
>  	if (!rbuf) {
>  		rc = -ENOMEM;
>  		goto out1;
> @@ -226,7 +299,7 @@ static int ima_calc_file_hash_atfm(struct file *file,
>  	}
>  	if (read)
>  		file->f_mode &= ~FMODE_READ;
> -	kfree(rbuf);
> +	ima_free_pages(rbuf, rbuf_size);
>  out2:
>  	if (!rc) {
>  		ahash_request_set_crypt(req, NULL, hash->digest, 0);


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




[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux