Commit aa724fe1 authored by Roberto Sassu's avatar Roberto Sassu Committed by Mimi Zohar

ima: Switch to dynamically allocated buffer for template digests

This patch dynamically allocates the array of tpm_digest structures in
ima_alloc_init_template() and ima_restore_template_data(). The size of the
array is equal to the number of PCR banks plus ima_extra_slots, to make
room for SHA1 and the IMA default hash algorithm, when PCR banks with those
algorithms are not allocated.

Calculating the SHA1 digest is mandatory, as SHA1 still remains the default
hash algorithm for the measurement list. When IMA will support the Crypto
Agile format, remaining digests will be also provided.

The position in the measurement entry array of the SHA1 digest is stored in
the ima_sha1_idx global variable and is determined at IMA initialization
time.
Signed-off-by: default avatarRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent 7ca79645
...@@ -45,11 +45,15 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; ...@@ -45,11 +45,15 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
#define IMA_TEMPLATE_IMA_NAME "ima" #define IMA_TEMPLATE_IMA_NAME "ima"
#define IMA_TEMPLATE_IMA_FMT "d|n" #define IMA_TEMPLATE_IMA_FMT "d|n"
#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0)
/* current content of the policy */ /* current content of the policy */
extern int ima_policy_flag; extern int ima_policy_flag;
/* set during initialization */ /* set during initialization */
extern int ima_hash_algo; extern int ima_hash_algo;
extern int ima_sha1_idx __ro_after_init;
extern int ima_extra_slots __ro_after_init;
extern int ima_appraise; extern int ima_appraise;
extern struct tpm_chip *ima_tpm_chip; extern struct tpm_chip *ima_tpm_chip;
...@@ -92,7 +96,7 @@ struct ima_template_desc { ...@@ -92,7 +96,7 @@ struct ima_template_desc {
struct ima_template_entry { struct ima_template_entry {
int pcr; int pcr;
u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ struct tpm_digest *digests;
struct ima_template_desc *template_desc; /* template descriptor */ struct ima_template_desc *template_desc; /* template descriptor */
u32 template_data_len; u32 template_data_len;
struct ima_field_data template_data[0]; /* template related data */ struct ima_field_data template_data[0]; /* template related data */
......
...@@ -27,6 +27,7 @@ void ima_free_template_entry(struct ima_template_entry *entry) ...@@ -27,6 +27,7 @@ void ima_free_template_entry(struct ima_template_entry *entry)
for (i = 0; i < entry->template_desc->num_fields; i++) for (i = 0; i < entry->template_desc->num_fields; i++)
kfree(entry->template_data[i].data); kfree(entry->template_data[i].data);
kfree(entry->digests);
kfree(entry); kfree(entry);
} }
...@@ -38,6 +39,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data, ...@@ -38,6 +39,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_desc *desc) struct ima_template_desc *desc)
{ {
struct ima_template_desc *template_desc; struct ima_template_desc *template_desc;
struct tpm_digest *digests;
int i, result = 0; int i, result = 0;
if (desc) if (desc)
...@@ -50,6 +52,14 @@ int ima_alloc_init_template(struct ima_event_data *event_data, ...@@ -50,6 +52,14 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
if (!*entry) if (!*entry)
return -ENOMEM; return -ENOMEM;
digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
sizeof(*digests), GFP_NOFS);
if (!digests) {
result = -ENOMEM;
goto out;
}
(*entry)->digests = digests;
(*entry)->template_desc = template_desc; (*entry)->template_desc = template_desc;
for (i = 0; i < template_desc->num_fields; i++) { for (i = 0; i < template_desc->num_fields; i++) {
const struct ima_template_field *field = const struct ima_template_field *field =
......
...@@ -57,6 +57,13 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size"); ...@@ -57,6 +57,13 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
static struct crypto_shash *ima_shash_tfm; static struct crypto_shash *ima_shash_tfm;
static struct crypto_ahash *ima_ahash_tfm; static struct crypto_ahash *ima_ahash_tfm;
int ima_sha1_idx __ro_after_init;
/*
* Additional number of slots reserved, as needed, for SHA1
* and IMA default algo.
*/
int ima_extra_slots __ro_after_init = 1;
int __init ima_init_crypto(void) int __init ima_init_crypto(void)
{ {
long rc; long rc;
...@@ -502,7 +509,8 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, ...@@ -502,7 +509,8 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
} }
if (!rc) if (!rc)
rc = crypto_shash_final(shash, entry->digest); rc = crypto_shash_final(shash,
entry->digests[ima_sha1_idx].digest);
return rc; return rc;
} }
......
...@@ -150,7 +150,7 @@ int ima_measurements_show(struct seq_file *m, void *v) ...@@ -150,7 +150,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
ima_putc(m, &pcr, sizeof(e->pcr)); ima_putc(m, &pcr, sizeof(e->pcr));
/* 2nd: template digest */ /* 2nd: template digest */
ima_putc(m, e->digest, TPM_DIGEST_SIZE); ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
/* 3rd: template name size */ /* 3rd: template name size */
namelen = !ima_canonical_fmt ? strlen(template_name) : namelen = !ima_canonical_fmt ? strlen(template_name) :
...@@ -233,7 +233,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) ...@@ -233,7 +233,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
seq_printf(m, "%2d ", e->pcr); seq_printf(m, "%2d ", e->pcr);
/* 2nd: SHA1 template hash */ /* 2nd: SHA1 template hash */
ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
/* 3th: template name */ /* 3th: template name */
seq_printf(m, " %s", template_name); seq_printf(m, " %s", template_name);
......
...@@ -55,7 +55,8 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, ...@@ -55,7 +55,8 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
key = ima_hash_key(digest_value); key = ima_hash_key(digest_value);
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) { hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) {
rc = memcmp(qe->entry->digest, digest_value, TPM_DIGEST_SIZE); rc = memcmp(qe->entry->digests[ima_sha1_idx].digest,
digest_value, TPM_DIGEST_SIZE);
if ((rc == 0) && (qe->entry->pcr == pcr)) { if ((rc == 0) && (qe->entry->pcr == pcr)) {
ret = qe; ret = qe;
break; break;
...@@ -75,7 +76,7 @@ static int get_binary_runtime_size(struct ima_template_entry *entry) ...@@ -75,7 +76,7 @@ static int get_binary_runtime_size(struct ima_template_entry *entry)
int size = 0; int size = 0;
size += sizeof(u32); /* pcr */ size += sizeof(u32); /* pcr */
size += sizeof(entry->digest); size += TPM_DIGEST_SIZE;
size += sizeof(int); /* template name size field */ size += sizeof(int); /* template name size field */
size += strlen(entry->template_desc->name); size += strlen(entry->template_desc->name);
size += sizeof(entry->template_data_len); size += sizeof(entry->template_data_len);
...@@ -107,7 +108,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry, ...@@ -107,7 +108,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
atomic_long_inc(&ima_htable.len); atomic_long_inc(&ima_htable.len);
if (update_htable) { if (update_htable) {
key = ima_hash_key(entry->digest); key = ima_hash_key(entry->digests[ima_sha1_idx].digest);
hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
} }
...@@ -171,7 +172,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, ...@@ -171,7 +172,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
mutex_lock(&ima_extend_list_mutex); mutex_lock(&ima_extend_list_mutex);
if (!violation) { if (!violation) {
memcpy(digest, entry->digest, sizeof(digest)); memcpy(digest, entry->digests[ima_sha1_idx].digest,
sizeof(digest));
if (ima_lookup_digest_entry(digest, entry->pcr)) { if (ima_lookup_digest_entry(digest, entry->pcr)) {
audit_cause = "hash_exists"; audit_cause = "hash_exists";
result = -EEXIST; result = -EEXIST;
......
...@@ -301,6 +301,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, ...@@ -301,6 +301,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
int template_data_size, int template_data_size,
struct ima_template_entry **entry) struct ima_template_entry **entry)
{ {
struct tpm_digest *digests;
int ret = 0; int ret = 0;
int i; int i;
...@@ -309,11 +310,21 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, ...@@ -309,11 +310,21 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
if (!*entry) if (!*entry)
return -ENOMEM; return -ENOMEM;
digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
sizeof(*digests), GFP_NOFS);
if (!digests) {
kfree(*entry);
return -ENOMEM;
}
(*entry)->digests = digests;
ret = ima_parse_buf(template_data, template_data + template_data_size, ret = ima_parse_buf(template_data, template_data + template_data_size,
NULL, template_desc->num_fields, NULL, template_desc->num_fields,
(*entry)->template_data, NULL, NULL, (*entry)->template_data, NULL, NULL,
ENFORCE_FIELDS | ENFORCE_BUFEND, "template data"); ENFORCE_FIELDS | ENFORCE_BUFEND, "template data");
if (ret < 0) { if (ret < 0) {
kfree((*entry)->digests);
kfree(*entry); kfree(*entry);
return ret; return ret;
} }
...@@ -445,8 +456,8 @@ int ima_restore_measurement_list(loff_t size, void *buf) ...@@ -445,8 +456,8 @@ int ima_restore_measurement_list(loff_t size, void *buf)
if (ret < 0) if (ret < 0)
break; break;
memcpy(entry->digest, hdr[HDR_DIGEST].data, memcpy(entry->digests[ima_sha1_idx].digest,
hdr[HDR_DIGEST].len); hdr[HDR_DIGEST].data, hdr[HDR_DIGEST].len);
entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) : entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) :
le32_to_cpu(*(hdr[HDR_PCR].data)); le32_to_cpu(*(hdr[HDR_PCR].data));
ret = ima_restore_measurement_entry(entry); ret = ima_restore_measurement_entry(entry);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment