| .. | .. |
|---|
| 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 | |
|---|
| .. | .. |
|---|
| 281 | 305 | int template_data_size, |
|---|
| 282 | 306 | struct ima_template_entry **entry) |
|---|
| 283 | 307 | { |
|---|
| 308 | + struct tpm_digest *digests; |
|---|
| 284 | 309 | int ret = 0; |
|---|
| 285 | 310 | int i; |
|---|
| 286 | 311 | |
|---|
| 287 | | - *entry = kzalloc(sizeof(**entry) + |
|---|
| 288 | | - template_desc->num_fields * sizeof(struct ima_field_data), |
|---|
| 289 | | - GFP_NOFS); |
|---|
| 312 | + *entry = kzalloc(struct_size(*entry, template_data, |
|---|
| 313 | + template_desc->num_fields), GFP_NOFS); |
|---|
| 290 | 314 | if (!*entry) |
|---|
| 291 | 315 | return -ENOMEM; |
|---|
| 316 | + |
|---|
| 317 | + digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, |
|---|
| 318 | + sizeof(*digests), GFP_NOFS); |
|---|
| 319 | + if (!digests) { |
|---|
| 320 | + kfree(*entry); |
|---|
| 321 | + return -ENOMEM; |
|---|
| 322 | + } |
|---|
| 323 | + |
|---|
| 324 | + (*entry)->digests = digests; |
|---|
| 292 | 325 | |
|---|
| 293 | 326 | ret = ima_parse_buf(template_data, template_data + template_data_size, |
|---|
| 294 | 327 | NULL, template_desc->num_fields, |
|---|
| 295 | 328 | (*entry)->template_data, NULL, NULL, |
|---|
| 296 | 329 | ENFORCE_FIELDS | ENFORCE_BUFEND, "template data"); |
|---|
| 297 | 330 | if (ret < 0) { |
|---|
| 331 | + kfree((*entry)->digests); |
|---|
| 298 | 332 | kfree(*entry); |
|---|
| 299 | 333 | return ret; |
|---|
| 300 | 334 | } |
|---|
| .. | .. |
|---|
| 327 | 361 | int ima_restore_measurement_list(loff_t size, void *buf) |
|---|
| 328 | 362 | { |
|---|
| 329 | 363 | char template_name[MAX_TEMPLATE_NAME_LEN]; |
|---|
| 364 | + unsigned char zero[TPM_DIGEST_SIZE] = { 0 }; |
|---|
| 330 | 365 | |
|---|
| 331 | 366 | struct ima_kexec_hdr *khdr = buf; |
|---|
| 332 | 367 | struct ima_field_data hdr[HDR__LAST] = { |
|---|
| .. | .. |
|---|
| 426 | 461 | if (ret < 0) |
|---|
| 427 | 462 | break; |
|---|
| 428 | 463 | |
|---|
| 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)); |
|---|
| 464 | + if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) { |
|---|
| 465 | + ret = ima_calc_field_array_hash( |
|---|
| 466 | + &entry->template_data[0], |
|---|
| 467 | + entry); |
|---|
| 468 | + if (ret < 0) { |
|---|
| 469 | + pr_err("cannot calculate template digest\n"); |
|---|
| 470 | + ret = -EINVAL; |
|---|
| 471 | + break; |
|---|
| 472 | + } |
|---|
| 473 | + } |
|---|
| 474 | + |
|---|
| 475 | + entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) : |
|---|
| 476 | + le32_to_cpu(*(u32 *)(hdr[HDR_PCR].data)); |
|---|
| 433 | 477 | ret = ima_restore_measurement_entry(entry); |
|---|
| 434 | 478 | if (ret < 0) |
|---|
| 435 | 479 | break; |
|---|