.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2013 Politecnico di Torino, Italy |
---|
3 | | - * TORSEC group -- http://security.polito.it |
---|
| 4 | + * TORSEC group -- https://security.polito.it |
---|
4 | 5 | * |
---|
5 | 6 | * Author: Roberto Sassu <roberto.sassu@polito.it> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License as |
---|
9 | | - * published by the Free Software Foundation, version 2 of the |
---|
10 | | - * License. |
---|
11 | 7 | * |
---|
12 | 8 | * File: ima_template.c |
---|
13 | 9 | * Helpers to manage template descriptors. |
---|
14 | 10 | */ |
---|
15 | | - |
---|
16 | | -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
17 | 11 | |
---|
18 | 12 | #include <linux/rculist.h> |
---|
19 | 13 | #include "ima.h" |
---|
.. | .. |
---|
26 | 20 | {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, |
---|
27 | 21 | {.name = "ima-ng", .fmt = "d-ng|n-ng"}, |
---|
28 | 22 | {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, |
---|
| 23 | + {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, |
---|
| 24 | + {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"}, |
---|
29 | 25 | {.name = "", .fmt = ""}, /* placeholder for a custom format */ |
---|
30 | 26 | }; |
---|
31 | 27 | |
---|
.. | .. |
---|
33 | 29 | static DEFINE_SPINLOCK(template_list); |
---|
34 | 30 | static int template_setup_done; |
---|
35 | 31 | |
---|
36 | | -static struct ima_template_field supported_fields[] = { |
---|
| 32 | +static const struct ima_template_field supported_fields[] = { |
---|
37 | 33 | {.field_id = "d", .field_init = ima_eventdigest_init, |
---|
38 | 34 | .field_show = ima_show_template_digest}, |
---|
39 | 35 | {.field_id = "n", .field_init = ima_eventname_init, |
---|
.. | .. |
---|
44 | 40 | .field_show = ima_show_template_string}, |
---|
45 | 41 | {.field_id = "sig", .field_init = ima_eventsig_init, |
---|
46 | 42 | .field_show = ima_show_template_sig}, |
---|
| 43 | + {.field_id = "buf", .field_init = ima_eventbuf_init, |
---|
| 44 | + .field_show = ima_show_template_buf}, |
---|
| 45 | + {.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init, |
---|
| 46 | + .field_show = ima_show_template_digest_ng}, |
---|
| 47 | + {.field_id = "modsig", .field_init = ima_eventmodsig_init, |
---|
| 48 | + .field_show = ima_show_template_sig}, |
---|
47 | 49 | }; |
---|
48 | | -#define MAX_TEMPLATE_NAME_LEN 15 |
---|
| 50 | + |
---|
| 51 | +/* |
---|
| 52 | + * Used when restoring measurements carried over from a kexec. 'd' and 'n' don't |
---|
| 53 | + * need to be accounted for since they shouldn't be defined in the same template |
---|
| 54 | + * description as 'd-ng' and 'n-ng' respectively. |
---|
| 55 | + */ |
---|
| 56 | +#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig") |
---|
49 | 57 | |
---|
50 | 58 | static struct ima_template_desc *ima_template; |
---|
51 | | -static struct ima_template_desc *lookup_template_desc(const char *name); |
---|
52 | | -static int template_desc_init_fields(const char *template_fmt, |
---|
53 | | - struct ima_template_field ***fields, |
---|
54 | | - int *num_fields); |
---|
| 59 | + |
---|
| 60 | +/** |
---|
| 61 | + * ima_template_has_modsig - Check whether template has modsig-related fields. |
---|
| 62 | + * @ima_template: IMA template to check. |
---|
| 63 | + * |
---|
| 64 | + * Tells whether the given template has fields referencing a file's appended |
---|
| 65 | + * signature. |
---|
| 66 | + */ |
---|
| 67 | +bool ima_template_has_modsig(const struct ima_template_desc *ima_template) |
---|
| 68 | +{ |
---|
| 69 | + int i; |
---|
| 70 | + |
---|
| 71 | + for (i = 0; i < ima_template->num_fields; i++) |
---|
| 72 | + if (!strcmp(ima_template->fields[i]->field_id, "modsig") || |
---|
| 73 | + !strcmp(ima_template->fields[i]->field_id, "d-modsig")) |
---|
| 74 | + return true; |
---|
| 75 | + |
---|
| 76 | + return false; |
---|
| 77 | +} |
---|
55 | 78 | |
---|
56 | 79 | static int __init ima_template_setup(char *str) |
---|
57 | 80 | { |
---|
.. | .. |
---|
112 | 135 | } |
---|
113 | 136 | __setup("ima_template_fmt=", ima_template_fmt_setup); |
---|
114 | 137 | |
---|
115 | | -static struct ima_template_desc *lookup_template_desc(const char *name) |
---|
| 138 | +struct ima_template_desc *lookup_template_desc(const char *name) |
---|
116 | 139 | { |
---|
117 | 140 | struct ima_template_desc *template_desc; |
---|
118 | 141 | int found = 0; |
---|
.. | .. |
---|
129 | 152 | return found ? template_desc : NULL; |
---|
130 | 153 | } |
---|
131 | 154 | |
---|
132 | | -static struct ima_template_field *lookup_template_field(const char *field_id) |
---|
| 155 | +static const struct ima_template_field * |
---|
| 156 | +lookup_template_field(const char *field_id) |
---|
133 | 157 | { |
---|
134 | 158 | int i; |
---|
135 | 159 | |
---|
.. | .. |
---|
156 | 180 | return j + 1; |
---|
157 | 181 | } |
---|
158 | 182 | |
---|
159 | | -static int template_desc_init_fields(const char *template_fmt, |
---|
160 | | - struct ima_template_field ***fields, |
---|
161 | | - int *num_fields) |
---|
| 183 | +int template_desc_init_fields(const char *template_fmt, |
---|
| 184 | + const struct ima_template_field ***fields, |
---|
| 185 | + int *num_fields) |
---|
162 | 186 | { |
---|
163 | 187 | const char *template_fmt_ptr; |
---|
164 | | - struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; |
---|
| 188 | + const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; |
---|
165 | 189 | int template_num_fields; |
---|
166 | 190 | int i, len; |
---|
167 | 191 | |
---|
.. | .. |
---|
196 | 220 | } |
---|
197 | 221 | |
---|
198 | 222 | if (fields && num_fields) { |
---|
199 | | - *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); |
---|
| 223 | + *fields = kmalloc_array(i, sizeof(**fields), GFP_KERNEL); |
---|
200 | 224 | if (*fields == NULL) |
---|
201 | 225 | return -ENOMEM; |
---|
202 | 226 | |
---|
203 | | - memcpy(*fields, found_fields, i * sizeof(*fields)); |
---|
| 227 | + memcpy(*fields, found_fields, i * sizeof(**fields)); |
---|
204 | 228 | *num_fields = i; |
---|
205 | 229 | } |
---|
206 | 230 | |
---|
.. | .. |
---|
266 | 290 | |
---|
267 | 291 | template_desc->name = ""; |
---|
268 | 292 | template_desc->fmt = kstrdup(template_name, GFP_KERNEL); |
---|
269 | | - if (!template_desc->fmt) |
---|
| 293 | + if (!template_desc->fmt) { |
---|
| 294 | + kfree(template_desc); |
---|
| 295 | + template_desc = NULL; |
---|
270 | 296 | goto out; |
---|
| 297 | + } |
---|
271 | 298 | |
---|
272 | 299 | spin_lock(&template_list); |
---|
273 | 300 | list_add_tail_rcu(&template_desc->list, &defined_templates); |
---|
.. | .. |
---|
281 | 308 | int template_data_size, |
---|
282 | 309 | struct ima_template_entry **entry) |
---|
283 | 310 | { |
---|
| 311 | + struct tpm_digest *digests; |
---|
284 | 312 | int ret = 0; |
---|
285 | 313 | int i; |
---|
286 | 314 | |
---|
287 | | - *entry = kzalloc(sizeof(**entry) + |
---|
288 | | - template_desc->num_fields * sizeof(struct ima_field_data), |
---|
289 | | - GFP_NOFS); |
---|
| 315 | + *entry = kzalloc(struct_size(*entry, template_data, |
---|
| 316 | + template_desc->num_fields), GFP_NOFS); |
---|
290 | 317 | if (!*entry) |
---|
291 | 318 | return -ENOMEM; |
---|
| 319 | + |
---|
| 320 | + digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, |
---|
| 321 | + sizeof(*digests), GFP_NOFS); |
---|
| 322 | + if (!digests) { |
---|
| 323 | + kfree(*entry); |
---|
| 324 | + return -ENOMEM; |
---|
| 325 | + } |
---|
| 326 | + |
---|
| 327 | + (*entry)->digests = digests; |
---|
292 | 328 | |
---|
293 | 329 | ret = ima_parse_buf(template_data, template_data + template_data_size, |
---|
294 | 330 | NULL, template_desc->num_fields, |
---|
295 | 331 | (*entry)->template_data, NULL, NULL, |
---|
296 | 332 | ENFORCE_FIELDS | ENFORCE_BUFEND, "template data"); |
---|
297 | 333 | if (ret < 0) { |
---|
| 334 | + kfree((*entry)->digests); |
---|
298 | 335 | kfree(*entry); |
---|
299 | 336 | return ret; |
---|
300 | 337 | } |
---|
.. | .. |
---|
327 | 364 | int ima_restore_measurement_list(loff_t size, void *buf) |
---|
328 | 365 | { |
---|
329 | 366 | char template_name[MAX_TEMPLATE_NAME_LEN]; |
---|
| 367 | + unsigned char zero[TPM_DIGEST_SIZE] = { 0 }; |
---|
330 | 368 | |
---|
331 | 369 | struct ima_kexec_hdr *khdr = buf; |
---|
332 | 370 | struct ima_field_data hdr[HDR__LAST] = { |
---|
.. | .. |
---|
426 | 464 | if (ret < 0) |
---|
427 | 465 | break; |
---|
428 | 466 | |
---|
429 | | - memcpy(entry->digest, hdr[HDR_DIGEST].data, |
---|
430 | | - hdr[HDR_DIGEST].len); |
---|
431 | | - entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) : |
---|
432 | | - le32_to_cpu(*(hdr[HDR_PCR].data)); |
---|
| 467 | + if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) { |
---|
| 468 | + ret = ima_calc_field_array_hash( |
---|
| 469 | + &entry->template_data[0], |
---|
| 470 | + entry); |
---|
| 471 | + if (ret < 0) { |
---|
| 472 | + pr_err("cannot calculate template digest\n"); |
---|
| 473 | + ret = -EINVAL; |
---|
| 474 | + break; |
---|
| 475 | + } |
---|
| 476 | + } |
---|
| 477 | + |
---|
| 478 | + entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) : |
---|
| 479 | + le32_to_cpu(*(u32 *)(hdr[HDR_PCR].data)); |
---|
433 | 480 | ret = ima_restore_measurement_entry(entry); |
---|
434 | 481 | if (ret < 0) |
---|
435 | 482 | break; |
---|