1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2adf53a77SRoberto Sassu /*
3adf53a77SRoberto Sassu * Copyright (C) 2013 Politecnico di Torino, Italy
4c9fecf50SAlexander A. Klimov * TORSEC group -- https://security.polito.it
5adf53a77SRoberto Sassu *
6adf53a77SRoberto Sassu * Author: Roberto Sassu <roberto.sassu@polito.it>
7adf53a77SRoberto Sassu *
8adf53a77SRoberto Sassu * File: ima_template.c
9adf53a77SRoberto Sassu * Helpers to manage template descriptors.
10adf53a77SRoberto Sassu */
1120ee451fSJoe Perches
123f23d624SMimi Zohar #include <linux/rculist.h>
13adf53a77SRoberto Sassu #include "ima.h"
143ce1217dSRoberto Sassu #include "ima_template_lib.h"
15adf53a77SRoberto Sassu
1647fdee60SRoberto Sassu enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME,
1747fdee60SRoberto Sassu HDR_TEMPLATE_DATA, HDR__LAST };
1847fdee60SRoberto Sassu
193f23d624SMimi Zohar static struct ima_template_desc builtin_templates[] = {
203ce1217dSRoberto Sassu {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
214d7aeee7SRoberto Sassu {.name = "ima-ng", .fmt = "d-ng|n-ng"},
22bcbc9b0cSMimi Zohar {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
23989dc725SMimi Zohar {.name = "ima-ngv2", .fmt = "d-ngv2|n-ng"},
24989dc725SMimi Zohar {.name = "ima-sigv2", .fmt = "d-ngv2|n-ng|sig"},
2586b4da8cSPrakhar Srivastava {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
263878d505SThiago Jung Bauermann {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
2788016de3SRoberto Sassu {.name = "evm-sig",
2888016de3SRoberto Sassu .fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"},
29c2426d2aSRoberto Sassu {.name = "", .fmt = ""}, /* placeholder for a custom format */
30adf53a77SRoberto Sassu };
31adf53a77SRoberto Sassu
323f23d624SMimi Zohar static LIST_HEAD(defined_templates);
333f23d624SMimi Zohar static DEFINE_SPINLOCK(template_list);
34bb8e52e4SRoberto Sassu static int template_setup_done;
353f23d624SMimi Zohar
36b2724d58SEric Biggers static const struct ima_template_field supported_fields[] = {
373ce1217dSRoberto Sassu {.field_id = "d", .field_init = ima_eventdigest_init,
383ce1217dSRoberto Sassu .field_show = ima_show_template_digest},
393ce1217dSRoberto Sassu {.field_id = "n", .field_init = ima_eventname_init,
403ce1217dSRoberto Sassu .field_show = ima_show_template_string},
414d7aeee7SRoberto Sassu {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init,
424d7aeee7SRoberto Sassu .field_show = ima_show_template_digest_ng},
43989dc725SMimi Zohar {.field_id = "d-ngv2", .field_init = ima_eventdigest_ngv2_init,
44989dc725SMimi Zohar .field_show = ima_show_template_digest_ngv2},
454d7aeee7SRoberto Sassu {.field_id = "n-ng", .field_init = ima_eventname_ng_init,
464d7aeee7SRoberto Sassu .field_show = ima_show_template_string},
47bcbc9b0cSMimi Zohar {.field_id = "sig", .field_init = ima_eventsig_init,
48bcbc9b0cSMimi Zohar .field_show = ima_show_template_sig},
4986b4da8cSPrakhar Srivastava {.field_id = "buf", .field_init = ima_eventbuf_init,
5086b4da8cSPrakhar Srivastava .field_show = ima_show_template_buf},
513878d505SThiago Jung Bauermann {.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,
523878d505SThiago Jung Bauermann .field_show = ima_show_template_digest_ng},
533878d505SThiago Jung Bauermann {.field_id = "modsig", .field_init = ima_eventmodsig_init,
543878d505SThiago Jung Bauermann .field_show = ima_show_template_sig},
55026d7fc9SRoberto Sassu {.field_id = "evmsig", .field_init = ima_eventevmsig_init,
56026d7fc9SRoberto Sassu .field_show = ima_show_template_sig},
577dcfeaccSRoberto Sassu {.field_id = "iuid", .field_init = ima_eventinodeuid_init,
587dcfeaccSRoberto Sassu .field_show = ima_show_template_uint},
597dcfeaccSRoberto Sassu {.field_id = "igid", .field_init = ima_eventinodegid_init,
607dcfeaccSRoberto Sassu .field_show = ima_show_template_uint},
61f8216f6bSRoberto Sassu {.field_id = "imode", .field_init = ima_eventinodemode_init,
62f8216f6bSRoberto Sassu .field_show = ima_show_template_uint},
638314b673SRoberto Sassu {.field_id = "xattrnames",
648314b673SRoberto Sassu .field_init = ima_eventinodexattrnames_init,
658314b673SRoberto Sassu .field_show = ima_show_template_string},
668314b673SRoberto Sassu {.field_id = "xattrlengths",
678314b673SRoberto Sassu .field_init = ima_eventinodexattrlengths_init,
688314b673SRoberto Sassu .field_show = ima_show_template_sig},
698314b673SRoberto Sassu {.field_id = "xattrvalues",
708314b673SRoberto Sassu .field_init = ima_eventinodexattrvalues_init,
718314b673SRoberto Sassu .field_show = ima_show_template_sig},
72adf53a77SRoberto Sassu };
73337619ebSThiago Jung Bauermann
74337619ebSThiago Jung Bauermann /*
75337619ebSThiago Jung Bauermann * Used when restoring measurements carried over from a kexec. 'd' and 'n' don't
76337619ebSThiago Jung Bauermann * need to be accounted for since they shouldn't be defined in the same template
77337619ebSThiago Jung Bauermann * description as 'd-ng' and 'n-ng' respectively.
78337619ebSThiago Jung Bauermann */
7988016de3SRoberto Sassu #define MAX_TEMPLATE_NAME_LEN \
8088016de3SRoberto Sassu sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode")
81adf53a77SRoberto Sassu
82a71dc65dSRoberto Sassu static struct ima_template_desc *ima_template;
83dea87d08SLakshmi Ramasubramanian static struct ima_template_desc *ima_buf_template;
849b9d4ce5SRoberto Sassu
85e5092255SThiago Jung Bauermann /**
86e5092255SThiago Jung Bauermann * ima_template_has_modsig - Check whether template has modsig-related fields.
87e5092255SThiago Jung Bauermann * @ima_template: IMA template to check.
88e5092255SThiago Jung Bauermann *
89e5092255SThiago Jung Bauermann * Tells whether the given template has fields referencing a file's appended
90e5092255SThiago Jung Bauermann * signature.
91e5092255SThiago Jung Bauermann */
ima_template_has_modsig(const struct ima_template_desc * ima_template)92e5092255SThiago Jung Bauermann bool ima_template_has_modsig(const struct ima_template_desc *ima_template)
93e5092255SThiago Jung Bauermann {
94e5092255SThiago Jung Bauermann int i;
95e5092255SThiago Jung Bauermann
96e5092255SThiago Jung Bauermann for (i = 0; i < ima_template->num_fields; i++)
97e5092255SThiago Jung Bauermann if (!strcmp(ima_template->fields[i]->field_id, "modsig") ||
98e5092255SThiago Jung Bauermann !strcmp(ima_template->fields[i]->field_id, "d-modsig"))
99e5092255SThiago Jung Bauermann return true;
100e5092255SThiago Jung Bauermann
101e5092255SThiago Jung Bauermann return false;
102e5092255SThiago Jung Bauermann }
103e5092255SThiago Jung Bauermann
ima_template_setup(char * str)1049b9d4ce5SRoberto Sassu static int __init ima_template_setup(char *str)
1059b9d4ce5SRoberto Sassu {
1069b9d4ce5SRoberto Sassu struct ima_template_desc *template_desc;
1079b9d4ce5SRoberto Sassu int template_len = strlen(str);
1089b9d4ce5SRoberto Sassu
109bb8e52e4SRoberto Sassu if (template_setup_done)
110c2426d2aSRoberto Sassu return 1;
111c2426d2aSRoberto Sassu
112bb8e52e4SRoberto Sassu if (!ima_template)
1133f23d624SMimi Zohar ima_init_template_list();
1143f23d624SMimi Zohar
1159b9d4ce5SRoberto Sassu /*
1169b9d4ce5SRoberto Sassu * Verify that a template with the supplied name exists.
1179b9d4ce5SRoberto Sassu * If not, use CONFIG_IMA_DEFAULT_TEMPLATE.
1189b9d4ce5SRoberto Sassu */
1199b9d4ce5SRoberto Sassu template_desc = lookup_template_desc(str);
12071fed2eeSRoberto Sassu if (!template_desc) {
12171fed2eeSRoberto Sassu pr_err("template %s not found, using %s\n",
12271fed2eeSRoberto Sassu str, CONFIG_IMA_DEFAULT_TEMPLATE);
1239b9d4ce5SRoberto Sassu return 1;
12471fed2eeSRoberto Sassu }
1259b9d4ce5SRoberto Sassu
1269b9d4ce5SRoberto Sassu /*
1279b9d4ce5SRoberto Sassu * Verify whether the current hash algorithm is supported
1289b9d4ce5SRoberto Sassu * by the 'ima' template.
1299b9d4ce5SRoberto Sassu */
1309b9d4ce5SRoberto Sassu if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 &&
1319b9d4ce5SRoberto Sassu ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) {
13220ee451fSJoe Perches pr_err("template does not support hash alg\n");
1339b9d4ce5SRoberto Sassu return 1;
1349b9d4ce5SRoberto Sassu }
1359b9d4ce5SRoberto Sassu
1369b9d4ce5SRoberto Sassu ima_template = template_desc;
137bb8e52e4SRoberto Sassu template_setup_done = 1;
1389b9d4ce5SRoberto Sassu return 1;
1399b9d4ce5SRoberto Sassu }
1409b9d4ce5SRoberto Sassu __setup("ima_template=", ima_template_setup);
141a71dc65dSRoberto Sassu
ima_template_fmt_setup(char * str)142c2426d2aSRoberto Sassu static int __init ima_template_fmt_setup(char *str)
143c2426d2aSRoberto Sassu {
1443f23d624SMimi Zohar int num_templates = ARRAY_SIZE(builtin_templates);
145c2426d2aSRoberto Sassu
146bb8e52e4SRoberto Sassu if (template_setup_done)
147c2426d2aSRoberto Sassu return 1;
148c2426d2aSRoberto Sassu
149c2426d2aSRoberto Sassu if (template_desc_init_fields(str, NULL, NULL) < 0) {
150c2426d2aSRoberto Sassu pr_err("format string '%s' not valid, using template %s\n",
151c2426d2aSRoberto Sassu str, CONFIG_IMA_DEFAULT_TEMPLATE);
152c2426d2aSRoberto Sassu return 1;
153c2426d2aSRoberto Sassu }
154c2426d2aSRoberto Sassu
1553f23d624SMimi Zohar builtin_templates[num_templates - 1].fmt = str;
1563f23d624SMimi Zohar ima_template = builtin_templates + num_templates - 1;
157bb8e52e4SRoberto Sassu template_setup_done = 1;
1583f23d624SMimi Zohar
159c2426d2aSRoberto Sassu return 1;
160c2426d2aSRoberto Sassu }
161c2426d2aSRoberto Sassu __setup("ima_template_fmt=", ima_template_fmt_setup);
162c2426d2aSRoberto Sassu
lookup_template_desc(const char * name)16319453ce0SMatthew Garrett struct ima_template_desc *lookup_template_desc(const char *name)
164a71dc65dSRoberto Sassu {
1653f23d624SMimi Zohar struct ima_template_desc *template_desc;
1663f23d624SMimi Zohar int found = 0;
167a71dc65dSRoberto Sassu
1683f23d624SMimi Zohar rcu_read_lock();
1693f23d624SMimi Zohar list_for_each_entry_rcu(template_desc, &defined_templates, list) {
1703f23d624SMimi Zohar if ((strcmp(template_desc->name, name) == 0) ||
1713f23d624SMimi Zohar (strcmp(template_desc->fmt, name) == 0)) {
1723f23d624SMimi Zohar found = 1;
1733f23d624SMimi Zohar break;
174a71dc65dSRoberto Sassu }
1753f23d624SMimi Zohar }
1763f23d624SMimi Zohar rcu_read_unlock();
1773f23d624SMimi Zohar return found ? template_desc : NULL;
178a71dc65dSRoberto Sassu }
179a71dc65dSRoberto Sassu
180b2724d58SEric Biggers static const struct ima_template_field *
lookup_template_field(const char * field_id)181b2724d58SEric Biggers lookup_template_field(const char *field_id)
182adf53a77SRoberto Sassu {
183adf53a77SRoberto Sassu int i;
184adf53a77SRoberto Sassu
185adf53a77SRoberto Sassu for (i = 0; i < ARRAY_SIZE(supported_fields); i++)
186adf53a77SRoberto Sassu if (strncmp(supported_fields[i].field_id, field_id,
187adf53a77SRoberto Sassu IMA_TEMPLATE_FIELD_ID_MAX_LEN) == 0)
188adf53a77SRoberto Sassu return &supported_fields[i];
189adf53a77SRoberto Sassu return NULL;
190adf53a77SRoberto Sassu }
191adf53a77SRoberto Sassu
template_fmt_size(const char * template_fmt)192dbc335d2SRoberto Sassu static int template_fmt_size(const char *template_fmt)
193adf53a77SRoberto Sassu {
194adf53a77SRoberto Sassu char c;
195adf53a77SRoberto Sassu int template_fmt_len = strlen(template_fmt);
196adf53a77SRoberto Sassu int i = 0, j = 0;
197adf53a77SRoberto Sassu
198adf53a77SRoberto Sassu while (i < template_fmt_len) {
199adf53a77SRoberto Sassu c = template_fmt[i];
200adf53a77SRoberto Sassu if (c == '|')
201adf53a77SRoberto Sassu j++;
202adf53a77SRoberto Sassu i++;
203adf53a77SRoberto Sassu }
204adf53a77SRoberto Sassu
205adf53a77SRoberto Sassu return j + 1;
206adf53a77SRoberto Sassu }
207adf53a77SRoberto Sassu
template_desc_init_fields(const char * template_fmt,const struct ima_template_field *** fields,int * num_fields)20819453ce0SMatthew Garrett int template_desc_init_fields(const char *template_fmt,
209b2724d58SEric Biggers const struct ima_template_field ***fields,
210adf53a77SRoberto Sassu int *num_fields)
211adf53a77SRoberto Sassu {
2129f3166b8SRoberto Sassu const char *template_fmt_ptr;
213b2724d58SEric Biggers const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
214c7d09367SMimi Zohar int template_num_fields;
2151bd7faceSRoberto Sassu int i, len;
216adf53a77SRoberto Sassu
217c7d09367SMimi Zohar if (num_fields && *num_fields > 0) /* already initialized? */
218c7d09367SMimi Zohar return 0;
219c7d09367SMimi Zohar
220c7d09367SMimi Zohar template_num_fields = template_fmt_size(template_fmt);
221c7d09367SMimi Zohar
22271fed2eeSRoberto Sassu if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) {
22371fed2eeSRoberto Sassu pr_err("format string '%s' contains too many fields\n",
22471fed2eeSRoberto Sassu template_fmt);
225adf53a77SRoberto Sassu return -EINVAL;
22671fed2eeSRoberto Sassu }
227adf53a77SRoberto Sassu
2289f3166b8SRoberto Sassu for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields;
2299f3166b8SRoberto Sassu i++, template_fmt_ptr += len + 1) {
2309f3166b8SRoberto Sassu char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1];
231adf53a77SRoberto Sassu
2329f3166b8SRoberto Sassu len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr;
2339f3166b8SRoberto Sassu if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) {
2349f3166b8SRoberto Sassu pr_err("Invalid field with length %d\n", len);
2351bd7faceSRoberto Sassu return -EINVAL;
2369f3166b8SRoberto Sassu }
2379f3166b8SRoberto Sassu
2389f3166b8SRoberto Sassu memcpy(tmp_field_id, template_fmt_ptr, len);
2399f3166b8SRoberto Sassu tmp_field_id[len] = '\0';
2401bd7faceSRoberto Sassu found_fields[i] = lookup_template_field(tmp_field_id);
2411bd7faceSRoberto Sassu if (!found_fields[i]) {
2429f3166b8SRoberto Sassu pr_err("field '%s' not found\n", tmp_field_id);
2431bd7faceSRoberto Sassu return -ENOENT;
244adf53a77SRoberto Sassu }
245adf53a77SRoberto Sassu }
2461bd7faceSRoberto Sassu
247c2426d2aSRoberto Sassu if (fields && num_fields) {
248*25369175SXiu Jianfeng *fields = kmalloc_array(i, sizeof(**fields), GFP_KERNEL);
2491bd7faceSRoberto Sassu if (*fields == NULL)
2501bd7faceSRoberto Sassu return -ENOMEM;
2511bd7faceSRoberto Sassu
252*25369175SXiu Jianfeng memcpy(*fields, found_fields, i * sizeof(**fields));
253adf53a77SRoberto Sassu *num_fields = i;
254c2426d2aSRoberto Sassu }
255c2426d2aSRoberto Sassu
2561bd7faceSRoberto Sassu return 0;
257adf53a77SRoberto Sassu }
258adf53a77SRoberto Sassu
ima_init_template_list(void)2593f23d624SMimi Zohar void ima_init_template_list(void)
2603f23d624SMimi Zohar {
2613f23d624SMimi Zohar int i;
2623f23d624SMimi Zohar
2633f23d624SMimi Zohar if (!list_empty(&defined_templates))
2643f23d624SMimi Zohar return;
2653f23d624SMimi Zohar
2663f23d624SMimi Zohar spin_lock(&template_list);
2673f23d624SMimi Zohar for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) {
2683f23d624SMimi Zohar list_add_tail_rcu(&builtin_templates[i].list,
2693f23d624SMimi Zohar &defined_templates);
2703f23d624SMimi Zohar }
2713f23d624SMimi Zohar spin_unlock(&template_list);
2723f23d624SMimi Zohar }
2733f23d624SMimi Zohar
ima_template_desc_current(void)274a71dc65dSRoberto Sassu struct ima_template_desc *ima_template_desc_current(void)
275a71dc65dSRoberto Sassu {
2763f23d624SMimi Zohar if (!ima_template) {
2773f23d624SMimi Zohar ima_init_template_list();
2784286587dSMimi Zohar ima_template =
2794286587dSMimi Zohar lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE);
2803f23d624SMimi Zohar }
281a71dc65dSRoberto Sassu return ima_template;
282a71dc65dSRoberto Sassu }
283a71dc65dSRoberto Sassu
ima_template_desc_buf(void)284dea87d08SLakshmi Ramasubramanian struct ima_template_desc *ima_template_desc_buf(void)
285dea87d08SLakshmi Ramasubramanian {
286dea87d08SLakshmi Ramasubramanian if (!ima_buf_template) {
287dea87d08SLakshmi Ramasubramanian ima_init_template_list();
288dea87d08SLakshmi Ramasubramanian ima_buf_template = lookup_template_desc("ima-buf");
289dea87d08SLakshmi Ramasubramanian }
290dea87d08SLakshmi Ramasubramanian return ima_buf_template;
291dea87d08SLakshmi Ramasubramanian }
292dea87d08SLakshmi Ramasubramanian
ima_init_template(void)293e4a9c519SDmitry Kasatkin int __init ima_init_template(void)
294adf53a77SRoberto Sassu {
295b4148db5SDmitry Kasatkin struct ima_template_desc *template = ima_template_desc_current();
29671fed2eeSRoberto Sassu int result;
297adf53a77SRoberto Sassu
29871fed2eeSRoberto Sassu result = template_desc_init_fields(template->fmt,
299b4148db5SDmitry Kasatkin &(template->fields),
300b4148db5SDmitry Kasatkin &(template->num_fields));
301dea87d08SLakshmi Ramasubramanian if (result < 0) {
302dea87d08SLakshmi Ramasubramanian pr_err("template %s init failed, result: %d\n",
303dea87d08SLakshmi Ramasubramanian (strlen(template->name) ?
304dea87d08SLakshmi Ramasubramanian template->name : template->fmt), result);
305dea87d08SLakshmi Ramasubramanian return result;
306dea87d08SLakshmi Ramasubramanian }
307dea87d08SLakshmi Ramasubramanian
308dea87d08SLakshmi Ramasubramanian template = ima_template_desc_buf();
309dea87d08SLakshmi Ramasubramanian if (!template) {
310dea87d08SLakshmi Ramasubramanian pr_err("Failed to get ima-buf template\n");
311dea87d08SLakshmi Ramasubramanian return -EINVAL;
312dea87d08SLakshmi Ramasubramanian }
313dea87d08SLakshmi Ramasubramanian
314dea87d08SLakshmi Ramasubramanian result = template_desc_init_fields(template->fmt,
315dea87d08SLakshmi Ramasubramanian &(template->fields),
316dea87d08SLakshmi Ramasubramanian &(template->num_fields));
31771fed2eeSRoberto Sassu if (result < 0)
3187dbdb420SRoberto Sassu pr_err("template %s init failed, result: %d\n",
3197dbdb420SRoberto Sassu (strlen(template->name) ?
3207dbdb420SRoberto Sassu template->name : template->fmt), result);
32171fed2eeSRoberto Sassu
32271fed2eeSRoberto Sassu return result;
323adf53a77SRoberto Sassu }
32494c3aac5SMimi Zohar
restore_template_fmt(char * template_name)325c7d09367SMimi Zohar static struct ima_template_desc *restore_template_fmt(char *template_name)
326c7d09367SMimi Zohar {
327c7d09367SMimi Zohar struct ima_template_desc *template_desc = NULL;
328c7d09367SMimi Zohar int ret;
329c7d09367SMimi Zohar
330c7d09367SMimi Zohar ret = template_desc_init_fields(template_name, NULL, NULL);
331c7d09367SMimi Zohar if (ret < 0) {
332c7d09367SMimi Zohar pr_err("attempting to initialize the template \"%s\" failed\n",
333c7d09367SMimi Zohar template_name);
334c7d09367SMimi Zohar goto out;
335c7d09367SMimi Zohar }
336c7d09367SMimi Zohar
337c7d09367SMimi Zohar template_desc = kzalloc(sizeof(*template_desc), GFP_KERNEL);
338c7d09367SMimi Zohar if (!template_desc)
339c7d09367SMimi Zohar goto out;
340c7d09367SMimi Zohar
341c7d09367SMimi Zohar template_desc->name = "";
342c7d09367SMimi Zohar template_desc->fmt = kstrdup(template_name, GFP_KERNEL);
34311220db4SHuaxin Lu if (!template_desc->fmt) {
34411220db4SHuaxin Lu kfree(template_desc);
34511220db4SHuaxin Lu template_desc = NULL;
346c7d09367SMimi Zohar goto out;
34711220db4SHuaxin Lu }
348c7d09367SMimi Zohar
349c7d09367SMimi Zohar spin_lock(&template_list);
350c7d09367SMimi Zohar list_add_tail_rcu(&template_desc->list, &defined_templates);
351c7d09367SMimi Zohar spin_unlock(&template_list);
352c7d09367SMimi Zohar out:
353c7d09367SMimi Zohar return template_desc;
354c7d09367SMimi Zohar }
355c7d09367SMimi Zohar
ima_restore_template_data(struct ima_template_desc * template_desc,void * template_data,int template_data_size,struct ima_template_entry ** entry)35694c3aac5SMimi Zohar static int ima_restore_template_data(struct ima_template_desc *template_desc,
35794c3aac5SMimi Zohar void *template_data,
35894c3aac5SMimi Zohar int template_data_size,
35994c3aac5SMimi Zohar struct ima_template_entry **entry)
36094c3aac5SMimi Zohar {
361aa724fe1SRoberto Sassu struct tpm_digest *digests;
36294c3aac5SMimi Zohar int ret = 0;
36394c3aac5SMimi Zohar int i;
36494c3aac5SMimi Zohar
365fa5b5717SGustavo A. R. Silva *entry = kzalloc(struct_size(*entry, template_data,
366fa5b5717SGustavo A. R. Silva template_desc->num_fields), GFP_NOFS);
36794c3aac5SMimi Zohar if (!*entry)
36894c3aac5SMimi Zohar return -ENOMEM;
36994c3aac5SMimi Zohar
370aa724fe1SRoberto Sassu digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
371aa724fe1SRoberto Sassu sizeof(*digests), GFP_NOFS);
372aa724fe1SRoberto Sassu if (!digests) {
373aa724fe1SRoberto Sassu kfree(*entry);
374aa724fe1SRoberto Sassu return -ENOMEM;
375aa724fe1SRoberto Sassu }
376aa724fe1SRoberto Sassu
377aa724fe1SRoberto Sassu (*entry)->digests = digests;
378aa724fe1SRoberto Sassu
37928a8dc41SRoberto Sassu ret = ima_parse_buf(template_data, template_data + template_data_size,
38028a8dc41SRoberto Sassu NULL, template_desc->num_fields,
38128a8dc41SRoberto Sassu (*entry)->template_data, NULL, NULL,
38228a8dc41SRoberto Sassu ENFORCE_FIELDS | ENFORCE_BUFEND, "template data");
38328a8dc41SRoberto Sassu if (ret < 0) {
384aa724fe1SRoberto Sassu kfree((*entry)->digests);
38528a8dc41SRoberto Sassu kfree(*entry);
38628a8dc41SRoberto Sassu return ret;
38728a8dc41SRoberto Sassu }
38828a8dc41SRoberto Sassu
38994c3aac5SMimi Zohar (*entry)->template_desc = template_desc;
39094c3aac5SMimi Zohar for (i = 0; i < template_desc->num_fields; i++) {
39128a8dc41SRoberto Sassu struct ima_field_data *field_data = &(*entry)->template_data[i];
39228a8dc41SRoberto Sassu u8 *data = field_data->data;
39394c3aac5SMimi Zohar
39494c3aac5SMimi Zohar (*entry)->template_data[i].data =
39594c3aac5SMimi Zohar kzalloc(field_data->len + 1, GFP_KERNEL);
39694c3aac5SMimi Zohar if (!(*entry)->template_data[i].data) {
39794c3aac5SMimi Zohar ret = -ENOMEM;
39894c3aac5SMimi Zohar break;
39994c3aac5SMimi Zohar }
40028a8dc41SRoberto Sassu memcpy((*entry)->template_data[i].data, data, field_data->len);
40128a8dc41SRoberto Sassu (*entry)->template_data_len += sizeof(field_data->len);
40294c3aac5SMimi Zohar (*entry)->template_data_len += field_data->len;
40394c3aac5SMimi Zohar }
40494c3aac5SMimi Zohar
40594c3aac5SMimi Zohar if (ret < 0) {
40694c3aac5SMimi Zohar ima_free_template_entry(*entry);
40794c3aac5SMimi Zohar *entry = NULL;
40894c3aac5SMimi Zohar }
40994c3aac5SMimi Zohar
41094c3aac5SMimi Zohar return ret;
41194c3aac5SMimi Zohar }
41294c3aac5SMimi Zohar
41394c3aac5SMimi Zohar /* Restore the serialized binary measurement list without extending PCRs. */
ima_restore_measurement_list(loff_t size,void * buf)41494c3aac5SMimi Zohar int ima_restore_measurement_list(loff_t size, void *buf)
41594c3aac5SMimi Zohar {
41694c3aac5SMimi Zohar char template_name[MAX_TEMPLATE_NAME_LEN];
4171ea973dfSRoberto Sassu unsigned char zero[TPM_DIGEST_SIZE] = { 0 };
41894c3aac5SMimi Zohar
41994c3aac5SMimi Zohar struct ima_kexec_hdr *khdr = buf;
42047fdee60SRoberto Sassu struct ima_field_data hdr[HDR__LAST] = {
42147fdee60SRoberto Sassu [HDR_PCR] = {.len = sizeof(u32)},
42247fdee60SRoberto Sassu [HDR_DIGEST] = {.len = TPM_DIGEST_SIZE},
42347fdee60SRoberto Sassu };
42494c3aac5SMimi Zohar
42594c3aac5SMimi Zohar void *bufp = buf + sizeof(*khdr);
426d68a6fe9SMimi Zohar void *bufendp;
42794c3aac5SMimi Zohar struct ima_template_entry *entry;
42894c3aac5SMimi Zohar struct ima_template_desc *template_desc;
42947fdee60SRoberto Sassu DECLARE_BITMAP(hdr_mask, HDR__LAST);
43094c3aac5SMimi Zohar unsigned long count = 0;
43194c3aac5SMimi Zohar int ret = 0;
43294c3aac5SMimi Zohar
43394c3aac5SMimi Zohar if (!buf || size < sizeof(*khdr))
43494c3aac5SMimi Zohar return 0;
43594c3aac5SMimi Zohar
436d68a6fe9SMimi Zohar if (ima_canonical_fmt) {
43724c9ae23SRoberto Sassu khdr->version = le16_to_cpu((__force __le16)khdr->version);
43824c9ae23SRoberto Sassu khdr->count = le64_to_cpu((__force __le64)khdr->count);
43924c9ae23SRoberto Sassu khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size);
440d68a6fe9SMimi Zohar }
441d68a6fe9SMimi Zohar
44294c3aac5SMimi Zohar if (khdr->version != 1) {
44394c3aac5SMimi Zohar pr_err("attempting to restore a incompatible measurement list");
44494c3aac5SMimi Zohar return -EINVAL;
44594c3aac5SMimi Zohar }
44694c3aac5SMimi Zohar
44794c3aac5SMimi Zohar if (khdr->count > ULONG_MAX - 1) {
44894c3aac5SMimi Zohar pr_err("attempting to restore too many measurements");
44994c3aac5SMimi Zohar return -EINVAL;
45094c3aac5SMimi Zohar }
45194c3aac5SMimi Zohar
45247fdee60SRoberto Sassu bitmap_zero(hdr_mask, HDR__LAST);
45347fdee60SRoberto Sassu bitmap_set(hdr_mask, HDR_PCR, 1);
45447fdee60SRoberto Sassu bitmap_set(hdr_mask, HDR_DIGEST, 1);
45547fdee60SRoberto Sassu
45694c3aac5SMimi Zohar /*
45794c3aac5SMimi Zohar * ima kexec buffer prefix: version, buffer size, count
45894c3aac5SMimi Zohar * v1 format: pcr, digest, template-name-len, template-name,
45994c3aac5SMimi Zohar * template-data-size, template-data
46094c3aac5SMimi Zohar */
461d68a6fe9SMimi Zohar bufendp = buf + khdr->buffer_size;
46294c3aac5SMimi Zohar while ((bufp < bufendp) && (count++ < khdr->count)) {
46347fdee60SRoberto Sassu int enforce_mask = ENFORCE_FIELDS;
46447fdee60SRoberto Sassu
46547fdee60SRoberto Sassu enforce_mask |= (count == khdr->count) ? ENFORCE_BUFEND : 0;
46647fdee60SRoberto Sassu ret = ima_parse_buf(bufp, bufendp, &bufp, HDR__LAST, hdr, NULL,
46747fdee60SRoberto Sassu hdr_mask, enforce_mask, "entry header");
46847fdee60SRoberto Sassu if (ret < 0)
46994c3aac5SMimi Zohar break;
47094c3aac5SMimi Zohar
47147fdee60SRoberto Sassu if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) {
47272bf83b0SJoe Perches pr_err("attempting to restore a template name that is too long\n");
47394c3aac5SMimi Zohar ret = -EINVAL;
47494c3aac5SMimi Zohar break;
47594c3aac5SMimi Zohar }
47694c3aac5SMimi Zohar
47794c3aac5SMimi Zohar /* template name is not null terminated */
47847fdee60SRoberto Sassu memcpy(template_name, hdr[HDR_TEMPLATE_NAME].data,
47947fdee60SRoberto Sassu hdr[HDR_TEMPLATE_NAME].len);
48047fdee60SRoberto Sassu template_name[hdr[HDR_TEMPLATE_NAME].len] = 0;
48194c3aac5SMimi Zohar
48294c3aac5SMimi Zohar if (strcmp(template_name, "ima") == 0) {
48372bf83b0SJoe Perches pr_err("attempting to restore an unsupported template \"%s\" failed\n",
48472bf83b0SJoe Perches template_name);
48594c3aac5SMimi Zohar ret = -EINVAL;
48694c3aac5SMimi Zohar break;
48794c3aac5SMimi Zohar }
48894c3aac5SMimi Zohar
48994c3aac5SMimi Zohar template_desc = lookup_template_desc(template_name);
49094c3aac5SMimi Zohar if (!template_desc) {
491c7d09367SMimi Zohar template_desc = restore_template_fmt(template_name);
492c7d09367SMimi Zohar if (!template_desc)
493c7d09367SMimi Zohar break;
494c7d09367SMimi Zohar }
495c7d09367SMimi Zohar
496c7d09367SMimi Zohar /*
497c7d09367SMimi Zohar * Only the running system's template format is initialized
498c7d09367SMimi Zohar * on boot. As needed, initialize the other template formats.
499c7d09367SMimi Zohar */
500c7d09367SMimi Zohar ret = template_desc_init_fields(template_desc->fmt,
501c7d09367SMimi Zohar &(template_desc->fields),
502c7d09367SMimi Zohar &(template_desc->num_fields));
503c7d09367SMimi Zohar if (ret < 0) {
50472bf83b0SJoe Perches pr_err("attempting to restore the template fmt \"%s\" failed\n",
50572bf83b0SJoe Perches template_desc->fmt);
50694c3aac5SMimi Zohar ret = -EINVAL;
50794c3aac5SMimi Zohar break;
50894c3aac5SMimi Zohar }
50994c3aac5SMimi Zohar
51094c3aac5SMimi Zohar ret = ima_restore_template_data(template_desc,
51147fdee60SRoberto Sassu hdr[HDR_TEMPLATE_DATA].data,
51247fdee60SRoberto Sassu hdr[HDR_TEMPLATE_DATA].len,
51394c3aac5SMimi Zohar &entry);
51494c3aac5SMimi Zohar if (ret < 0)
51594c3aac5SMimi Zohar break;
51694c3aac5SMimi Zohar
5171ea973dfSRoberto Sassu if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {
5181ea973dfSRoberto Sassu ret = ima_calc_field_array_hash(
5191ea973dfSRoberto Sassu &entry->template_data[0],
5201ea973dfSRoberto Sassu entry);
5211ea973dfSRoberto Sassu if (ret < 0) {
5221ea973dfSRoberto Sassu pr_err("cannot calculate template digest\n");
5231ea973dfSRoberto Sassu ret = -EINVAL;
5241ea973dfSRoberto Sassu break;
5251ea973dfSRoberto Sassu }
5261ea973dfSRoberto Sassu }
5271ea973dfSRoberto Sassu
5287990ccafSLi Huafei entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :
52924c9ae23SRoberto Sassu le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data));
53094c3aac5SMimi Zohar ret = ima_restore_measurement_entry(entry);
53194c3aac5SMimi Zohar if (ret < 0)
53294c3aac5SMimi Zohar break;
53394c3aac5SMimi Zohar
53494c3aac5SMimi Zohar }
53594c3aac5SMimi Zohar return ret;
53694c3aac5SMimi Zohar }
537