aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Kasatkin <d.kasatkin@samsung.com>2014-05-06 07:54:27 -0400
committerMimi Zohar <zohar@linux.vnet.ibm.com>2014-07-17 09:35:11 -0400
commit32c2e6752ff0f48fe03b9e1c7c64bde580a840d2 (patch)
tree82d66c533fb992e6f9f2f7dcc10f8ec0d1057314
parent6edf7a89260859c5e72861dc4e6e169495f076c8 (diff)
ima: provide double buffering for hash calculation
The asynchronous hash API allows initiating a hash calculation and then performing other tasks, while waiting for the hash calculation to complete. This patch introduces usage of double buffering for simultaneous hashing and reading of the next chunk of data from storage. Changes in v3: - better comments Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
-rw-r--r--security/integrity/ima/ima_crypto.c65
1 files changed, 49 insertions, 16 deletions
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 84b938f86bea..0bd732843fe7 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -253,12 +253,12 @@ static int ima_calc_file_hash_atfm(struct file *file,
253 struct crypto_ahash *tfm) 253 struct crypto_ahash *tfm)
254{ 254{
255 loff_t i_size, offset; 255 loff_t i_size, offset;
256 char *rbuf; 256 char *rbuf[2] = { NULL, };
257 int rc, read = 0, rbuf_len; 257 int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0;
258 struct ahash_request *req; 258 struct ahash_request *req;
259 struct scatterlist sg[1]; 259 struct scatterlist sg[1];
260 struct ahash_completion res; 260 struct ahash_completion res;
261 size_t rbuf_size; 261 size_t rbuf_size[2];
262 262
263 hash->length = crypto_ahash_digestsize(tfm); 263 hash->length = crypto_ahash_digestsize(tfm);
264 264
@@ -284,36 +284,69 @@ static int ima_calc_file_hash_atfm(struct file *file,
284 * Try to allocate maximum size of memory. 284 * Try to allocate maximum size of memory.
285 * Fail if even a single page cannot be allocated. 285 * Fail if even a single page cannot be allocated.
286 */ 286 */
287 rbuf = ima_alloc_pages(i_size, &rbuf_size, 1); 287 rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1);
288 if (!rbuf) { 288 if (!rbuf[0]) {
289 rc = -ENOMEM; 289 rc = -ENOMEM;
290 goto out1; 290 goto out1;
291 } 291 }
292 292
293 /* Only allocate one buffer if that is enough. */
294 if (i_size > rbuf_size[0]) {
295 /*
296 * Try to allocate secondary buffer. If that fails fallback to
297 * using single buffering. Use previous memory allocation size
298 * as baseline for possible allocation size.
299 */
300 rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0],
301 &rbuf_size[1], 0);
302 }
303
293 if (!(file->f_mode & FMODE_READ)) { 304 if (!(file->f_mode & FMODE_READ)) {
294 file->f_mode |= FMODE_READ; 305 file->f_mode |= FMODE_READ;
295 read = 1; 306 read = 1;
296 } 307 }
297 308
298 for (offset = 0; offset < i_size; offset += rbuf_len) { 309 for (offset = 0; offset < i_size; offset += rbuf_len) {
299 rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE); 310 if (!rbuf[1] && offset) {
300 if (rbuf_len < 0) { 311 /* Not using two buffers, and it is not the first
301 rc = rbuf_len; 312 * read/request, wait for the completion of the
302 break; 313 * previous ahash_update() request.
314 */
315 rc = ahash_wait(ahash_rc, &res);
316 if (rc)
317 goto out3;
318 }
319 /* read buffer */
320 rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
321 rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len);
322 if (rc != rbuf_len)
323 goto out3;
324
325 if (rbuf[1] && offset) {
326 /* Using two buffers, and it is not the first
327 * read/request, wait for the completion of the
328 * previous ahash_update() request.
329 */
330 rc = ahash_wait(ahash_rc, &res);
331 if (rc)
332 goto out3;
303 } 333 }
304 if (rbuf_len == 0)
305 break;
306 334
307 sg_init_one(&sg[0], rbuf, rbuf_len); 335 sg_init_one(&sg[0], rbuf[active], rbuf_len);
308 ahash_request_set_crypt(req, sg, NULL, rbuf_len); 336 ahash_request_set_crypt(req, sg, NULL, rbuf_len);
309 337
310 rc = ahash_wait(crypto_ahash_update(req), &res); 338 ahash_rc = crypto_ahash_update(req);
311 if (rc) 339
312 break; 340 if (rbuf[1])
341 active = !active; /* swap buffers, if we use two */
313 } 342 }
343 /* wait for the last update request to complete */
344 rc = ahash_wait(ahash_rc, &res);
345out3:
314 if (read) 346 if (read)
315 file->f_mode &= ~FMODE_READ; 347 file->f_mode &= ~FMODE_READ;
316 ima_free_pages(rbuf, rbuf_size); 348 ima_free_pages(rbuf[0], rbuf_size[0]);
349 ima_free_pages(rbuf[1], rbuf_size[1]);
317out2: 350out2:
318 if (!rc) { 351 if (!rc) {
319 ahash_request_set_crypt(req, NULL, hash->digest, 0); 352 ahash_request_set_crypt(req, NULL, hash->digest, 0);