diff options
Diffstat (limited to 'security/integrity/ima/ima_template.c')
| -rw-r--r-- | security/integrity/ima/ima_template.c | 166 |
1 files changed, 133 insertions, 33 deletions
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index b631b8bc7624..04c49f05cb74 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -1,20 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Politecnico di Torino, Italy - * TORSEC group -- http://security.polito.it + * TORSEC group -- https://security.polito.it * * Author: Roberto Sassu <roberto.sassu@polito.it> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_template.c * Helpers to manage template descriptors. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/rculist.h> #include "ima.h" #include "ima_template_lib.h" @@ -26,11 +20,18 @@ static struct ima_template_desc builtin_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, + {.name = "ima-ngv2", .fmt = "d-ngv2|n-ng"}, + {.name = "ima-sigv2", .fmt = "d-ngv2|n-ng|sig"}, + {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, + {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"}, + {.name = "evm-sig", + .fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"}, {.name = "", .fmt = ""}, /* placeholder for a custom format */ }; static LIST_HEAD(defined_templates); static DEFINE_SPINLOCK(template_list); +static int template_setup_done; static const struct ima_template_field supported_fields[] = { {.field_id = "d", .field_init = ima_eventdigest_init, @@ -39,28 +40,77 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_string}, {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init, .field_show = ima_show_template_digest_ng}, + {.field_id = "d-ngv2", .field_init = ima_eventdigest_ngv2_init, + .field_show = ima_show_template_digest_ngv2}, {.field_id = "n-ng", .field_init = ima_eventname_ng_init, .field_show = ima_show_template_string}, {.field_id = "sig", .field_init = ima_eventsig_init, .field_show = ima_show_template_sig}, + {.field_id = "buf", .field_init = ima_eventbuf_init, + .field_show = ima_show_template_buf}, + {.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init, + .field_show = ima_show_template_digest_ng}, + {.field_id = "modsig", .field_init = ima_eventmodsig_init, + .field_show = ima_show_template_sig}, + {.field_id = "evmsig", .field_init = ima_eventevmsig_init, + .field_show = ima_show_template_sig}, + {.field_id = "iuid", .field_init = ima_eventinodeuid_init, + .field_show = ima_show_template_uint}, + {.field_id = "igid", .field_init = ima_eventinodegid_init, + .field_show = ima_show_template_uint}, + {.field_id = "imode", .field_init = ima_eventinodemode_init, + .field_show = ima_show_template_uint}, + {.field_id = "xattrnames", + .field_init = ima_eventinodexattrnames_init, + .field_show = ima_show_template_string}, + {.field_id = "xattrlengths", + .field_init = ima_eventinodexattrlengths_init, + .field_show = ima_show_template_sig}, + {.field_id = "xattrvalues", + .field_init = ima_eventinodexattrvalues_init, + .field_show = ima_show_template_sig}, }; -#define MAX_TEMPLATE_NAME_LEN 15 + +/* + * Used when restoring measurements carried over from a kexec. 'd' and 'n' don't + * need to be accounted for since they shouldn't be defined in the same template + * description as 'd-ng' and 'n-ng' respectively. + */ +#define MAX_TEMPLATE_NAME_LEN \ + sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode") static struct ima_template_desc *ima_template; -static struct ima_template_desc *lookup_template_desc(const char *name); -static int template_desc_init_fields(const char *template_fmt, - const struct ima_template_field ***fields, - int *num_fields); +static struct ima_template_desc *ima_buf_template; + +/** + * ima_template_has_modsig - Check whether template has modsig-related fields. + * @ima_template: IMA template to check. + * + * Tells whether the given template has fields referencing a file's appended + * signature. + */ +bool ima_template_has_modsig(const struct ima_template_desc *ima_template) +{ + int i; + + for (i = 0; i < ima_template->num_fields; i++) + if (!strcmp(ima_template->fields[i]->field_id, "modsig") || + !strcmp(ima_template->fields[i]->field_id, "d-modsig")) + return true; + + return false; +} static int __init ima_template_setup(char *str) { struct ima_template_desc *template_desc; int template_len = strlen(str); - if (ima_template) + if (template_setup_done) return 1; - ima_init_template_list(); + if (!ima_template) + ima_init_template_list(); /* * Verify that a template with the supplied name exists. @@ -84,6 +134,7 @@ static int __init ima_template_setup(char *str) } ima_template = template_desc; + template_setup_done = 1; return 1; } __setup("ima_template=", ima_template_setup); @@ -92,7 +143,7 @@ static int __init ima_template_fmt_setup(char *str) { int num_templates = ARRAY_SIZE(builtin_templates); - if (ima_template) + if (template_setup_done) return 1; if (template_desc_init_fields(str, NULL, NULL) < 0) { @@ -103,12 +154,13 @@ static int __init ima_template_fmt_setup(char *str) builtin_templates[num_templates - 1].fmt = str; ima_template = builtin_templates + num_templates - 1; + template_setup_done = 1; return 1; } __setup("ima_template_fmt=", ima_template_fmt_setup); -static struct ima_template_desc *lookup_template_desc(const char *name) +struct ima_template_desc *lookup_template_desc(const char *name) { struct ima_template_desc *template_desc; int found = 0; @@ -153,9 +205,9 @@ static int template_fmt_size(const char *template_fmt) return j + 1; } -static int template_desc_init_fields(const char *template_fmt, - const struct ima_template_field ***fields, - int *num_fields) +int template_desc_init_fields(const char *template_fmt, + const struct ima_template_field ***fields, + int *num_fields) { const char *template_fmt_ptr; const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; @@ -193,11 +245,11 @@ static int template_desc_init_fields(const char *template_fmt, } if (fields && num_fields) { - *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); + *fields = kmalloc_array(i, sizeof(**fields), GFP_KERNEL); if (*fields == NULL) return -ENOMEM; - memcpy(*fields, found_fields, i * sizeof(*fields)); + memcpy(*fields, found_fields, i * sizeof(**fields)); *num_fields = i; } @@ -229,6 +281,15 @@ struct ima_template_desc *ima_template_desc_current(void) return ima_template; } +struct ima_template_desc *ima_template_desc_buf(void) +{ + if (!ima_buf_template) { + ima_init_template_list(); + ima_buf_template = lookup_template_desc("ima-buf"); + } + return ima_buf_template; +} + int __init ima_init_template(void) { struct ima_template_desc *template = ima_template_desc_current(); @@ -237,6 +298,22 @@ int __init ima_init_template(void) result = template_desc_init_fields(template->fmt, &(template->fields), &(template->num_fields)); + if (result < 0) { + pr_err("template %s init failed, result: %d\n", + (strlen(template->name) ? + template->name : template->fmt), result); + return result; + } + + template = ima_template_desc_buf(); + if (!template) { + pr_err("Failed to get ima-buf template\n"); + return -EINVAL; + } + + result = template_desc_init_fields(template->fmt, + &(template->fields), + &(template->num_fields)); if (result < 0) pr_err("template %s init failed, result: %d\n", (strlen(template->name) ? @@ -263,8 +340,11 @@ static struct ima_template_desc *restore_template_fmt(char *template_name) template_desc->name = ""; template_desc->fmt = kstrdup(template_name, GFP_KERNEL); - if (!template_desc->fmt) + if (!template_desc->fmt) { + kfree(template_desc); + template_desc = NULL; goto out; + } spin_lock(&template_list); list_add_tail_rcu(&template_desc->list, &defined_templates); @@ -278,20 +358,30 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, int template_data_size, struct ima_template_entry **entry) { + struct tpm_digest *digests; int ret = 0; int i; - *entry = kzalloc(sizeof(**entry) + - template_desc->num_fields * sizeof(struct ima_field_data), - GFP_NOFS); + *entry = kzalloc(struct_size(*entry, template_data, + template_desc->num_fields), GFP_NOFS); if (!*entry) 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, NULL, template_desc->num_fields, (*entry)->template_data, NULL, NULL, ENFORCE_FIELDS | ENFORCE_BUFEND, "template data"); if (ret < 0) { + kfree((*entry)->digests); kfree(*entry); return ret; } @@ -324,6 +414,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, int ima_restore_measurement_list(loff_t size, void *buf) { char template_name[MAX_TEMPLATE_NAME_LEN]; + unsigned char zero[TPM_DIGEST_SIZE] = { 0 }; struct ima_kexec_hdr *khdr = buf; struct ima_field_data hdr[HDR__LAST] = { @@ -343,9 +434,9 @@ int ima_restore_measurement_list(loff_t size, void *buf) return 0; if (ima_canonical_fmt) { - khdr->version = le16_to_cpu(khdr->version); - khdr->count = le64_to_cpu(khdr->count); - khdr->buffer_size = le64_to_cpu(khdr->buffer_size); + khdr->version = le16_to_cpu((__force __le16)khdr->version); + khdr->count = le64_to_cpu((__force __le64)khdr->count); + khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size); } if (khdr->version != 1) { @@ -423,10 +514,19 @@ int ima_restore_measurement_list(loff_t size, void *buf) if (ret < 0) break; - memcpy(entry->digest, hdr[HDR_DIGEST].data, - hdr[HDR_DIGEST].len); - entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) : - le32_to_cpu(*(hdr[HDR_PCR].data)); + if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) { + ret = ima_calc_field_array_hash( + &entry->template_data[0], + entry); + if (ret < 0) { + pr_err("cannot calculate template digest\n"); + ret = -EINVAL; + break; + } + } + + entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) : + le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data)); ret = ima_restore_measurement_entry(entry); if (ret < 0) break; |
