Path: blob/master/security/integrity/ima/ima_template.c
26424 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2013 Politecnico di Torino, Italy3* TORSEC group -- https://security.polito.it4*5* Author: Roberto Sassu <[email protected]>6*7* File: ima_template.c8* Helpers to manage template descriptors.9*/1011#include <linux/rculist.h>12#include "ima.h"13#include "ima_template_lib.h"1415enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME,16HDR_TEMPLATE_DATA, HDR__LAST };1718static struct ima_template_desc builtin_templates[] = {19{.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},20{.name = "ima-ng", .fmt = "d-ng|n-ng"},21{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},22{.name = "ima-ngv2", .fmt = "d-ngv2|n-ng"},23{.name = "ima-sigv2", .fmt = "d-ngv2|n-ng|sig"},24{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},25{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},26{.name = "evm-sig",27.fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"},28{.name = "", .fmt = ""}, /* placeholder for a custom format */29};3031static LIST_HEAD(defined_templates);32static DEFINE_SPINLOCK(template_list);33static int template_setup_done;3435static const struct ima_template_field supported_fields[] = {36{.field_id = "d", .field_init = ima_eventdigest_init,37.field_show = ima_show_template_digest},38{.field_id = "n", .field_init = ima_eventname_init,39.field_show = ima_show_template_string},40{.field_id = "d-ng", .field_init = ima_eventdigest_ng_init,41.field_show = ima_show_template_digest_ng},42{.field_id = "d-ngv2", .field_init = ima_eventdigest_ngv2_init,43.field_show = ima_show_template_digest_ngv2},44{.field_id = "n-ng", .field_init = ima_eventname_ng_init,45.field_show = ima_show_template_string},46{.field_id = "sig", .field_init = ima_eventsig_init,47.field_show = ima_show_template_sig},48{.field_id = "buf", .field_init = ima_eventbuf_init,49.field_show = ima_show_template_buf},50{.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,51.field_show = ima_show_template_digest_ng},52{.field_id = "modsig", .field_init = ima_eventmodsig_init,53.field_show = ima_show_template_sig},54{.field_id = "evmsig", .field_init = ima_eventevmsig_init,55.field_show = ima_show_template_sig},56{.field_id = "iuid", .field_init = ima_eventinodeuid_init,57.field_show = ima_show_template_uint},58{.field_id = "igid", .field_init = ima_eventinodegid_init,59.field_show = ima_show_template_uint},60{.field_id = "imode", .field_init = ima_eventinodemode_init,61.field_show = ima_show_template_uint},62{.field_id = "xattrnames",63.field_init = ima_eventinodexattrnames_init,64.field_show = ima_show_template_string},65{.field_id = "xattrlengths",66.field_init = ima_eventinodexattrlengths_init,67.field_show = ima_show_template_sig},68{.field_id = "xattrvalues",69.field_init = ima_eventinodexattrvalues_init,70.field_show = ima_show_template_sig},71};7273/*74* Used when restoring measurements carried over from a kexec. 'd' and 'n' don't75* need to be accounted for since they shouldn't be defined in the same template76* description as 'd-ng' and 'n-ng' respectively.77*/78#define MAX_TEMPLATE_NAME_LEN \79sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode")8081static struct ima_template_desc *ima_template;82static struct ima_template_desc *ima_buf_template;8384/**85* ima_template_has_modsig - Check whether template has modsig-related fields.86* @ima_template: IMA template to check.87*88* Tells whether the given template has fields referencing a file's appended89* signature.90*/91bool ima_template_has_modsig(const struct ima_template_desc *ima_template)92{93int i;9495for (i = 0; i < ima_template->num_fields; i++)96if (!strcmp(ima_template->fields[i]->field_id, "modsig") ||97!strcmp(ima_template->fields[i]->field_id, "d-modsig"))98return true;99100return false;101}102103static int __init ima_template_setup(char *str)104{105struct ima_template_desc *template_desc;106int template_len = strlen(str);107108if (template_setup_done)109return 1;110111if (!ima_template)112ima_init_template_list();113114/*115* Verify that a template with the supplied name exists.116* If not, use CONFIG_IMA_DEFAULT_TEMPLATE.117*/118template_desc = lookup_template_desc(str);119if (!template_desc) {120pr_err("template %s not found, using %s\n",121str, CONFIG_IMA_DEFAULT_TEMPLATE);122return 1;123}124125/*126* Verify whether the current hash algorithm is supported127* by the 'ima' template.128*/129if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 &&130ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) {131pr_err("template does not support hash alg\n");132return 1;133}134135ima_template = template_desc;136template_setup_done = 1;137return 1;138}139__setup("ima_template=", ima_template_setup);140141static int __init ima_template_fmt_setup(char *str)142{143int num_templates = ARRAY_SIZE(builtin_templates);144145if (template_setup_done)146return 1;147148if (template_desc_init_fields(str, NULL, NULL) < 0) {149pr_err("format string '%s' not valid, using template %s\n",150str, CONFIG_IMA_DEFAULT_TEMPLATE);151return 1;152}153154builtin_templates[num_templates - 1].fmt = str;155ima_template = builtin_templates + num_templates - 1;156template_setup_done = 1;157158return 1;159}160__setup("ima_template_fmt=", ima_template_fmt_setup);161162struct ima_template_desc *lookup_template_desc(const char *name)163{164struct ima_template_desc *template_desc;165int found = 0;166167rcu_read_lock();168list_for_each_entry_rcu(template_desc, &defined_templates, list) {169if ((strcmp(template_desc->name, name) == 0) ||170(strcmp(template_desc->fmt, name) == 0)) {171found = 1;172break;173}174}175rcu_read_unlock();176return found ? template_desc : NULL;177}178179static const struct ima_template_field *180lookup_template_field(const char *field_id)181{182int i;183184for (i = 0; i < ARRAY_SIZE(supported_fields); i++)185if (strncmp(supported_fields[i].field_id, field_id,186IMA_TEMPLATE_FIELD_ID_MAX_LEN) == 0)187return &supported_fields[i];188return NULL;189}190191static int template_fmt_size(const char *template_fmt)192{193char c;194int template_fmt_len = strlen(template_fmt);195int i = 0, j = 0;196197while (i < template_fmt_len) {198c = template_fmt[i];199if (c == '|')200j++;201i++;202}203204return j + 1;205}206207int template_desc_init_fields(const char *template_fmt,208const struct ima_template_field ***fields,209int *num_fields)210{211const char *template_fmt_ptr;212const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];213int template_num_fields;214int i, len;215216if (num_fields && *num_fields > 0) /* already initialized? */217return 0;218219template_num_fields = template_fmt_size(template_fmt);220221if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) {222pr_err("format string '%s' contains too many fields\n",223template_fmt);224return -EINVAL;225}226227for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields;228i++, template_fmt_ptr += len + 1) {229char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1];230231len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr;232if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) {233pr_err("Invalid field with length %d\n", len);234return -EINVAL;235}236237memcpy(tmp_field_id, template_fmt_ptr, len);238tmp_field_id[len] = '\0';239found_fields[i] = lookup_template_field(tmp_field_id);240if (!found_fields[i]) {241pr_err("field '%s' not found\n", tmp_field_id);242return -ENOENT;243}244}245246if (fields && num_fields) {247*fields = kmalloc_array(i, sizeof(**fields), GFP_KERNEL);248if (*fields == NULL)249return -ENOMEM;250251memcpy(*fields, found_fields, i * sizeof(**fields));252*num_fields = i;253}254255return 0;256}257258void ima_init_template_list(void)259{260int i;261262if (!list_empty(&defined_templates))263return;264265spin_lock(&template_list);266for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) {267list_add_tail_rcu(&builtin_templates[i].list,268&defined_templates);269}270spin_unlock(&template_list);271}272273struct ima_template_desc *ima_template_desc_current(void)274{275if (!ima_template) {276ima_init_template_list();277ima_template =278lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE);279}280return ima_template;281}282283struct ima_template_desc *ima_template_desc_buf(void)284{285if (!ima_buf_template) {286ima_init_template_list();287ima_buf_template = lookup_template_desc("ima-buf");288}289return ima_buf_template;290}291292int __init ima_init_template(void)293{294struct ima_template_desc *template = ima_template_desc_current();295int result;296297result = template_desc_init_fields(template->fmt,298&(template->fields),299&(template->num_fields));300if (result < 0) {301pr_err("template %s init failed, result: %d\n",302(strlen(template->name) ?303template->name : template->fmt), result);304return result;305}306307template = ima_template_desc_buf();308if (!template) {309pr_err("Failed to get ima-buf template\n");310return -EINVAL;311}312313result = template_desc_init_fields(template->fmt,314&(template->fields),315&(template->num_fields));316if (result < 0)317pr_err("template %s init failed, result: %d\n",318(strlen(template->name) ?319template->name : template->fmt), result);320321return result;322}323324static struct ima_template_desc *restore_template_fmt(char *template_name)325{326struct ima_template_desc *template_desc = NULL;327int ret;328329ret = template_desc_init_fields(template_name, NULL, NULL);330if (ret < 0) {331pr_err("attempting to initialize the template \"%s\" failed\n",332template_name);333goto out;334}335336template_desc = kzalloc(sizeof(*template_desc), GFP_KERNEL);337if (!template_desc)338goto out;339340template_desc->name = "";341template_desc->fmt = kstrdup(template_name, GFP_KERNEL);342if (!template_desc->fmt) {343kfree(template_desc);344template_desc = NULL;345goto out;346}347348spin_lock(&template_list);349list_add_tail_rcu(&template_desc->list, &defined_templates);350spin_unlock(&template_list);351out:352return template_desc;353}354355static int ima_restore_template_data(struct ima_template_desc *template_desc,356void *template_data,357int template_data_size,358struct ima_template_entry **entry)359{360struct tpm_digest *digests;361int ret = 0;362int i;363364*entry = kzalloc(struct_size(*entry, template_data,365template_desc->num_fields), GFP_NOFS);366if (!*entry)367return -ENOMEM;368369digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,370sizeof(*digests), GFP_NOFS);371if (!digests) {372kfree(*entry);373return -ENOMEM;374}375376(*entry)->digests = digests;377378ret = ima_parse_buf(template_data, template_data + template_data_size,379NULL, template_desc->num_fields,380(*entry)->template_data, NULL, NULL,381ENFORCE_FIELDS | ENFORCE_BUFEND, "template data");382if (ret < 0) {383kfree((*entry)->digests);384kfree(*entry);385return ret;386}387388(*entry)->template_desc = template_desc;389for (i = 0; i < template_desc->num_fields; i++) {390struct ima_field_data *field_data = &(*entry)->template_data[i];391u8 *data = field_data->data;392393(*entry)->template_data[i].data =394kzalloc(field_data->len + 1, GFP_KERNEL);395if (!(*entry)->template_data[i].data) {396ret = -ENOMEM;397break;398}399memcpy((*entry)->template_data[i].data, data, field_data->len);400(*entry)->template_data_len += sizeof(field_data->len);401(*entry)->template_data_len += field_data->len;402}403404if (ret < 0) {405ima_free_template_entry(*entry);406*entry = NULL;407}408409return ret;410}411412/* Restore the serialized binary measurement list without extending PCRs. */413int ima_restore_measurement_list(loff_t size, void *buf)414{415char template_name[MAX_TEMPLATE_NAME_LEN];416unsigned char zero[TPM_DIGEST_SIZE] = { 0 };417418struct ima_kexec_hdr *khdr = buf;419struct ima_field_data hdr[HDR__LAST] = {420[HDR_PCR] = {.len = sizeof(u32)},421[HDR_DIGEST] = {.len = TPM_DIGEST_SIZE},422};423424void *bufp = buf + sizeof(*khdr);425void *bufendp;426struct ima_template_entry *entry;427struct ima_template_desc *template_desc;428DECLARE_BITMAP(hdr_mask, HDR__LAST);429unsigned long count = 0;430int ret = 0;431432if (!buf || size < sizeof(*khdr))433return 0;434435if (ima_canonical_fmt) {436khdr->version = le16_to_cpu((__force __le16)khdr->version);437khdr->count = le64_to_cpu((__force __le64)khdr->count);438khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size);439}440441if (khdr->version != 1) {442pr_err("attempting to restore a incompatible measurement list");443return -EINVAL;444}445446if (khdr->count > ULONG_MAX - 1) {447pr_err("attempting to restore too many measurements");448return -EINVAL;449}450451bitmap_zero(hdr_mask, HDR__LAST);452bitmap_set(hdr_mask, HDR_PCR, 1);453bitmap_set(hdr_mask, HDR_DIGEST, 1);454455/*456* ima kexec buffer prefix: version, buffer size, count457* v1 format: pcr, digest, template-name-len, template-name,458* template-data-size, template-data459*/460bufendp = buf + khdr->buffer_size;461while ((bufp < bufendp) && (count++ < khdr->count)) {462int enforce_mask = ENFORCE_FIELDS;463464enforce_mask |= (count == khdr->count) ? ENFORCE_BUFEND : 0;465ret = ima_parse_buf(bufp, bufendp, &bufp, HDR__LAST, hdr, NULL,466hdr_mask, enforce_mask, "entry header");467if (ret < 0)468break;469470if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) {471pr_err("attempting to restore a template name that is too long\n");472ret = -EINVAL;473break;474}475476/* template name is not null terminated */477memcpy(template_name, hdr[HDR_TEMPLATE_NAME].data,478hdr[HDR_TEMPLATE_NAME].len);479template_name[hdr[HDR_TEMPLATE_NAME].len] = 0;480481if (strcmp(template_name, "ima") == 0) {482pr_err("attempting to restore an unsupported template \"%s\" failed\n",483template_name);484ret = -EINVAL;485break;486}487488template_desc = lookup_template_desc(template_name);489if (!template_desc) {490template_desc = restore_template_fmt(template_name);491if (!template_desc)492break;493}494495/*496* Only the running system's template format is initialized497* on boot. As needed, initialize the other template formats.498*/499ret = template_desc_init_fields(template_desc->fmt,500&(template_desc->fields),501&(template_desc->num_fields));502if (ret < 0) {503pr_err("attempting to restore the template fmt \"%s\" failed\n",504template_desc->fmt);505ret = -EINVAL;506break;507}508509ret = ima_restore_template_data(template_desc,510hdr[HDR_TEMPLATE_DATA].data,511hdr[HDR_TEMPLATE_DATA].len,512&entry);513if (ret < 0)514break;515516if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {517ret = ima_calc_field_array_hash(518&entry->template_data[0],519entry);520if (ret < 0) {521pr_err("cannot calculate template digest\n");522ret = -EINVAL;523break;524}525}526527entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :528le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data));529ret = ima_restore_measurement_entry(entry);530if (ret < 0)531break;532533}534return ret;535}536537538