diff options
Diffstat (limited to 'security/integrity/ima/ima_crypto.c')
| -rw-r--r-- | security/integrity/ima/ima_crypto.c | 394 |
1 files changed, 18 insertions, 376 deletions
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 6f5696d999d0..0d72b48249ee 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -11,51 +11,15 @@ */ #include <linux/kernel.h> -#include <linux/moduleparam.h> -#include <linux/ratelimit.h> #include <linux/file.h> #include <linux/crypto.h> -#include <linux/scatterlist.h> #include <linux/err.h> #include <linux/slab.h> #include <crypto/hash.h> #include "ima.h" -/* minimum file size for ahash use */ -static unsigned long ima_ahash_minsize; -module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); -MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use"); - -/* default is 0 - 1 page. */ -static int ima_maxorder; -static unsigned int ima_bufsize = PAGE_SIZE; - -static int param_set_bufsize(const char *val, const struct kernel_param *kp) -{ - unsigned long long size; - int order; - - size = memparse(val, NULL); - order = get_order(size); - if (order > MAX_PAGE_ORDER) - return -EINVAL; - ima_maxorder = order; - ima_bufsize = PAGE_SIZE << order; - return 0; -} - -static const struct kernel_param_ops param_ops_bufsize = { - .set = param_set_bufsize, - .get = param_get_uint, -}; -#define param_check_bufsize(name, p) __param_check(name, p, unsigned int) - -module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644); -MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size"); - static struct crypto_shash *ima_shash_tfm; -static struct crypto_ahash *ima_ahash_tfm; int ima_sha1_idx __ro_after_init; int ima_hash_algo_idx __ro_after_init; @@ -109,6 +73,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) int __init ima_init_crypto(void) { + unsigned int digest_size; enum hash_algo algo; long rc; int i; @@ -138,8 +103,8 @@ int __init ima_init_crypto(void) if (ima_hash_algo_idx < 0) ima_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++; - ima_algo_array = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, - sizeof(*ima_algo_array), GFP_KERNEL); + ima_algo_array = kzalloc_objs(*ima_algo_array, + NR_BANKS(ima_tpm_chip) + ima_extra_slots); if (!ima_algo_array) { rc = -ENOMEM; goto out; @@ -147,7 +112,9 @@ int __init ima_init_crypto(void) for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { algo = ima_tpm_chip->allocated_banks[i].crypto_id; + digest_size = ima_tpm_chip->allocated_banks[i].digest_size; ima_algo_array[i].algo = algo; + ima_algo_array[i].digest_size = digest_size; /* unknown TPM algorithm */ if (algo == HASH_ALGO__LAST) @@ -183,12 +150,15 @@ int __init ima_init_crypto(void) } ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1; + ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE; } if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && ima_hash_algo_idx != ima_sha1_idx) { + digest_size = hash_digest_size[ima_hash_algo]; ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm; ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo; + ima_algo_array[ima_hash_algo_idx].digest_size = digest_size; } return 0; @@ -220,234 +190,6 @@ static void ima_free_tfm(struct crypto_shash *tfm) crypto_free_shash(tfm); } -/** - * ima_alloc_pages() - Allocate 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. - * - * By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL) - * - * 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; - int order = ima_maxorder; - gfp_t gfp_mask = __GFP_RECLAIM | __GFP_NOWARN | __GFP_NORETRY; - - if (order) - order = min(get_order(max_size), 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 struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo) -{ - struct crypto_ahash *tfm = ima_ahash_tfm; - int rc; - - if (algo < 0 || algo >= HASH_ALGO__LAST) - algo = ima_hash_algo; - - if (algo != ima_hash_algo || !tfm) { - tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0); - if (!IS_ERR(tfm)) { - if (algo == ima_hash_algo) - ima_ahash_tfm = tfm; - } else { - rc = PTR_ERR(tfm); - pr_err("Can not allocate %s (reason: %d)\n", - hash_algo_name[algo], rc); - } - } - return tfm; -} - -static void ima_free_atfm(struct crypto_ahash *tfm) -{ - if (tfm != ima_ahash_tfm) - crypto_free_ahash(tfm); -} - -static inline int ahash_wait(int err, struct crypto_wait *wait) -{ - - err = crypto_wait_req(err, wait); - - if (err) - pr_crit_ratelimited("ahash calculation failed: err: %d\n", err); - - return err; -} - -static int ima_calc_file_hash_atfm(struct file *file, - struct ima_digest_data *hash, - struct crypto_ahash *tfm) -{ - loff_t i_size, offset; - char *rbuf[2] = { NULL, }; - int rc, rbuf_len, active = 0, ahash_rc = 0; - struct ahash_request *req; - struct scatterlist sg[1]; - struct crypto_wait wait; - size_t rbuf_size[2]; - - hash->length = crypto_ahash_digestsize(tfm); - - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) - return -ENOMEM; - - crypto_init_wait(&wait); - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &wait); - - rc = ahash_wait(crypto_ahash_init(req), &wait); - if (rc) - goto out1; - - i_size = i_size_read(file_inode(file)); - - if (i_size == 0) - goto out2; - - /* - * Try to allocate maximum size of memory. - * Fail if even a single page cannot be allocated. - */ - rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1); - if (!rbuf[0]) { - rc = -ENOMEM; - goto out1; - } - - /* Only allocate one buffer if that is enough. */ - if (i_size > rbuf_size[0]) { - /* - * Try to allocate secondary buffer. If that fails fallback to - * using single buffering. Use previous memory allocation size - * as baseline for possible allocation size. - */ - rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0], - &rbuf_size[1], 0); - } - - for (offset = 0; offset < i_size; offset += rbuf_len) { - if (!rbuf[1] && offset) { - /* Not using two buffers, and it is not the first - * read/request, wait for the completion of the - * previous ahash_update() request. - */ - rc = ahash_wait(ahash_rc, &wait); - if (rc) - goto out3; - } - /* read buffer */ - rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); - rc = integrity_kernel_read(file, offset, rbuf[active], - rbuf_len); - if (rc != rbuf_len) { - if (rc >= 0) - rc = -EINVAL; - /* - * Forward current rc, do not overwrite with return value - * from ahash_wait() - */ - ahash_wait(ahash_rc, &wait); - goto out3; - } - - if (rbuf[1] && offset) { - /* Using two buffers, and it is not the first - * read/request, wait for the completion of the - * previous ahash_update() request. - */ - rc = ahash_wait(ahash_rc, &wait); - if (rc) - goto out3; - } - - sg_init_one(&sg[0], rbuf[active], rbuf_len); - ahash_request_set_crypt(req, sg, NULL, rbuf_len); - - ahash_rc = crypto_ahash_update(req); - - if (rbuf[1]) - active = !active; /* swap buffers, if we use two */ - } - /* wait for the last update request to complete */ - rc = ahash_wait(ahash_rc, &wait); -out3: - ima_free_pages(rbuf[0], rbuf_size[0]); - ima_free_pages(rbuf[1], rbuf_size[1]); -out2: - if (!rc) { - ahash_request_set_crypt(req, NULL, hash->digest, 0); - rc = ahash_wait(crypto_ahash_final(req), &wait); - } -out1: - ahash_request_free(req); - return rc; -} - -static int ima_calc_file_ahash(struct file *file, struct ima_digest_data *hash) -{ - struct crypto_ahash *tfm; - int rc; - - tfm = ima_alloc_atfm(hash->algo); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - rc = ima_calc_file_hash_atfm(file, hash, tfm); - - ima_free_atfm(tfm); - - return rc; -} - static int ima_calc_file_hash_tfm(struct file *file, struct ima_digest_data *hash, struct crypto_shash *tfm) @@ -499,41 +241,15 @@ out: return rc; } -static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash) -{ - struct crypto_shash *tfm; - int rc; - - tfm = ima_alloc_tfm(hash->algo); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - rc = ima_calc_file_hash_tfm(file, hash, tfm); - - ima_free_tfm(tfm); - - return rc; -} - /* * ima_calc_file_hash - calculate file hash - * - * Asynchronous hash (ahash) allows using HW acceleration for calculating - * a hash. ahash performance varies for different data sizes on different - * crypto accelerators. shash performance might be better for smaller files. - * The 'ima.ahash_minsize' module parameter allows specifying the best - * minimum file size for using ahash on the system. - * - * If the ima.ahash_minsize parameter is not specified, this function uses - * shash for the hash calculation. If ahash fails, it falls back to using - * shash. */ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) { - loff_t i_size; int rc; struct file *f = file; bool new_file_instance = false; + struct crypto_shash *tfm; /* * For consistency, fail file's opened with the O_DIRECT flag on @@ -557,16 +273,13 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) new_file_instance = true; } - i_size = i_size_read(file_inode(f)); - - if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { - rc = ima_calc_file_ahash(f, hash); - if (!rc) - goto out; + tfm = ima_alloc_tfm(hash->algo); + if (IS_ERR(tfm)) { + rc = PTR_ERR(tfm); + } else { + rc = ima_calc_file_hash_tfm(f, hash, tfm); + ima_free_tfm(tfm); } - - rc = ima_calc_file_shash(f, hash); -out: if (new_file_instance) fput(f); return rc; @@ -655,63 +368,6 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, return rc; } -static int calc_buffer_ahash_atfm(const void *buf, loff_t len, - struct ima_digest_data *hash, - struct crypto_ahash *tfm) -{ - struct ahash_request *req; - struct scatterlist sg; - struct crypto_wait wait; - int rc, ahash_rc = 0; - - hash->length = crypto_ahash_digestsize(tfm); - - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) - return -ENOMEM; - - crypto_init_wait(&wait); - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &wait); - - rc = ahash_wait(crypto_ahash_init(req), &wait); - if (rc) - goto out; - - sg_init_one(&sg, buf, len); - ahash_request_set_crypt(req, &sg, NULL, len); - - ahash_rc = crypto_ahash_update(req); - - /* wait for the update request to complete */ - rc = ahash_wait(ahash_rc, &wait); - if (!rc) { - ahash_request_set_crypt(req, NULL, hash->digest, 0); - rc = ahash_wait(crypto_ahash_final(req), &wait); - } -out: - ahash_request_free(req); - return rc; -} - -static int calc_buffer_ahash(const void *buf, loff_t len, - struct ima_digest_data *hash) -{ - struct crypto_ahash *tfm; - int rc; - - tfm = ima_alloc_atfm(hash->algo); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - rc = calc_buffer_ahash_atfm(buf, len, hash, tfm); - - ima_free_atfm(tfm); - - return rc; -} - static int calc_buffer_shash_tfm(const void *buf, loff_t size, struct ima_digest_data *hash, struct crypto_shash *tfm) @@ -742,8 +398,8 @@ static int calc_buffer_shash_tfm(const void *buf, loff_t size, return rc; } -static int calc_buffer_shash(const void *buf, loff_t len, - struct ima_digest_data *hash) +int ima_calc_buffer_hash(const void *buf, loff_t len, + struct ima_digest_data *hash) { struct crypto_shash *tfm; int rc; @@ -758,20 +414,6 @@ static int calc_buffer_shash(const void *buf, loff_t len, return rc; } -int ima_calc_buffer_hash(const void *buf, loff_t len, - struct ima_digest_data *hash) -{ - int rc; - - if (ima_ahash_minsize && len >= ima_ahash_minsize) { - rc = calc_buffer_ahash(buf, len, hash); - if (!rc) - return 0; - } - - return calc_buffer_shash(buf, len, hash); -} - static void ima_pcrread(u32 idx, struct tpm_digest *d) { if (!ima_tpm_chip) @@ -832,7 +474,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, } } if (!rc) - crypto_shash_final(shash, digest); + rc = crypto_shash_final(shash, digest); return rc; } |
