aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);