1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2013 Politecnico di Torino, Italy |
4 | * TORSEC group -- https://security.polito.it |
5 | * |
6 | * Author: Roberto Sassu <roberto.sassu@polito.it> |
7 | * |
8 | * File: ima_template.c |
9 | * Helpers to manage template descriptors. |
10 | */ |
11 | |
12 | #include <linux/rculist.h> |
13 | #include "ima.h" |
14 | #include "ima_template_lib.h" |
15 | |
16 | enum { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME, |
17 | HDR_TEMPLATE_DATA, HDR__LAST }; |
18 | |
19 | static struct ima_template_desc builtin_templates[] = { |
20 | {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, |
21 | {.name = "ima-ng" , .fmt = "d-ng|n-ng" }, |
22 | {.name = "ima-sig" , .fmt = "d-ng|n-ng|sig" }, |
23 | {.name = "ima-ngv2" , .fmt = "d-ngv2|n-ng" }, |
24 | {.name = "ima-sigv2" , .fmt = "d-ngv2|n-ng|sig" }, |
25 | {.name = "ima-buf" , .fmt = "d-ng|n-ng|buf" }, |
26 | {.name = "ima-modsig" , .fmt = "d-ng|n-ng|sig|d-modsig|modsig" }, |
27 | {.name = "evm-sig" , |
28 | .fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode" }, |
29 | {.name = "" , .fmt = "" }, /* placeholder for a custom format */ |
30 | }; |
31 | |
32 | static LIST_HEAD(defined_templates); |
33 | static DEFINE_SPINLOCK(template_list); |
34 | static int template_setup_done; |
35 | |
36 | static const struct ima_template_field supported_fields[] = { |
37 | {.field_id = "d" , .field_init = ima_eventdigest_init, |
38 | .field_show = ima_show_template_digest}, |
39 | {.field_id = "n" , .field_init = ima_eventname_init, |
40 | .field_show = ima_show_template_string}, |
41 | {.field_id = "d-ng" , .field_init = ima_eventdigest_ng_init, |
42 | .field_show = ima_show_template_digest_ng}, |
43 | {.field_id = "d-ngv2" , .field_init = ima_eventdigest_ngv2_init, |
44 | .field_show = ima_show_template_digest_ngv2}, |
45 | {.field_id = "n-ng" , .field_init = ima_eventname_ng_init, |
46 | .field_show = ima_show_template_string}, |
47 | {.field_id = "sig" , .field_init = ima_eventsig_init, |
48 | .field_show = ima_show_template_sig}, |
49 | {.field_id = "buf" , .field_init = ima_eventbuf_init, |
50 | .field_show = ima_show_template_buf}, |
51 | {.field_id = "d-modsig" , .field_init = ima_eventdigest_modsig_init, |
52 | .field_show = ima_show_template_digest_ng}, |
53 | {.field_id = "modsig" , .field_init = ima_eventmodsig_init, |
54 | .field_show = ima_show_template_sig}, |
55 | {.field_id = "evmsig" , .field_init = ima_eventevmsig_init, |
56 | .field_show = ima_show_template_sig}, |
57 | {.field_id = "iuid" , .field_init = ima_eventinodeuid_init, |
58 | .field_show = ima_show_template_uint}, |
59 | {.field_id = "igid" , .field_init = ima_eventinodegid_init, |
60 | .field_show = ima_show_template_uint}, |
61 | {.field_id = "imode" , .field_init = ima_eventinodemode_init, |
62 | .field_show = ima_show_template_uint}, |
63 | {.field_id = "xattrnames" , |
64 | .field_init = ima_eventinodexattrnames_init, |
65 | .field_show = ima_show_template_string}, |
66 | {.field_id = "xattrlengths" , |
67 | .field_init = ima_eventinodexattrlengths_init, |
68 | .field_show = ima_show_template_sig}, |
69 | {.field_id = "xattrvalues" , |
70 | .field_init = ima_eventinodexattrvalues_init, |
71 | .field_show = ima_show_template_sig}, |
72 | }; |
73 | |
74 | /* |
75 | * Used when restoring measurements carried over from a kexec. 'd' and 'n' don't |
76 | * need to be accounted for since they shouldn't be defined in the same template |
77 | * description as 'd-ng' and 'n-ng' respectively. |
78 | */ |
79 | #define MAX_TEMPLATE_NAME_LEN \ |
80 | sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode") |
81 | |
82 | static struct ima_template_desc *ima_template; |
83 | static struct ima_template_desc *ima_buf_template; |
84 | |
85 | /** |
86 | * ima_template_has_modsig - Check whether template has modsig-related fields. |
87 | * @ima_template: IMA template to check. |
88 | * |
89 | * Tells whether the given template has fields referencing a file's appended |
90 | * signature. |
91 | */ |
92 | bool ima_template_has_modsig(const struct ima_template_desc *ima_template) |
93 | { |
94 | int i; |
95 | |
96 | for (i = 0; i < ima_template->num_fields; i++) |
97 | if (!strcmp(ima_template->fields[i]->field_id, "modsig" ) || |
98 | !strcmp(ima_template->fields[i]->field_id, "d-modsig" )) |
99 | return true; |
100 | |
101 | return false; |
102 | } |
103 | |
104 | static int __init ima_template_setup(char *str) |
105 | { |
106 | struct ima_template_desc *template_desc; |
107 | int template_len = strlen(str); |
108 | |
109 | if (template_setup_done) |
110 | return 1; |
111 | |
112 | if (!ima_template) |
113 | ima_init_template_list(); |
114 | |
115 | /* |
116 | * Verify that a template with the supplied name exists. |
117 | * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. |
118 | */ |
119 | template_desc = lookup_template_desc(name: str); |
120 | if (!template_desc) { |
121 | pr_err("template %s not found, using %s\n" , |
122 | str, CONFIG_IMA_DEFAULT_TEMPLATE); |
123 | return 1; |
124 | } |
125 | |
126 | /* |
127 | * Verify whether the current hash algorithm is supported |
128 | * by the 'ima' template. |
129 | */ |
130 | if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 && |
131 | ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) { |
132 | pr_err("template does not support hash alg\n" ); |
133 | return 1; |
134 | } |
135 | |
136 | ima_template = template_desc; |
137 | template_setup_done = 1; |
138 | return 1; |
139 | } |
140 | __setup("ima_template=" , ima_template_setup); |
141 | |
142 | static int __init ima_template_fmt_setup(char *str) |
143 | { |
144 | int num_templates = ARRAY_SIZE(builtin_templates); |
145 | |
146 | if (template_setup_done) |
147 | return 1; |
148 | |
149 | if (template_desc_init_fields(template_fmt: str, NULL, NULL) < 0) { |
150 | pr_err("format string '%s' not valid, using template %s\n" , |
151 | str, CONFIG_IMA_DEFAULT_TEMPLATE); |
152 | return 1; |
153 | } |
154 | |
155 | builtin_templates[num_templates - 1].fmt = str; |
156 | ima_template = builtin_templates + num_templates - 1; |
157 | template_setup_done = 1; |
158 | |
159 | return 1; |
160 | } |
161 | __setup("ima_template_fmt=" , ima_template_fmt_setup); |
162 | |
163 | struct ima_template_desc *lookup_template_desc(const char *name) |
164 | { |
165 | struct ima_template_desc *template_desc; |
166 | int found = 0; |
167 | |
168 | rcu_read_lock(); |
169 | list_for_each_entry_rcu(template_desc, &defined_templates, list) { |
170 | if ((strcmp(template_desc->name, name) == 0) || |
171 | (strcmp(template_desc->fmt, name) == 0)) { |
172 | found = 1; |
173 | break; |
174 | } |
175 | } |
176 | rcu_read_unlock(); |
177 | return found ? template_desc : NULL; |
178 | } |
179 | |
180 | static const struct ima_template_field * |
181 | lookup_template_field(const char *field_id) |
182 | { |
183 | int i; |
184 | |
185 | for (i = 0; i < ARRAY_SIZE(supported_fields); i++) |
186 | if (strncmp(supported_fields[i].field_id, field_id, |
187 | IMA_TEMPLATE_FIELD_ID_MAX_LEN) == 0) |
188 | return &supported_fields[i]; |
189 | return NULL; |
190 | } |
191 | |
192 | static int template_fmt_size(const char *template_fmt) |
193 | { |
194 | char c; |
195 | int template_fmt_len = strlen(template_fmt); |
196 | int i = 0, j = 0; |
197 | |
198 | while (i < template_fmt_len) { |
199 | c = template_fmt[i]; |
200 | if (c == '|') |
201 | j++; |
202 | i++; |
203 | } |
204 | |
205 | return j + 1; |
206 | } |
207 | |
208 | int template_desc_init_fields(const char *template_fmt, |
209 | const struct ima_template_field ***fields, |
210 | int *num_fields) |
211 | { |
212 | const char *template_fmt_ptr; |
213 | const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; |
214 | int template_num_fields; |
215 | int i, len; |
216 | |
217 | if (num_fields && *num_fields > 0) /* already initialized? */ |
218 | return 0; |
219 | |
220 | template_num_fields = template_fmt_size(template_fmt); |
221 | |
222 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) { |
223 | pr_err("format string '%s' contains too many fields\n" , |
224 | template_fmt); |
225 | return -EINVAL; |
226 | } |
227 | |
228 | for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields; |
229 | i++, template_fmt_ptr += len + 1) { |
230 | char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1]; |
231 | |
232 | len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr; |
233 | if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) { |
234 | pr_err("Invalid field with length %d\n" , len); |
235 | return -EINVAL; |
236 | } |
237 | |
238 | memcpy(tmp_field_id, template_fmt_ptr, len); |
239 | tmp_field_id[len] = '\0'; |
240 | found_fields[i] = lookup_template_field(field_id: tmp_field_id); |
241 | if (!found_fields[i]) { |
242 | pr_err("field '%s' not found\n" , tmp_field_id); |
243 | return -ENOENT; |
244 | } |
245 | } |
246 | |
247 | if (fields && num_fields) { |
248 | *fields = kmalloc_array(n: i, size: sizeof(**fields), GFP_KERNEL); |
249 | if (*fields == NULL) |
250 | return -ENOMEM; |
251 | |
252 | memcpy(*fields, found_fields, i * sizeof(**fields)); |
253 | *num_fields = i; |
254 | } |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | void ima_init_template_list(void) |
260 | { |
261 | int i; |
262 | |
263 | if (!list_empty(head: &defined_templates)) |
264 | return; |
265 | |
266 | spin_lock(lock: &template_list); |
267 | for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) { |
268 | list_add_tail_rcu(new: &builtin_templates[i].list, |
269 | head: &defined_templates); |
270 | } |
271 | spin_unlock(lock: &template_list); |
272 | } |
273 | |
274 | struct ima_template_desc *ima_template_desc_current(void) |
275 | { |
276 | if (!ima_template) { |
277 | ima_init_template_list(); |
278 | ima_template = |
279 | lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE); |
280 | } |
281 | return ima_template; |
282 | } |
283 | |
284 | struct ima_template_desc *ima_template_desc_buf(void) |
285 | { |
286 | if (!ima_buf_template) { |
287 | ima_init_template_list(); |
288 | ima_buf_template = lookup_template_desc(name: "ima-buf" ); |
289 | } |
290 | return ima_buf_template; |
291 | } |
292 | |
293 | int __init ima_init_template(void) |
294 | { |
295 | struct ima_template_desc *template = ima_template_desc_current(); |
296 | int result; |
297 | |
298 | result = template_desc_init_fields(template_fmt: template->fmt, |
299 | fields: &(template->fields), |
300 | num_fields: &(template->num_fields)); |
301 | if (result < 0) { |
302 | pr_err("template %s init failed, result: %d\n" , |
303 | (strlen(template->name) ? |
304 | template->name : template->fmt), result); |
305 | return result; |
306 | } |
307 | |
308 | template = ima_template_desc_buf(); |
309 | if (!template) { |
310 | pr_err("Failed to get ima-buf template\n" ); |
311 | return -EINVAL; |
312 | } |
313 | |
314 | result = template_desc_init_fields(template_fmt: template->fmt, |
315 | fields: &(template->fields), |
316 | num_fields: &(template->num_fields)); |
317 | if (result < 0) |
318 | pr_err("template %s init failed, result: %d\n" , |
319 | (strlen(template->name) ? |
320 | template->name : template->fmt), result); |
321 | |
322 | return result; |
323 | } |
324 | |
325 | static struct ima_template_desc *restore_template_fmt(char *template_name) |
326 | { |
327 | struct ima_template_desc *template_desc = NULL; |
328 | int ret; |
329 | |
330 | ret = template_desc_init_fields(template_fmt: template_name, NULL, NULL); |
331 | if (ret < 0) { |
332 | pr_err("attempting to initialize the template \"%s\" failed\n" , |
333 | template_name); |
334 | goto out; |
335 | } |
336 | |
337 | template_desc = kzalloc(size: sizeof(*template_desc), GFP_KERNEL); |
338 | if (!template_desc) |
339 | goto out; |
340 | |
341 | template_desc->name = "" ; |
342 | template_desc->fmt = kstrdup(s: template_name, GFP_KERNEL); |
343 | if (!template_desc->fmt) { |
344 | kfree(objp: template_desc); |
345 | template_desc = NULL; |
346 | goto out; |
347 | } |
348 | |
349 | spin_lock(lock: &template_list); |
350 | list_add_tail_rcu(new: &template_desc->list, head: &defined_templates); |
351 | spin_unlock(lock: &template_list); |
352 | out: |
353 | return template_desc; |
354 | } |
355 | |
356 | static int ima_restore_template_data(struct ima_template_desc *template_desc, |
357 | void *template_data, |
358 | int template_data_size, |
359 | struct ima_template_entry **entry) |
360 | { |
361 | struct tpm_digest *digests; |
362 | int ret = 0; |
363 | int i; |
364 | |
365 | *entry = kzalloc(struct_size(*entry, template_data, |
366 | template_desc->num_fields), GFP_NOFS); |
367 | if (!*entry) |
368 | return -ENOMEM; |
369 | |
370 | digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, |
371 | size: sizeof(*digests), GFP_NOFS); |
372 | if (!digests) { |
373 | kfree(objp: *entry); |
374 | return -ENOMEM; |
375 | } |
376 | |
377 | (*entry)->digests = digests; |
378 | |
379 | ret = ima_parse_buf(bufstartp: template_data, bufendp: template_data + template_data_size, |
380 | NULL, maxfields: template_desc->num_fields, |
381 | fields: (*entry)->template_data, NULL, NULL, |
382 | ENFORCE_FIELDS | ENFORCE_BUFEND, bufname: "template data" ); |
383 | if (ret < 0) { |
384 | kfree(objp: (*entry)->digests); |
385 | kfree(objp: *entry); |
386 | return ret; |
387 | } |
388 | |
389 | (*entry)->template_desc = template_desc; |
390 | for (i = 0; i < template_desc->num_fields; i++) { |
391 | struct ima_field_data *field_data = &(*entry)->template_data[i]; |
392 | u8 *data = field_data->data; |
393 | |
394 | (*entry)->template_data[i].data = |
395 | kzalloc(size: field_data->len + 1, GFP_KERNEL); |
396 | if (!(*entry)->template_data[i].data) { |
397 | ret = -ENOMEM; |
398 | break; |
399 | } |
400 | memcpy((*entry)->template_data[i].data, data, field_data->len); |
401 | (*entry)->template_data_len += sizeof(field_data->len); |
402 | (*entry)->template_data_len += field_data->len; |
403 | } |
404 | |
405 | if (ret < 0) { |
406 | ima_free_template_entry(entry: *entry); |
407 | *entry = NULL; |
408 | } |
409 | |
410 | return ret; |
411 | } |
412 | |
413 | /* Restore the serialized binary measurement list without extending PCRs. */ |
414 | int ima_restore_measurement_list(loff_t size, void *buf) |
415 | { |
416 | char template_name[MAX_TEMPLATE_NAME_LEN]; |
417 | unsigned char zero[TPM_DIGEST_SIZE] = { 0 }; |
418 | |
419 | struct ima_kexec_hdr *khdr = buf; |
420 | struct ima_field_data hdr[HDR__LAST] = { |
421 | [HDR_PCR] = {.len = sizeof(u32)}, |
422 | [HDR_DIGEST] = {.len = TPM_DIGEST_SIZE}, |
423 | }; |
424 | |
425 | void *bufp = buf + sizeof(*khdr); |
426 | void *bufendp; |
427 | struct ima_template_entry *entry; |
428 | struct ima_template_desc *template_desc; |
429 | DECLARE_BITMAP(hdr_mask, HDR__LAST); |
430 | unsigned long count = 0; |
431 | int ret = 0; |
432 | |
433 | if (!buf || size < sizeof(*khdr)) |
434 | return 0; |
435 | |
436 | if (ima_canonical_fmt) { |
437 | khdr->version = le16_to_cpu((__force __le16)khdr->version); |
438 | khdr->count = le64_to_cpu((__force __le64)khdr->count); |
439 | khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size); |
440 | } |
441 | |
442 | if (khdr->version != 1) { |
443 | pr_err("attempting to restore a incompatible measurement list" ); |
444 | return -EINVAL; |
445 | } |
446 | |
447 | if (khdr->count > ULONG_MAX - 1) { |
448 | pr_err("attempting to restore too many measurements" ); |
449 | return -EINVAL; |
450 | } |
451 | |
452 | bitmap_zero(dst: hdr_mask, nbits: HDR__LAST); |
453 | bitmap_set(map: hdr_mask, start: HDR_PCR, nbits: 1); |
454 | bitmap_set(map: hdr_mask, start: HDR_DIGEST, nbits: 1); |
455 | |
456 | /* |
457 | * ima kexec buffer prefix: version, buffer size, count |
458 | * v1 format: pcr, digest, template-name-len, template-name, |
459 | * template-data-size, template-data |
460 | */ |
461 | bufendp = buf + khdr->buffer_size; |
462 | while ((bufp < bufendp) && (count++ < khdr->count)) { |
463 | int enforce_mask = ENFORCE_FIELDS; |
464 | |
465 | enforce_mask |= (count == khdr->count) ? ENFORCE_BUFEND : 0; |
466 | ret = ima_parse_buf(bufstartp: bufp, bufendp, bufcurp: &bufp, maxfields: HDR__LAST, fields: hdr, NULL, |
467 | len_mask: hdr_mask, enforce_mask, bufname: "entry header" ); |
468 | if (ret < 0) |
469 | break; |
470 | |
471 | if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) { |
472 | pr_err("attempting to restore a template name that is too long\n" ); |
473 | ret = -EINVAL; |
474 | break; |
475 | } |
476 | |
477 | /* template name is not null terminated */ |
478 | memcpy(template_name, hdr[HDR_TEMPLATE_NAME].data, |
479 | hdr[HDR_TEMPLATE_NAME].len); |
480 | template_name[hdr[HDR_TEMPLATE_NAME].len] = 0; |
481 | |
482 | if (strcmp(template_name, "ima" ) == 0) { |
483 | pr_err("attempting to restore an unsupported template \"%s\" failed\n" , |
484 | template_name); |
485 | ret = -EINVAL; |
486 | break; |
487 | } |
488 | |
489 | template_desc = lookup_template_desc(name: template_name); |
490 | if (!template_desc) { |
491 | template_desc = restore_template_fmt(template_name); |
492 | if (!template_desc) |
493 | break; |
494 | } |
495 | |
496 | /* |
497 | * Only the running system's template format is initialized |
498 | * on boot. As needed, initialize the other template formats. |
499 | */ |
500 | ret = template_desc_init_fields(template_fmt: template_desc->fmt, |
501 | fields: &(template_desc->fields), |
502 | num_fields: &(template_desc->num_fields)); |
503 | if (ret < 0) { |
504 | pr_err("attempting to restore the template fmt \"%s\" failed\n" , |
505 | template_desc->fmt); |
506 | ret = -EINVAL; |
507 | break; |
508 | } |
509 | |
510 | ret = ima_restore_template_data(template_desc, |
511 | template_data: hdr[HDR_TEMPLATE_DATA].data, |
512 | template_data_size: hdr[HDR_TEMPLATE_DATA].len, |
513 | entry: &entry); |
514 | if (ret < 0) |
515 | break; |
516 | |
517 | if (memcmp(p: hdr[HDR_DIGEST].data, q: zero, size: sizeof(zero))) { |
518 | ret = ima_calc_field_array_hash( |
519 | field_data: &entry->template_data[0], |
520 | entry); |
521 | if (ret < 0) { |
522 | pr_err("cannot calculate template digest\n" ); |
523 | ret = -EINVAL; |
524 | break; |
525 | } |
526 | } |
527 | |
528 | entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) : |
529 | le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data)); |
530 | ret = ima_restore_measurement_entry(entry); |
531 | if (ret < 0) |
532 | break; |
533 | |
534 | } |
535 | return ret; |
536 | } |
537 | |