18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005,2006,2007,2008 IBM Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Reiner Sailer <sailer@watson.ibm.com> 78c2ecf20Sopenharmony_ci * Leendert van Doorn <leendert@watson.ibm.com> 88c2ecf20Sopenharmony_ci * Mimi Zohar <zohar@us.ibm.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * File: ima_init.c 118c2ecf20Sopenharmony_ci * initialization and cleanup functions 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "ima.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* name for boot aggregate entry */ 228c2ecf20Sopenharmony_ciconst char boot_aggregate_name[] = "boot_aggregate"; 238c2ecf20Sopenharmony_cistruct tpm_chip *ima_tpm_chip; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Add the boot aggregate to the IMA measurement list and extend 268c2ecf20Sopenharmony_ci * the PCR register. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Calculate the boot aggregate, a hash over tpm registers 0-7, 298c2ecf20Sopenharmony_ci * assuming a TPM chip exists, and zeroes if the TPM chip does not 308c2ecf20Sopenharmony_ci * exist. Add the boot aggregate measurement to the measurement 318c2ecf20Sopenharmony_ci * list and extend the PCR register. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * If a tpm chip does not exist, indicate the core root of trust is 348c2ecf20Sopenharmony_ci * not hardware based by invalidating the aggregate PCR value. 358c2ecf20Sopenharmony_ci * (The aggregate PCR value is invalidated by adding one value to 368c2ecf20Sopenharmony_ci * the measurement list and extending the aggregate PCR value with 378c2ecf20Sopenharmony_ci * a different value.) Violations add a zero entry to the measurement 388c2ecf20Sopenharmony_ci * list and extend the aggregate PCR value with ff...ff's. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_cistatic int __init ima_add_boot_aggregate(void) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci static const char op[] = "add_boot_aggregate"; 438c2ecf20Sopenharmony_ci const char *audit_cause = "ENOMEM"; 448c2ecf20Sopenharmony_ci struct ima_template_entry *entry; 458c2ecf20Sopenharmony_ci struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; 468c2ecf20Sopenharmony_ci struct ima_event_data event_data = { .iint = iint, 478c2ecf20Sopenharmony_ci .filename = boot_aggregate_name }; 488c2ecf20Sopenharmony_ci int result = -ENOMEM; 498c2ecf20Sopenharmony_ci int violation = 0; 508c2ecf20Sopenharmony_ci struct { 518c2ecf20Sopenharmony_ci struct ima_digest_data hdr; 528c2ecf20Sopenharmony_ci char digest[TPM_MAX_DIGEST_SIZE]; 538c2ecf20Sopenharmony_ci } hash; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci memset(iint, 0, sizeof(*iint)); 568c2ecf20Sopenharmony_ci memset(&hash, 0, sizeof(hash)); 578c2ecf20Sopenharmony_ci iint->ima_hash = &hash.hdr; 588c2ecf20Sopenharmony_ci iint->ima_hash->algo = ima_hash_algo; 598c2ecf20Sopenharmony_ci iint->ima_hash->length = hash_digest_size[ima_hash_algo]; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * With TPM 2.0 hash agility, TPM chips could support multiple TPM 638c2ecf20Sopenharmony_ci * PCR banks, allowing firmware to configure and enable different 648c2ecf20Sopenharmony_ci * banks. The SHA1 bank is not necessarily enabled. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Use the same hash algorithm for reading the TPM PCRs as for 678c2ecf20Sopenharmony_ci * calculating the boot aggregate digest. Preference is given to 688c2ecf20Sopenharmony_ci * the configured IMA default hash algorithm. Otherwise, use the 698c2ecf20Sopenharmony_ci * TCG required banks - SHA256 for TPM 2.0, SHA1 for TPM 1.2. 708c2ecf20Sopenharmony_ci * Ultimately select SHA1 also for TPM 2.0 if the SHA256 PCR bank 718c2ecf20Sopenharmony_ci * is not found. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci if (ima_tpm_chip) { 748c2ecf20Sopenharmony_ci result = ima_calc_boot_aggregate(&hash.hdr); 758c2ecf20Sopenharmony_ci if (result < 0) { 768c2ecf20Sopenharmony_ci audit_cause = "hashing_error"; 778c2ecf20Sopenharmony_ci goto err_out; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci result = ima_alloc_init_template(&event_data, &entry, NULL); 828c2ecf20Sopenharmony_ci if (result < 0) { 838c2ecf20Sopenharmony_ci audit_cause = "alloc_entry"; 848c2ecf20Sopenharmony_ci goto err_out; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci result = ima_store_template(entry, violation, NULL, 888c2ecf20Sopenharmony_ci boot_aggregate_name, 898c2ecf20Sopenharmony_ci CONFIG_IMA_MEASURE_PCR_IDX); 908c2ecf20Sopenharmony_ci if (result < 0) { 918c2ecf20Sopenharmony_ci ima_free_template_entry(entry); 928c2ecf20Sopenharmony_ci audit_cause = "store_entry"; 938c2ecf20Sopenharmony_ci goto err_out; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_cierr_out: 978c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, 988c2ecf20Sopenharmony_ci audit_cause, result, 0); 998c2ecf20Sopenharmony_ci return result; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#ifdef CONFIG_IMA_LOAD_X509 1038c2ecf20Sopenharmony_civoid __init ima_load_x509(void) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int unset_flags = ima_policy_flag & IMA_APPRAISE; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ima_policy_flag &= ~unset_flags; 1088c2ecf20Sopenharmony_ci integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH); 1098c2ecf20Sopenharmony_ci ima_policy_flag |= unset_flags; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint __init ima_init(void) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int rc; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ima_tpm_chip = tpm_default_chip(); 1188c2ecf20Sopenharmony_ci if (!ima_tpm_chip) 1198c2ecf20Sopenharmony_ci pr_info("No TPM chip found, activating TPM-bypass!\n"); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA); 1228c2ecf20Sopenharmony_ci if (rc) 1238c2ecf20Sopenharmony_ci return rc; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci rc = ima_init_crypto(); 1268c2ecf20Sopenharmony_ci if (rc) 1278c2ecf20Sopenharmony_ci return rc; 1288c2ecf20Sopenharmony_ci rc = ima_init_template(); 1298c2ecf20Sopenharmony_ci if (rc != 0) 1308c2ecf20Sopenharmony_ci return rc; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* It can be called before ima_init_digests(), it does not use TPM. */ 1338c2ecf20Sopenharmony_ci ima_load_kexec_buffer(); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci rc = ima_init_digests(); 1368c2ecf20Sopenharmony_ci if (rc != 0) 1378c2ecf20Sopenharmony_ci return rc; 1388c2ecf20Sopenharmony_ci rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */ 1398c2ecf20Sopenharmony_ci if (rc != 0) 1408c2ecf20Sopenharmony_ci return rc; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ima_init_policy(); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci rc = ima_fs_init(); 1458c2ecf20Sopenharmony_ci if (rc != 0) 1468c2ecf20Sopenharmony_ci return rc; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ima_init_key_queue(); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return rc; 1518c2ecf20Sopenharmony_ci} 152