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