diff options
| -rw-r--r-- | security/integrity/ima/ima_crypto.c | 65 |
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); | ||
| 345 | out3: | ||
| 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]); | ||
| 317 | out2: | 350 | out2: |
| 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); |
