Received: by 2002:a05:6358:3188:b0:123:57c1:9b43 with SMTP id q8csp35194602rwd; Mon, 10 Jul 2023 04:08:46 -0700 (PDT) X-Google-Smtp-Source: APBJJlGYQ48g8SKe34AEPSu654fPqQ3mecCVuDGq6k6Rjt9fIW1haNF4Hz98dsgIWUz3IUFL03di X-Received: by 2002:aa7:da98:0:b0:51e:1c18:dd99 with SMTP id q24-20020aa7da98000000b0051e1c18dd99mr9903060eds.38.1688987325968; Mon, 10 Jul 2023 04:08:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1688987325; cv=none; d=google.com; s=arc-20160816; b=rfuwRaG7j8un6Kh2L23pbRNniUzYax55cGNhscA6xPnJj7tHhDRCPz1EBlVbkustth bR0PpcMaxOP+MWh2Iebzj12LvN9waW3b7J0NvUB5YknEumASnvE8S6O0dk/3XbnVDPqo qeIGLPL/NMb8i33vCKahxJ8UhDpu3nSPO5Wji8b2JQhdPttD84g6X0W7JkPISYBp/67j TKWwBTt7DNxLygdDMVoDrZ+rSYh8FdngHM3VS8IOUdtkY3EJvGO3OpJ8LgO8sLfWF5nq AErCv6LBjBLNTXNQaydoJTZUs32kqgupZjtpmV1gu6Obd8eachi0qAc6EJ1LJYU3O1Wp MmCg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:to:from; bh=y1pbsKvm4V1GYFOxXoalbQFLUeUEJU2wkgz1DCx/q+M=; fh=XmWF9XfVxriV9HvdKqMb6KHEGw2y762qN7GZzdFCqto=; b=ANnFZeqZBo7VSUP7J0WXl1YrxunGBHH745f55/MJh/Fy0PrJT89LsUhL+yU7i+5AYr eCabXjTHIJRWd5FT/PL6RviV97wtf/eQ7YHhKVK8NYyfJg9/dYZJqC4534PC0U7Iwo/X 9rRmR2hrKSyeGxLsimPn3/AYE9t0gr5WC6Syt26NzGnloIy15eMJSpnk9iuJQE6WZ1hK RdPz71pZWaK+b6xY1Fj4bafZSma4kOmCOtfXWDihnCoH7VexK6aX6MwqHDP6r3xOMLL5 k4xaVrEqwtZsP+meRWsBmGSm0e3EVayxSTGe29LhziY8B9vO1qJvEj57wkNiuyueWIzI cksQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id o16-20020a056402039000b0051dd2d6c09fsi4563041edv.424.2023.07.10.04.08.21; Mon, 10 Jul 2023 04:08:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231949AbjGJLDH (ORCPT + 99 others); Mon, 10 Jul 2023 07:03:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57008 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231654AbjGJLCx (ORCPT ); Mon, 10 Jul 2023 07:02:53 -0400 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id AEBE2D2; Mon, 10 Jul 2023 04:02:51 -0700 (PDT) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 36AANOHK019769; Mon, 10 Jul 2023 05:23:24 -0500 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 36AANOV9019767; Mon, 10 Jul 2023 05:23:24 -0500 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" 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 Message-Id: <20230710102319.19716-7-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230710102319.19716-1-greg@enjellic.com> References: <20230710102319.19716-1-greg@enjellic.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- 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 + * + * Implements management of a TPM trust root for the in kernel TMA. + */ + +#include + +#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