public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Dr. Greg" <greg@enjellic.com>
To: linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org, corbet@lwn.net
Subject: [PATCH 06/13] Add root domain trust implementation.
Date: Mon, 10 Jul 2023 05:23:12 -0500	[thread overview]
Message-ID: <20230710102319.19716-7-greg@enjellic.com> (raw)
In-Reply-To: <20230710102319.19716-1-greg@enjellic.com>

The trust.c contains the support infrastructure for anchoring the
root modeling domain in a hardware TPM implementation if it is
available.

The security state coefficients are extended, by default, into
Platform Configuration Register (PCR) 11 in order to provide
authentication of the security execution trajectory for the root
domain.  This value was chosen to avoid the use of PCR register
10 that the Integrity Measurement Architecture uses to register
the integrity events that it handles.

This PCR value can be changed through the kernel configuration
process.

This file is also responsible for computing the hardware platform
aggregate measurement.  This is the linear extension sum over PCR
rsegisters 0 through 7.  This file contains an accessor function
for surfacing this value to either the internal or external
Trusted Modeling Agent implementations.

The platform hardware aggregate value is designed to be the first
security state coefficient injected into a model.

Updates to the TPM are through an ordered asynchronous workqueue.
This is needed in order to support the modeling of security event
hooks that are called while a process is in atomic context.

This is also a performance optimization given that TPM
transactions are not highly performant, particularly on discrete
TPM implementations.  Extension of values to PCR's have
historically been done on a relatively infrequent basis, such as
when a file is accessed.  The high rate of security event
processing that can occur in the root modeling namespace
significantly benefits from this optimization.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/trust.c | 220 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 220 insertions(+)
 create mode 100644 security/tsem/trust.c

