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