// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2005,2006,2007,2008 IBM Corporation
*
* Authors:
* Mimi Zohar <zohar@us.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* File: ima_crypto.c
* Calculates md5/sha1 file hash, template hash, boot-aggreate hash
*/
#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_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;
struct ima_algo_desc {
struct crypto_shash *tfm;
enum hash_algo algo;
};
int ima_sha1_idx __ro_after_init;
int ima_hash_algo_idx __ro_after_init;
/*
* Additional number of slots reserved, as needed, for SHA1
* and IMA default algo.
*/
int ima_extra_slots __ro_after_init;
static struct ima_algo_desc *ima_algo_array;
static int __init ima_init_ima_crypto(void)
{
long rc;
ima_shash_tfm = crypto_alloc_shash(hash_algo_name[ima_hash_algo], 0, 0);
if (IS_ERR(ima_shash_tfm)) {
rc = PTR_ERR(ima_shash_tfm);
pr_err("Can not allocate %s (reason: %ld)\n",
hash_algo_name[ima_hash_algo], rc);
return rc;
}
pr_info("Allocated hash algorithm: %s\n",
hash_algo_name[ima_hash_algo]);
return 0;
}
static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
{
struct crypto_shash *tfm = ima_shash_tfm;
int rc, i;
if (algo < 0 || algo >= HASH_ALGO__LAST)
algo = ima_hash_algo;
if (algo == ima_hash_algo)
return tfm;
for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++)
if (ima_algo_array[i].tfm && ima_algo_array[i].algo == algo)
return ima_algo_array[i].tfm;
tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
if (IS_ERR(tfm)) {
rc = PTR_ERR(tfm);
pr_err("Can not allocate %s (reason: %d)\n",
hash_algo_name[algo], rc);
}
return tfm;
}
int __init ima_init_crypto(void)
{
enum hash_algo algo;
long rc;
int i;
rc = ima_init_ima_crypto();
if (rc)
return rc;
ima_sha1_idx = -1;
ima_hash_algo_idx = -1;
for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
algo = ima_tpm_chip->allocated_banks[i].crypto_id;
if (algo == HASH_ALGO_SHA1)
ima_sha1_idx = i;
if (algo == ima_hash_algo)
ima_hash_algo_idx = i;
}
if (ima_sha1_idx < 0) {
ima_sha1_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
if (ima_hash_algo == HASH_ALGO_SHA1)
ima_hash_algo_idx = ima_sha1_idx;
}
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);
if (!ima_algo_array) {
rc = -ENOMEM;
goto out;
}
for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
algo = ima_tpm_chip->allocated_banks[i].crypto_id;
ima_algo_array[i].algo = algo;
/* unknown TPM algorithm */
if (algo == HASH_ALGO__LAST)
continue;
if (algo == ima_hash_algo) {
ima_algo_array[i].tfm = ima_shash_tfm;
continue;
}
ima_algo_array[i].tfm = ima_alloc_tfm(algo);
if (IS_ERR(ima_algo_array[i].tfm)) {
if (algo == HASH_ALGO_SHA1) {
rc = PTR_ERR(ima_algo_array[i].tfm);
ima_algo_array[i].tfm = NULL;