diff --git a/security/tsem/trust.c b/security/tsem/trust.c
new file mode 100644
index 000000000000..85f7542cf76f
--- /dev/null
+++ b/security/tsem/trust.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * Implements management of a TPM trust root for the in kernel TMA.
+ */
+
+#include <linux/tpm.h>
+
+#include "tsem.h"
+
+static struct workqueue_struct *tpm_update_wq;
+
+static u8 zero_aggregate[HASH_MAX_DIGESTSIZE];
+
+static struct tpm_chip *tpm;
+
+static struct tpm_digest *digests;
+
+struct hardware_aggregate {
+	struct list_head list;
+	char *name;
+	u8 value[HASH_MAX_DIGESTSIZE];
+};
+
+DEFINE_MUTEX(hardware_aggregate_mutex);
+LIST_HEAD(hardware_aggregate_list);
+
+static struct hardware_aggregate *find_aggregate(void)
+{
+	struct hardware_aggregate *aggregate;
+
+	list_for_each_entry(aggregate, &hardware_aggregate_list, list) {
+		if (!strcmp(aggregate->name,
+			    tsem_context(current)->digestname))
+			goto done;
+	}
+	aggregate = NULL;
+
+ done:
+	return aggregate;
+}
+
+static struct hardware_aggregate *add_aggregate(u8 *new_aggregate)
+{
+	struct hardware_aggregate *aggregate;
+
+	aggregate = kzalloc(sizeof(*aggregate), GFP_KERNEL);
+	if (!aggregate)
+		return NULL;
+
+	aggregate->name = kstrdup(tsem_context(current)->digestname,
+				  GFP_KERNEL);
+	if (!aggregate->name) {
+		kfree(aggregate);
+		return NULL;
+	}
+	memcpy(aggregate->value, new_aggregate, tsem_digestsize());
+
+	list_add(&aggregate->list, &hardware_aggregate_list);
+
+	return aggregate;
+}
+
+/**
+ * tsem_trust_aggregate() - Return a pointer to the hardware aggregate.
+ *
+ * This function returns a pointer to the hardware aggregate encoded
+ * with the hash function for the current modeling domain.
+ *
+ * Return: A pointer is returned to the hardware aggregate value that
+ *	   has been cached.
+ */
+u8 *tsem_trust_aggregate(void)
+{
+	u8 aggregate[HASH_MAX_DIGESTSIZE], *retn = zero_aggregate;
+	u16 size;
+	unsigned int lp;
+	struct tpm_digest pcr;
+	struct hardware_aggregate *hw_aggregate;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	if (!tpm)
+		return retn;
+
+	mutex_lock(&hardware_aggregate_mutex);
+
+	hw_aggregate = find_aggregate();
+	if (hw_aggregate) {
+		retn = hw_aggregate->value;
+		goto done;
+	}
+
+	shash->tfm = tsem_digest();
+	if (crypto_shash_init(shash))
+		goto done;
+
+	if (tpm_is_tpm2(tpm))
+		pcr.alg_id = TPM_ALG_SHA256;
+	else
+		pcr.alg_id = TPM_ALG_SHA1;
+	memset(pcr.digest, '\0', TPM_MAX_DIGEST_SIZE);
+
+	for (lp = 0; lp < tpm->nr_allocated_banks; lp++) {
+		if (pcr.alg_id == tpm->allocated_banks[lp].alg_id) {
+			size = tpm->allocated_banks[lp].digest_size;
+			break;
+		}
+	}
+
+	for (lp = 0; lp < 8; ++lp) {
+		if (tpm_pcr_read(tpm, lp, &pcr))
+			goto done;
+		if (crypto_shash_update(shash, pcr.digest, size))
+			goto done;
+	}
+	if (!crypto_shash_final(shash, aggregate)) {
+		hw_aggregate = add_aggregate(aggregate);
+		if (hw_aggregate)
+			retn = hw_aggregate->value;
+	}
+
+ done:
+	mutex_unlock(&hardware_aggregate_mutex);
+
+	if (retn == zero_aggregate)
+		pr_warn("tsem: Error generating platform aggregate\n");
+
+	return retn;
+}
+
+static void tpm_update_worker(struct work_struct *work)
+{
+	int amt, bank, digestsize;
+	struct tsem_event *ep;
+
+	ep = container_of(work, struct tsem_event, work);
+	digestsize = ep->digestsize;
+
+	for (bank = 0; bank < tpm->nr_allocated_banks; bank++) {
+		if (tpm->allocated_banks[bank].digest_size > digestsize) {
+			amt = digestsize;
+			memset(digests[bank].digest, '\0',
+			       tpm->allocated_banks[bank].digest_size);
+		} else
+			amt = tpm->allocated_banks[bank].digest_size;
+		memcpy(digests[bank].digest, ep->mapping, amt);
+	}
+
+	if (tpm_pcr_extend(tpm, CONFIG_SECURITY_TSEM_ROOT_MODEL_PCR,
+			   digests))
+		pr_warn("tsem: Failed TPM update.\n");
+
+	tsem_event_put(ep);
+}
+
+/**
+ * tsem_trust_add_point() - Add a measurement to the trust root.
+ * @ep: A pointer to the security event description whose measurement
+ *	is to be extended into the TPM.
+ *
+ * This function extends the platform configuration register being
+ * used to document the hardware root of trust for internally modeled
+ * domains with a security event coefficient value.
+ *
+ * Return: If the extension fails the error return value from the
+ *	   TPM command is returned, otherwise a value of zero is
+ *	   returned.
+ */
+int tsem_trust_add_event(struct tsem_event *ep)
+{
+	bool retn;
+
+	if (!tpm)
+		return 0;
+
+	tsem_event_get(ep);
+	ep->digestsize = tsem_digestsize();
+
+	INIT_WORK(&ep->work, tpm_update_worker);
+	retn = queue_work(tpm_update_wq, &ep->work);
+
+	return 0;
+}
+
+static int __init trust_init(void)
+{
+	int retn = -EINVAL, lp;
+
+	tpm = tpm_default_chip();
+	if (!tpm)
+		return retn;
+
+	tpm_update_wq = alloc_ordered_workqueue("tsem_tpm", 0);
+	if (IS_ERR(tpm_update_wq)) {
+		retn = PTR_ERR(tpm_update_wq);
+		goto done;
+	}
+
+	digests = kcalloc(tpm->nr_allocated_banks, sizeof(*digests), GFP_NOFS);
+	if (!digests) {
+		tpm = NULL;
+		return retn;
+	}
+	for (lp = 0; lp < tpm->nr_allocated_banks; lp++)
+		digests[lp].alg_id = tpm->allocated_banks[lp].alg_id;
+	retn = 0;
+
+ done:
+	if (retn) {
+		destroy_workqueue(tpm_update_wq);
+		kfree(digests);
+	}
+
+	return retn;
+}
+
+device_initcall_sync(trust_init);
-- 
2.39.1


  parent reply	other threads:[~2023-07-10 11:03 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
2023-07-10 10:23 ` [PATCH 01/13] Update MAINTAINERS file Dr. Greg
2023-07-10 20:00   ` Randy Dunlap
2023-07-15 22:45     ` Dr. Greg
2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
2023-07-11  4:37   ` Randy Dunlap
2023-07-17  0:36     ` Dr. Greg
2023-07-17  1:56       ` Randy Dunlap
2023-08-08 18:48   ` Serge Hallyn
2023-08-11 20:22     ` Dr. Greg
2024-01-04 15:54       ` Paul Moore
2024-01-05  3:54         ` Dr. Greg
2024-01-04  4:00   ` [PATCH 2/13] " Paul Moore
2024-01-05  2:55     ` Dr. Greg
2024-01-08 11:43     ` Dr. Greg
2024-02-05 16:09       ` Paul Moore
2024-02-19 11:16         ` Dr. Greg
2023-07-10 10:23 ` [PATCH 03/13] Implement CAP_TRUST capability Dr. Greg
2023-08-07 20:21   ` Casey Schaufler
2023-08-15 10:19     ` Dr. Greg
2023-08-15 17:15       ` Casey Schaufler
2023-07-10 10:23 ` [PATCH 04/13] Add TSEM master header file Dr. Greg
2023-08-07 20:39   ` Casey Schaufler
2023-08-10  2:57     ` Dr. Greg
2023-08-10 15:03       ` Casey Schaufler
2023-07-10 10:23 ` [PATCH 05/13] Add primary TSEM implementation file Dr. Greg
2023-08-07 21:00   ` Casey Schaufler
2023-08-11  7:21     ` Dr. Greg
2023-07-10 10:23 ` Dr. Greg [this message]
2023-07-10 10:23 ` [PATCH 07/13] Implement TSEM control plane Dr. Greg
2023-07-10 10:23 ` [PATCH 08/13] Add namespace implementation Dr. Greg
2023-07-10 10:23 ` [PATCH 09/13] Add security event description export facility Dr. Greg
2023-07-10 10:23 ` [PATCH 10/13] Add event description implementation Dr. Greg
2023-07-10 10:23 ` [PATCH 11/13] Implement security event mapping Dr. Greg
2023-07-10 10:23 ` [PATCH 12/13] Implement an internal Trusted Modeling Agent Dr. Greg
2023-07-10 10:23 ` [PATCH 13/13] Activate the configuration and build of the TSEM LSM Dr. Greg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230710102319.19716-7-greg@enjellic.com \
    --to=greg@enjellic.com \
    --cc=corbet@lwn.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox