| 1 | |
| 2 | |
| 3 | * Copyright (C) 2013 Politecnico di Torino, Italy
|
| 4 | * TORSEC group -- https://security.polito.it
|
| 5 | *
|
| 6 | * Author: Roberto Sassu <[email protected]>
|
| 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 header_fields { 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 = ""},
|
| 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(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(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)
|
| 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(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_objs(**fields, i);
|
| 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(&defined_templates))
|
| 264 | return;
|
| 265 |
|
| 266 | spin_lock(&template_list);
|
| 267 | for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) {
|
| 268 | list_add_tail_rcu(&builtin_templates[i].list,
|
| 269 | &defined_templates);
|
| 270 | }
|
| 271 | spin_unlock(&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("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,
|
| 299 | &(template->fields),
|
| 300 | &(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,
|
| 315 | &(template->fields),
|
| 316 | &(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_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_obj(*template_desc);
|
| 338 | if (!template_desc)
|
| 339 | goto out;
|
| 340 |
|
| 341 | template_desc->name = "";
|
| 342 | template_desc->fmt = kstrdup(template_name, GFP_KERNEL);
|
| 343 | if (!template_desc->fmt) {
|
| 344 | kfree(template_desc);
|
| 345 | template_desc = NULL;
|
| 346 | goto out;
|
| 347 | }
|
| 348 |
|
| 349 | spin_lock(&template_list);
|
| 350 | list_add_tail_rcu(&template_desc->list, &defined_templates);
|
| 351 | spin_unlock(&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_flex(**entry, template_data, template_desc->num_fields,
|
| 366 | GFP_NOFS);
|
| 367 | if (!*entry)
|
| 368 | return -ENOMEM;
|
| 369 |
|
| 370 | digests = kzalloc_objs(*digests,
|
| 371 | NR_BANKS(ima_tpm_chip) + ima_extra_slots,
|
| 372 | GFP_NOFS);
|
| 373 | if (!digests) {
|
| 374 | kfree(*entry);
|
| 375 | return -ENOMEM;
|
| 376 | }
|
| 377 |
|
| 378 | (*entry)->digests = digests;
|
| 379 |
|
| 380 | ret = ima_parse_buf(template_data, template_data + template_data_size,
|
| 381 | NULL, template_desc->num_fields,
|
| 382 | (*entry)->template_data, NULL, NULL,
|
| 383 | ENFORCE_FIELDS | ENFORCE_BUFEND, "template data");
|
| 384 | if (ret < 0) {
|
| 385 | kfree((*entry)->digests);
|
| 386 | kfree(*entry);
|
| 387 | return ret;
|
| 388 | }
|
| 389 |
|
| 390 | (*entry)->template_desc = template_desc;
|
| 391 | for (i = 0; i < template_desc->num_fields; i++) {
|
| 392 | struct ima_field_data *field_data = &(*entry)->template_data[i];
|
| 393 | u8 *data = field_data->data;
|
| 394 |
|
| 395 | (*entry)->template_data[i].data =
|
| 396 | kzalloc(field_data->len + 1, GFP_KERNEL);
|
| 397 | if (!(*entry)->template_data[i].data) {
|
| 398 | ret = -ENOMEM;
|
| 399 | break;
|
| 400 | }
|
| 401 | memcpy((*entry)->template_data[i].data, data, field_data->len);
|
| 402 | (*entry)->template_data_len += sizeof(field_data->len);
|
| 403 | (*entry)->template_data_len += field_data->len;
|
| 404 | }
|
| 405 |
|
| 406 | if (ret < 0) {
|
| 407 | ima_free_template_entry(*entry);
|
| 408 | *entry = NULL;
|
| 409 | }
|
| 410 |
|
| 411 | return ret;
|
| 412 | }
|
| 413 |
|
| 414 |
|
| 415 | int ima_restore_measurement_list(loff_t size, void *buf)
|
| 416 | {
|
| 417 | char template_name[MAX_TEMPLATE_NAME_LEN];
|
| 418 | unsigned char zero[TPM_DIGEST_SIZE] = { 0 };
|
| 419 |
|
| 420 | struct ima_kexec_hdr *khdr = buf;
|
| 421 | struct ima_field_data hdr[HDR__LAST] = {
|
| 422 | [HDR_PCR] = {.len = sizeof(u32)},
|
| 423 | [HDR_DIGEST] = {.len = TPM_DIGEST_SIZE},
|
| 424 | };
|
| 425 |
|
| 426 | void *bufp = buf + sizeof(*khdr);
|
| 427 | void *bufendp;
|
| 428 | struct ima_template_entry *entry;
|
| 429 | struct ima_template_desc *template_desc;
|
| 430 | DECLARE_BITMAP(hdr_mask, HDR__LAST);
|
| 431 | unsigned long count = 0;
|
| 432 | int ret = 0;
|
| 433 |
|
| 434 | if (!buf || size < sizeof(*khdr))
|
| 435 | return 0;
|
| 436 |
|
| 437 | if (ima_canonical_fmt) {
|
| 438 | khdr->version = le16_to_cpu((__force __le16)khdr->version);
|
| 439 | khdr->count = le64_to_cpu((__force __le64)khdr->count);
|
| 440 | khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size);
|
| 441 | }
|
| 442 |
|
| 443 | if (khdr->version != 1) {
|
| 444 | pr_err("attempting to restore a incompatible measurement list");
|
| 445 | return -EINVAL;
|
| 446 | }
|
| 447 |
|
| 448 | if (khdr->count > ULONG_MAX - 1) {
|
| 449 | pr_err("attempting to restore too many measurements");
|
| 450 | return -EINVAL;
|
| 451 | }
|
| 452 |
|
| 453 | bitmap_zero(hdr_mask, HDR__LAST);
|
| 454 | bitmap_set(hdr_mask, HDR_PCR, 1);
|
| 455 | bitmap_set(hdr_mask, HDR_DIGEST, 1);
|
| 456 |
|
| 457 | |
| 458 | * ima kexec buffer prefix: version, buffer size, count
|
| 459 | * v1 format: pcr, digest, template-name-len, template-name,
|
| 460 | * template-data-size, template-data
|
| 461 |
|
| 462 | bufendp = buf + khdr->buffer_size;
|
| 463 | while ((bufp < bufendp) && (count++ < khdr->count)) {
|
| 464 | int enforce_mask = ENFORCE_FIELDS;
|
| 465 |
|
| 466 | enforce_mask |= (count == khdr->count) ? ENFORCE_BUFEND : 0;
|
| 467 | ret = ima_parse_buf(bufp, bufendp, &bufp, HDR__LAST, hdr, NULL,
|
| 468 | hdr_mask, enforce_mask, "entry header");
|
| 469 | if (ret < 0)
|
| 470 | break;
|
| 471 |
|
| 472 | if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) {
|
| 473 | pr_err("attempting to restore a template name that is too long\n");
|
| 474 | ret = -EINVAL;
|
| 475 | break;
|
| 476 | }
|
| 477 |
|
| 478 |
|
| 479 | memcpy(template_name, hdr[HDR_TEMPLATE_NAME].data,
|
| 480 | hdr[HDR_TEMPLATE_NAME].len);
|
| 481 | template_name[hdr[HDR_TEMPLATE_NAME].len] = 0;
|
| 482 |
|
| 483 | if (strcmp(template_name, "ima") == 0) {
|
| 484 | pr_err("attempting to restore an unsupported template \"%s\" failed\n",
|
| 485 | template_name);
|
| 486 | ret = -EINVAL;
|
| 487 | break;
|
| 488 | }
|
| 489 |
|
| 490 | template_desc = lookup_template_desc(template_name);
|
| 491 | if (!template_desc) {
|
| 492 | template_desc = restore_template_fmt(template_name);
|
| 493 | if (!template_desc)
|
| 494 | break;
|
| 495 | }
|
| 496 |
|
| 497 | |
| 498 | * Only the running system's template format is initialized
|
| 499 | * on boot. As needed, initialize the other template formats.
|
| 500 |
|
| 501 | ret = template_desc_init_fields(template_desc->fmt,
|
| 502 | &(template_desc->fields),
|
| 503 | &(template_desc->num_fields));
|
| 504 | if (ret < 0) {
|
| 505 | pr_err("attempting to restore the template fmt \"%s\" failed\n",
|
| 506 | template_desc->fmt);
|
| 507 | ret = -EINVAL;
|
| 508 | break;
|
| 509 | }
|
| 510 |
|
| 511 | ret = ima_restore_template_data(template_desc,
|
| 512 | hdr[HDR_TEMPLATE_DATA].data,
|
| 513 | hdr[HDR_TEMPLATE_DATA].len,
|
| 514 | &entry);
|
| 515 | if (ret < 0)
|
| 516 | break;
|
| 517 |
|
| 518 | if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {
|
| 519 | ret = ima_calc_field_array_hash(
|
| 520 | &entry->template_data[0],
|
| 521 | entry);
|
| 522 | if (ret < 0) {
|
| 523 | pr_err("cannot calculate template digest\n");
|
| 524 | ret = -EINVAL;
|
| 525 | break;
|
| 526 | }
|
| 527 | }
|
| 528 |
|
| 529 | entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :
|
| 530 | le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data));
|
| 531 | ret = ima_restore_measurement_entry(entry);
|
| 532 | if (ret < 0)
|
| 533 | break;
|
| 534 |
|
| 535 | }
|
| 536 | return ret;
|
| 537 | }
|