aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDmitry Kasatkin <d.kasatkin@samsung.com>2014-05-06 07:47:13 -0400
committerMimi Zohar <zohar@linux.vnet.ibm.com>2014-07-17 09:35:11 -0400
commit6edf7a89260859c5e72861dc4e6e169495f076c8 (patch)
treec3d39715070ca8c0d832c95818e05524555c7bf2 /security
parent3bcced39ea7d1b0da0a991e221f53de480c6b60b (diff)
ima: introduce multi-page collect buffers
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 using 'ahash_bufsize' module parameter. Default buffer size is 4096 bytes. Changes in v3: - kernel parameter replaced with module parameter Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/ima/ima_crypto.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index b9e5120559d4..84b938f86bea 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -37,6 +37,33 @@ static unsigned long ima_ahash_minsize;
37module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); 37module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644);
38MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use"); 38MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use");
39 39
40/* default is 0 - 1 page. */
41static int ima_maxorder;
42static unsigned int ima_bufsize = PAGE_SIZE;
43
44static int param_set_bufsize(const char *val, const struct kernel_param *kp)
45{
46 unsigned long long size;
47 int order;
48
49 size = memparse(val, NULL);
50 order = get_order(size);
51 if (order >= MAX_ORDER)
52 return -EINVAL;
53 ima_maxorder = order;
54 ima_bufsize = PAGE_SIZE << order;
55 return 0;
56}
57
58static struct kernel_param_ops param_ops_bufsize = {
59 .set = param_set_bufsize,
60 .get = param_get_uint,
61};
62#define param_check_bufsize(name, p) __param_check(name, p, unsigned int)
63
64module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644);
65MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
66
40static struct crypto_shash *ima_shash_tfm; 67static struct crypto_shash *ima_shash_tfm;
41static struct crypto_ahash *ima_ahash_tfm; 68static struct crypto_ahash *ima_ahash_tfm;
42 69
@@ -106,6 +133,68 @@ static void ima_free_tfm(struct crypto_shash *tfm)
106 crypto_free_shash(tfm); 133 crypto_free_shash(tfm);
107} 134}
108 135
136/**
137 * ima_alloc_pages() - Allocate contiguous pages.
138 * @max_size: Maximum amount of memory to allocate.
139 * @allocated_size: Returned size of actual allocation.
140 * @last_warn: Should the min_size allocation warn or not.
141 *
142 * Tries to do opportunistic allocation for memory first trying to allocate
143 * max_size amount of memory and then splitting that until zero order is
144 * reached. Allocation is tried without generating allocation warnings unless
145 * last_warn is set. Last_warn set affects only last allocation of zero order.
146 *
147 * By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL)
148 *
149 * Return pointer to allocated memory, or NULL on failure.
150 */
151static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size,
152 int last_warn)
153{
154 void *ptr;
155 int order = ima_maxorder;
156 gfp_t gfp_mask = __GFP_WAIT | __GFP_NOWARN | __GFP_NORETRY;
157
158 if (order)
159 order = min(get_order(max_size), order);
160
161 for (; order; order--) {
162 ptr = (void *)__get_free_pages(gfp_mask, order);
163 if (ptr) {
164 *allocated_size = PAGE_SIZE << order;
165 return ptr;
166 }
167 }
168
169 /* order is zero - one page */
170
171 gfp_mask = GFP_KERNEL;
172
173 if (!last_warn)
174 gfp_mask |= __GFP_NOWARN;
175
176 ptr = (void *)__get_free_pages(gfp_mask, 0);
177 if (ptr) {
178 *allocated_size = PAGE_SIZE;
179 return ptr;
180 }
181
182 *allocated_size = 0;
183 return NULL;
184}
185
186/**
187 * ima_free_pages() - Free pages allocated by ima_alloc_pages().
188 * @ptr: Pointer to allocated pages.
189 * @size: Size of allocated buffer.
190 */
191static void ima_free_pages(void *ptr, size_t size)
192{
193 if (!ptr)
194 return;
195 free_pages((unsigned long)ptr, get_order(size));
196}
197
109static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo) 198static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
110{ 199{
111 struct crypto_ahash *tfm = ima_ahash_tfm; 200 struct crypto_ahash *tfm = ima_ahash_tfm;
@@ -169,6 +258,7 @@ static int ima_calc_file_hash_atfm(struct file *file,
169 struct ahash_request *req; 258 struct ahash_request *req;
170 struct scatterlist sg[1]; 259 struct scatterlist sg[1];
171 struct ahash_completion res; 260 struct ahash_completion res;
261 size_t rbuf_size;
172 262
173 hash->length = crypto_ahash_digestsize(tfm); 263 hash->length = crypto_ahash_digestsize(tfm);
174 264
@@ -190,7 +280,11 @@ static int ima_calc_file_hash_atfm(struct file *file,
190 if (i_size == 0) 280 if (i_size == 0)
191 goto out2; 281 goto out2;
192 282
193 rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); 283 /*
284 * Try to allocate maximum size of memory.
285 * Fail if even a single page cannot be allocated.
286 */
287 rbuf = ima_alloc_pages(i_size, &rbuf_size, 1);
194 if (!rbuf) { 288 if (!rbuf) {
195 rc = -ENOMEM; 289 rc = -ENOMEM;
196 goto out1; 290 goto out1;
@@ -219,7 +313,7 @@ static int ima_calc_file_hash_atfm(struct file *file,
219 } 313 }
220 if (read) 314 if (read)
221 file->f_mode &= ~FMODE_READ; 315 file->f_mode &= ~FMODE_READ;
222 kfree(rbuf); 316 ima_free_pages(rbuf, rbuf_size);
223out2: 317out2:
224 if (!rc) { 318 if (!rc) {
225 ahash_request_set_crypt(req, NULL, hash->digest, 0); 319 ahash_request_set_crypt(req, NULL, hash->digest, 0);