From patchwork Fri Jul 28 19:30:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 13332602 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3B81C001DE for ; Fri, 28 Jul 2023 19:31:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233869AbjG1TbE (ORCPT ); Fri, 28 Jul 2023 15:31:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48926 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233779AbjG1TbD (ORCPT ); Fri, 28 Jul 2023 15:31:03 -0400 Received: from mgamail.intel.com (unknown [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF1162D5D; Fri, 28 Jul 2023 12:30:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1690572659; x=1722108659; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mGaMlBipNmPfGhHLAGsqi0OkKPmtkBtlrURLdYIcgyI=; b=SsAtewQNkZTLC6BNFnMjtP+oG0dOXfVgcpMbt1f0Xiqe5PiyX9aKJx9C W8A0Vcm2OGT6/5tXZ+W2ZJZNkorBHulpWH21N/juniDomxpVx0G/hGVpA jTz0dvK6Y4imeUUqzJloENqW/GpDzfn4fkK2Nmj+3O8iaFGE1W4ACHlN1 ulP4bMcWpOc7HLO4tamX3gdhPNpuLYEWZG3KrduR5JqSnemvK1367dY+M Wx8SSgdpJjx8amlZIkdsLnitUAVxvTmYSKcVp8vWbkz+rMkuUwMZAoGiq UKtqXIqQPvITyanL29Kmtbou0VfvtgT+hx/LkLqWXSwdohvjomuFGaipC g==; X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="348958854" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="348958854" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:30:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="797529634" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="797529634" Received: from cheehong-laptop.gar.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.212.158.179]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:30:58 -0700 Subject: [PATCH 1/4] keys: Introduce tsm keys From: Dan Williams To: dhowells@redhat.com Cc: Kuppuswamy Sathyanarayanan , Kuppuswamy Sathyanarayanan , Jarkko Sakkinen , Dionna Amalie Glaze , Greg Kroah-Hartman , Samuel Ortiz , peterz@infradead.org, linux-coco@lists.linux.dev, keyrings@vger.kernel.org, x86@kernel.org, linux-kernel@vger.kernel.org Date: Fri, 28 Jul 2023 12:30:58 -0700 Message-ID: <169057265801.180586.10867293237672839356.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> References: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: keyrings@vger.kernel.org One of the common operations of a TSM (Trusted Security Module) is to provide a way for a TVM (confidential computing guest execution environment) to take a measurement of its run state and use that with a key-exchange protocol to establish a shared secret with a third-party / remote attestation agent. The concept is common across TSMs, but the implementations are unfortunately vendor specific. While the industry grapples with a common definition of this attestation format [1], Linux need not make this problem worse by defining a new ABI per TSM that wants to perform a similar operation. The current momentum has been to invent new ioctl-ABI per TSM per function which at best is an abdication of the kernel's responsibility to make common infrastructure concepts share common ABI. The proposal, targeted to conceptually work with TDX, SEV, COVE if not more, is to define a new key type that produces a TSM common blob format and moves the vendor specificity inside that envelope. The common Linux definition is: " " This approach later allows for the standardization of the attestation blob format without needing to change the Linux ABI. TSM specific options are encoded in the frontend request format where the options like SEV:vmpl (privilege level) can be specified and TSMs that do not support them can decide to ignore them or fail if they are specified. For now, "privlevel=" and "format=" are the only implemented options. Example of establishing a tsm key and dumping the provider-specific report: dd if=/dev/urandom of=pubkey bs=1 count=64 keyctl add tsm tsm_test "auth $(xxd -p -c 0 < pubkey) privlevel=2" @u keyctl print 280877394 | awk '{ print $3 }' | xxd -p -c 0 -r | hexdump -C Now, this patch ends up being a fairly simple custom-key format because most of the follow-on work that happens after publishing a TSM-wrapped public-key is performed by userspace. The TSM key is just one step in establishing a shared secret that can be used to unlock other keys. For example a user-key could be populated with the resulting shared secret and that could be used as a master-key for an encrypted-key (security/keys/encrypted-keys/encrypted.c). While the discussion that led to this proposal hinted at a new trusted-key (security/keys/trusted-keys/trusted_core.c) type rooted in the TSM [2], more work is needed to fetch a secret from the TSM directly. The trusted-key core expects a pre-established secure channel to seal and unseal secrets locally. For that reason a "tsm" flavor trusted-key is saved for follow on work. That will likely starting as a wrapper around SNP_GET_DERIVED_KEY. Link: http://lore.kernel.org/r/64961c3baf8ce_142af829436@dwillia2-xfh.jf.intel.com.notmuch [1] Link: http://lore.kernel.org/r/CAAH4kHYLETfPk-sMD-QSJd0fJ7Qnt04FBwFuEkpnehB5U7D_yw@mail.gmail.com [2] Cc: Kuppuswamy Sathyanarayanan Tested-by: Kuppuswamy Sathyanarayanan Cc: David Howells Cc: Jarkko Sakkinen Cc: Dionna Amalie Glaze Cc: Greg Kroah-Hartman Cc: Samuel Ortiz Signed-off-by: Dan Williams --- include/keys/tsm.h | 71 ++++++++++++ security/keys/Kconfig | 12 ++ security/keys/Makefile | 1 security/keys/tsm.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 366 insertions(+) create mode 100644 include/keys/tsm.h create mode 100644 security/keys/tsm.c diff --git a/include/keys/tsm.h b/include/keys/tsm.h new file mode 100644 index 000000000000..61a81017d8f5 --- /dev/null +++ b/include/keys/tsm.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __TSM_H +#define __TSM_H + +#include +#include + +/* + * @TSM_DATA_MAX: a reasonable max with enough space for known attestation + * report formats. This mirrors the trusted/encrypted key blob max size. + */ +#define TSM_DATA_MAX 32767 +#define TSM_PUBKEY_MAX 64 +#define TSM_FORMAT_MAX 16 + +/** + * DOC: TSM Keys + * + * Trusted Security Module Keys are a common provider of blobs that + * facilitate key-exchange between a TVM (confidential computing guest) + * and an attestation service. A TSM key combines a user-defined blob + * (likely a public-key for a key-exchance protocol) with a signed + * attestation report. That combined blob is then used to obtain + * secrets provided by an agent that can validate the attestation + * report. + * + * A full implementation uses a tsm key to, for example, establish a + * shared secret and then use that communication channel to instantiate + * other keys. The expectation is that the requester of the tsm key + * knows a priori the key-exchange protocol associated with the + * 'pubkey'. + * + * The attestation report format is TSM provider specific, when / if a + * standard materializes it is only a change to the auth_blob_desc + * member of 'struct tsm_key_payload', to convey that common format. + */ + +/** + * struct tsm_key_payload - generic payload for vendor TSM blobs + * @privlevel: optional privilege level to associate with @pubkey + * @pubkey_len: how much of @pubkey is valid + * @pubkey: the public key-exchange blob to include in the attestation report + * @auth_blob_desc: base ascii descriptor of @auth_blob + * @auth_blob_format: for TSMs with multiple formats, extend @auth_blob_desc + * @auth_blob_len: TSM provider length of the array it publishes in @auth_blob + * @auth_blob: TSM specific attestation report blob + */ +struct tsm_key_payload { + int privlevel; + size_t pubkey_len; + u8 pubkey[TSM_PUBKEY_MAX]; + const char *auth_blob_desc; + char auth_blob_format[TSM_FORMAT_MAX]; + size_t auth_blob_len; + u8 *auth_blob; +}; + +/* + * arch specific ops, only one is expected to be registered at a time + * i.e. only one of SEV, TDX, COVE, etc. + */ +struct tsm_key_ops { + const char *name; + struct module *module; + int (*auth_new)(struct tsm_key_payload *t, void *provider_data); +}; + +int register_tsm_provider(const struct tsm_key_ops *ops, void *provider_data); +void unregister_tsm_provider(const struct tsm_key_ops *ops); + +#endif /* __TSM_H */ diff --git a/security/keys/Kconfig b/security/keys/Kconfig index abb03a1b2a5c..f530cbd876fc 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -133,3 +133,15 @@ config KEY_NOTIFICATIONS on keys and keyrings on which the caller has View permission. This makes use of pipes to handle the notification buffer and provides KEYCTL_WATCH_KEY to enable/disable watches. + +config TSM_KEYS + tristate "TSM-based (Confidential Computing) keys" + help + TSM (Trusted Security Module) key support arranges to convey a blob to + a confidentiality and integrity protected virtual machine / guest + (TVM). The blob instantiation flow involves submitting the measurement + report of a TVM, obtained from the platform TSM, to a remote + attestation service that only provides the key if the report passes + validation. The report format is vendor specific and the validation is + user policy, so this feature requires a /etc/request-key.conf handler + for communicating with the remote attestation provider. diff --git a/security/keys/Makefile b/security/keys/Makefile index 5f40807f05b3..96972a4815d5 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += keyctl_pkey.o # Key types # obj-$(CONFIG_BIG_KEYS) += big_key.o +obj-$(CONFIG_TSM_KEYS) += tsm.o obj-$(CONFIG_TRUSTED_KEYS) += trusted-keys/ obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ diff --git a/security/keys/tsm.c b/security/keys/tsm.c new file mode 100644 index 000000000000..d9532319f819 --- /dev/null +++ b/security/keys/tsm.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct tsm_provider { + const struct tsm_key_ops *ops; + void *data; +} provider; +static DECLARE_RWSEM(tsm_key_rwsem); + +static const struct tsm_key_ops *get_ops(void) +{ + down_read(&tsm_key_rwsem); + return provider.ops; +} + +static void *get_data(void) +{ + lockdep_assert_held(&tsm_key_rwsem); + return provider.data; +} + +static void put_ops(void) +{ + up_read(&tsm_key_rwsem); +} + +int register_tsm_provider(const struct tsm_key_ops *ops, + void *provider_data) +{ + const struct tsm_key_ops *conflict; + int rc; + + down_write(&tsm_key_rwsem); + conflict = provider.ops; + if (conflict) { + pr_err("\"%s\" ops already registered\n", conflict->name); + rc = -EEXIST; + goto out; + } + try_module_get(ops->module); + provider.ops = ops; + provider.data = provider_data; + rc = 0; +out: + up_write(&tsm_key_rwsem); + return rc; +} +EXPORT_SYMBOL_GPL(register_tsm_provider); + +void unregister_tsm_provider(const struct tsm_key_ops *ops) +{ + down_write(&tsm_key_rwsem); + provider.ops = NULL; + provider.data = NULL; + module_put(ops->module); + up_write(&tsm_key_rwsem); +} +EXPORT_SYMBOL_GPL(unregister_tsm_provider); + +enum { + Opt_err, + Opt_auth, + Opt_format, + Opt_privlevel, +}; + +static const match_table_t tsm_tokens = { + { Opt_auth, "auth" }, + { Opt_privlevel, "privlevel=%s" }, + { Opt_format, "format=%s" }, + { Opt_err, NULL }, +}; + +/* + * tsm_parse - parse the tsm request data + * + * input format: "auth [options]" + * + * Checks for options and parses a hex blob of data to be wrapped by the + * TSM attestation format. + * + * options: + * privlevel= integer for selecting the privelege level of the + * request, if the platform TSM supports that concept. To + * date only SEV accepts this option. Default 0. + * format= string modifier for the format, if the platform TSM + * supports multiple formats. To date only SEV accepts an + * "extended" argument. Default "". + * + * On success returns 0, otherwise -EINVAL. + */ +static int tsm_parse(char *input, struct tsm_key_payload *t) +{ + substring_t args[MAX_OPT_ARGS]; + unsigned long optmask = 0; + unsigned int privlevel; + int token, rc; + char *p; + + /* all tsm keys must start with "auth" as a placeholder command */ + p = strsep(&input, " \t"); + if (!p) + return -EINVAL; + token = match_token(p, tsm_tokens, args); + switch (token) { + case Opt_auth: + break; + default: + return -EINVAL; + } + + /* next is the pubkey hex blob */ + p = strsep(&input, " \t"); + if (!p) + return -EINVAL; + t->pubkey_len = strlen(p) / 2; + if (t->pubkey_len > TSM_PUBKEY_MAX) + return -EINVAL; + rc = hex2bin(t->pubkey, p, t->pubkey_len); + if (rc < 0) + return -EINVAL; + + /* last is zero or more options */ + while ((p = strsep(&input, " \t"))) { + if (*p == '\0' || *p == ' ' || *p == '\t') + continue; + token = match_token(p, tsm_tokens, args); + /* each option can appear only once */ + if (test_and_set_bit(token, &optmask)) + return -EINVAL; + switch (token) { + case Opt_privlevel: + rc = kstrtouint(args[0].from, 16, &privlevel); + if (rc) + return rc; + t->privlevel = privlevel; + break; + case Opt_format: + if (strlen(args[0].from) >= TSM_FORMAT_MAX) + return -EINVAL; + strscpy(t->auth_blob_format, args[0].from, + TSM_FORMAT_MAX); + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int tsm_instantiate(struct key *key, struct key_preparsed_payload *prep) +{ + size_t datalen = prep->datalen; + const struct tsm_key_ops *ops; + int rc; + + if (datalen <= 0 || datalen > TSM_DATA_MAX || !prep->data) + return -EINVAL; + + char *datablob __free(kfree) = + kmemdup_nul(prep->data, datalen, GFP_KERNEL); + if (!datablob) + return -ENOMEM; + + struct tsm_key_payload *t __free(kfree) = + kzalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return -ENOMEM; + + rc = tsm_parse(datablob, t); + if (rc < 0) + return rc; + + ops = get_ops(); + if (ops) + rc = ops->auth_new(t, get_data()); + else + rc = -ENXIO; + put_ops(); + + if (rc) + return rc; + + rc = key_payload_reserve(key, sizeof(*t) + t->auth_blob_len); + if (rc) { + kvfree(t->auth_blob); + return rc; + } + + rcu_assign_keypointer(key, t); + no_free_ptr(t); + return 0; +} + +/* + * tsm_read - format and copy out the tsm auth record + * + * The resulting datablob format is: + * + * + * On success, return to userspace the size of the formatted payload. + */ +static long tsm_read(const struct key *key, char *buffer, size_t buflen) +{ + size_t asciiblob_len, desc_len; + struct tsm_key_payload *t; + char *buf, *format = NULL; + const int nr_spaces = 2; + + t = dereference_key_locked(key); + + desc_len = strlen(t->auth_blob_desc); + if (t->auth_blob_format[0]) { + format = &t->auth_blob_format[0]; + desc_len += strlen(format) + 1; + } + + asciiblob_len = + t->pubkey_len * 2 + desc_len + t->auth_blob_len * 2 + nr_spaces; + + if (!buffer || buflen < asciiblob_len) + return asciiblob_len; + + buf = bin2hex(buffer, t->pubkey, t->pubkey_len); + if (format) + buf += sprintf(buf, " %s:%s ", t->auth_blob_desc, format); + else + buf += sprintf(buf, " %s ", t->auth_blob_desc); + buf = bin2hex(buf, t->auth_blob, t->auth_blob_len); + + /* sanity check for future changes to this function */ + WARN_ON_ONCE(buf - buffer != asciiblob_len); + + return asciiblob_len; +} + +static void tsm_destroy(struct key *key) +{ + struct tsm_key_payload *t = key->payload.data[0]; + + kvfree(t->auth_blob); + kfree(t); +} + +static struct key_type key_type_tsm = { + .name = "tsm", + .instantiate = tsm_instantiate, + .destroy = tsm_destroy, + .describe = user_describe, + .read = tsm_read, +}; + +static int __init tsm_key_init(void) +{ + return register_key_type(&key_type_tsm); +} +module_init(tsm_key_init); + +static void __exit tsm_key_exit(void) +{ + unregister_key_type(&key_type_tsm); +} +module_exit(tsm_key_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Provide Trusted Security Module attestation reports as Key payloads"); From patchwork Fri Jul 28 19:31:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 13332603 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B527C001DE for ; Fri, 28 Jul 2023 19:31:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234153AbjG1TbL (ORCPT ); Fri, 28 Jul 2023 15:31:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48982 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233837AbjG1TbG (ORCPT ); Fri, 28 Jul 2023 15:31:06 -0400 Received: from mgamail.intel.com (unknown [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4B24A2736; Fri, 28 Jul 2023 12:31:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1690572665; x=1722108665; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZKEMKTZcxb+bR5sevS5HirhkX4iYwm8FNvR5plo9bz8=; b=Y/nsKeO2ccCHbcJ5ElgM+6O1+yydrPdT11Stfs/TB3eFFmoEGEaYmW0s w2DNC8dz+P59286ou+eDVY1nBEQPX3fnN1mVj/covmOy+DGOYd9/XT3/d b/8YMm4ORNZoArlUepOipsrO8RsPYrtEmzKGTF01tM2hwvkRrh7alr7N/ cvUKHe6WWR532Q9Qsnv11Ef2WvgfgNg6U6ptoVJpaKBDeTmGQWaBbcwJC 8YNhaQ2G0cGC0B2MTyfgZ3xSoLpY8fxJXAEXqlNuevs8gdmtAGQB0yBE2 TT87PouhfY8Z/nBULQ5ZuVkzZP3b+p2UwzuSdsLdftr4YYjkQSnjxPGZu w==; X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="348958868" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="348958868" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:31:05 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="797529706" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="797529706" Received: from cheehong-laptop.gar.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.212.158.179]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:31:04 -0700 Subject: [PATCH 2/4] virt: sevguest: Prep for kernel internal {get, get_ext}_report() From: Dan Williams To: dhowells@redhat.com Cc: Borislav Petkov , Tom Lendacky , Dionna Glaze , Brijesh Singh , peterz@infradead.org, linux-coco@lists.linux.dev, keyrings@vger.kernel.org, x86@kernel.org, linux-kernel@vger.kernel.org Date: Fri, 28 Jul 2023 12:31:04 -0700 Message-ID: <169057266405.180586.11333199807740052979.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> References: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: keyrings@vger.kernel.org In preparation for using the TSM key facility to convey attestation blobs to userspace, add an argument to flag whether @arg is a user buffer or a kernel buffer. While TSM keys is meant to replace existing confidenital computing ioctl() implementations for attestation report retrieval the old ioctl() path needs to stick around for a deprecation period. No behavior change intended, just introduce the copy wrappers and @type argument. Note that these wrappers are similar to copy_{to,from}_sockptr(). If this approach moves forward that concept is something that can be generalized into a helper with a generic name. Cc: Borislav Petkov Cc: Tom Lendacky Cc: Dionna Glaze Cc: Brijesh Singh Signed-off-by: Dan Williams --- drivers/virt/coco/sev-guest/sev-guest.c | 48 ++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c index 97dbe715e96a..f48c4764a7a2 100644 --- a/drivers/virt/coco/sev-guest/sev-guest.c +++ b/drivers/virt/coco/sev-guest/sev-guest.c @@ -470,7 +470,32 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, return 0; } -static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg) +enum snp_arg_type { + SNP_UARG, + SNP_KARG, +}; + +static unsigned long copy_from(void *to, unsigned long from, unsigned long n, + enum snp_arg_type type) +{ + if (type == SNP_UARG) + return copy_from_user(to, (void __user *)from, n); + memcpy(to, (void *)from, n); + return 0; +} + +static unsigned long copy_to(unsigned long to, const void *from, + unsigned long n, enum snp_arg_type type) +{ + if (type == SNP_UARG) + return copy_to_user((void __user *)to, from, n); + memcpy((void *)to, from, n); + return 0; +} + +static int get_report(struct snp_guest_dev *snp_dev, + struct snp_guest_request_ioctl *arg, + enum snp_arg_type type) { struct snp_guest_crypto *crypto = snp_dev->crypto; struct snp_report_resp *resp; @@ -482,7 +507,7 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io if (!arg->req_data || !arg->resp_data) return -EINVAL; - if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) + if (copy_from(&req, arg->req_data, sizeof(req), type)) return -EFAULT; /* @@ -501,7 +526,7 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io if (rc) goto e_free; - if (copy_to_user((void __user *)arg->resp_data, resp, sizeof(*resp))) + if (copy_to(arg->resp_data, resp, sizeof(*resp), type)) rc = -EFAULT; e_free: @@ -550,7 +575,9 @@ static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_reque return rc; } -static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg) +static int get_ext_report(struct snp_guest_dev *snp_dev, + struct snp_guest_request_ioctl *arg, + enum snp_arg_type type) { struct snp_guest_crypto *crypto = snp_dev->crypto; struct snp_ext_report_req req; @@ -562,7 +589,7 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques if (!arg->req_data || !arg->resp_data) return -EINVAL; - if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) + if (copy_from(&req, arg->req_data, sizeof(req), type)) return -EFAULT; /* userspace does not want certificate data */ @@ -611,14 +638,13 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques if (ret) goto e_free; - if (npages && - copy_to_user((void __user *)req.certs_address, snp_dev->certs_data, - req.certs_len)) { + if (npages && copy_to(req.certs_address, snp_dev->certs_data, + req.certs_len, type)) { ret = -EFAULT; goto e_free; } - if (copy_to_user((void __user *)arg->resp_data, resp, sizeof(*resp))) + if (copy_to(arg->resp_data, resp, sizeof(*resp), type)) ret = -EFAULT; e_free: @@ -653,13 +679,13 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long switch (ioctl) { case SNP_GET_REPORT: - ret = get_report(snp_dev, &input); + ret = get_report(snp_dev, &input, SNP_UARG); break; case SNP_GET_DERIVED_KEY: ret = get_derived_key(snp_dev, &input); break; case SNP_GET_EXT_REPORT: - ret = get_ext_report(snp_dev, &input); + ret = get_ext_report(snp_dev, &input, SNP_UARG); break; default: break; From patchwork Fri Jul 28 19:31:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 13332604 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 053A8C001DF for ; Fri, 28 Jul 2023 19:31:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234249AbjG1Tb0 (ORCPT ); Fri, 28 Jul 2023 15:31:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49032 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234226AbjG1TbN (ORCPT ); Fri, 28 Jul 2023 15:31:13 -0400 Received: from mgamail.intel.com (unknown [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 268DD448C; Fri, 28 Jul 2023 12:31:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1690572671; x=1722108671; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RReoo07Z8COfyQe4vCo2LnNBVJrUhMSozbnkyWWcdFM=; b=YLsLnojcakGLqg6bJDCDLohIWqBqDNKU3DTWmrn5tn34wxmzwf27l7DJ kvC7+8F7SauzrgETPrCrBlY3YZj9sUm+hzSk3XJIWVXC7TO0e0KuLJQsW yOlbCWGYg3dM52o2PZUyqBTA2VxC5xrn+GatRjvVawyvzXyU44xyYt86K aa3OMN4njjqizTxI3SyNy8ecdR8vfLZpXUQiireVJodYZEVb6h/roQ+nf elhWg7PmUIygWhUjaAzqdiO7F6Rc3j1rdW2RdsOwgVWkpLZZsC0eg7vHc L6+L+SLHEGyswRYz4HFE4puclomP7Zt58yovAizrgTYfUZNRKr4+E5K9u w==; X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="348958883" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="348958883" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:31:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="797529731" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="797529731" Received: from cheehong-laptop.gar.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.212.158.179]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:31:10 -0700 Subject: [PATCH 3/4] mm/slab: Add __free() support for kvfree From: Dan Williams To: dhowells@redhat.com Cc: Andrew Morton , Peter Zijlstra , Greg Kroah-Hartman , linux-coco@lists.linux.dev, keyrings@vger.kernel.org, x86@kernel.org, linux-kernel@vger.kernel.org Date: Fri, 28 Jul 2023 12:31:10 -0700 Message-ID: <169057267001.180586.1162740444367661440.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> References: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: keyrings@vger.kernel.org Allow for the declaration of variables that trigger kvfree() when they go out of scope. Cc: Andrew Morton Cc: Peter Zijlstra Cc: Greg Kroah-Hartman Signed-off-by: Dan Williams --- include/linux/slab.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/slab.h b/include/linux/slab.h index 848c7c82ad5a..241025367943 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -746,6 +746,8 @@ static inline __alloc_size(1, 2) void *kvcalloc(size_t n, size_t size, gfp_t fla extern void *kvrealloc(const void *p, size_t oldsize, size_t newsize, gfp_t flags) __realloc_size(3); extern void kvfree(const void *addr); +DEFINE_FREE(kvfree, void *, if (_T) kvfree(_T)) + extern void kvfree_sensitive(const void *addr, size_t len); unsigned int kmem_cache_size(struct kmem_cache *s); From patchwork Fri Jul 28 19:31:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 13332605 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EBC72C001DE for ; Fri, 28 Jul 2023 19:31:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233739AbjG1Tbt (ORCPT ); Fri, 28 Jul 2023 15:31:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48996 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234254AbjG1Tbo (ORCPT ); Fri, 28 Jul 2023 15:31:44 -0400 Received: from mgamail.intel.com (unknown [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9A163268B; Fri, 28 Jul 2023 12:31:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1690572689; x=1722108689; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZmjmGLkvlIjh8KgnWd4vxpMs4lTuf4Wk7sbNKNMFp8U=; b=WTPuKzK5XobA6Sm+c1I2DA0Ff/Ssu2SMO+MSAgrAosreBiIJ6r6l6qn+ NWNYzIy8vylJU3LyQ2l3+rFunizuyWAXJDKE4JtEiNE0qQVkk7As0MZKY ETE3/+voU1ujHKhkCkTVuH+MPTpohdGM7m7G60n9Fx3xKy4MhirpO4v1N R91S96ijr9eUh8Yg/shnGiH5N4M7C3OfFFzEsOd6P3yqwZ3mRN45T4OVK /2WgxrXo93HQGZmm6M1Nx3usIUzHy9tBFFLSRCS6UrZwykg5A9JKMLw4t YOdm/YBUplC1oKzJjZkVHbbossCrDwVSF4x6dfcSBKCkUVMgFUDK4EX0f A==; X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="348958904" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="348958904" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:31:16 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10785"; a="797529767" X-IronPort-AV: E=Sophos;i="6.01,238,1684825200"; d="scan'208";a="797529767" Received: from cheehong-laptop.gar.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.212.158.179]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jul 2023 12:31:16 -0700 Subject: [PATCH 4/4] virt: sevguest: Add TSM key support for SNP_{GET, GET_EXT}_REPORT From: Dan Williams To: dhowells@redhat.com Cc: Borislav Petkov , Tom Lendacky , Dionna Glaze , Brijesh Singh , peterz@infradead.org, linux-coco@lists.linux.dev, keyrings@vger.kernel.org, x86@kernel.org, linux-kernel@vger.kernel.org Date: Fri, 28 Jul 2023 12:31:15 -0700 Message-ID: <169057267580.180586.15710177655506555147.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> References: <169057265210.180586.7950140104251236598.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: keyrings@vger.kernel.org The sevguest driver was a first mover in the confidential computing space. As a first mover that afforded some leeway to build the driver without concern for common infrastructure. Now that sevguest is no longer a singleton [1] the common operation of building and transmitting attestation report blobs can / should be made common. In this model the so called "TSM-provider" implementations can share a common envelope ABI even if the contents of that envelope remain vendor-specific. When / if the industry agrees on an attestation record format, that definition can also fit in the same ABI. In the meantime the kernel's maintenance burden is reduced and collaboration on the commons is increased. Convert sevguest to use TSM keys to retrieve the blobs that the SNP_{GET,GET_EXT}_REPORT ioctls produce. The flow for retrieving the SNP_GET_REPORT blob via the keyctl utility would be: dd if=/dev/urandom of=pubkey bs=1 count=64 keyctl add tsm tsm_test "auth $(xxd -p -c 0 < pubkey) privlevel=2" @u keyctl print $key_id | awk '{ print $3 }' | xxd -p -c 0 -r | hexdump -C ...while the SNP_GET_EXT_REPORT flow adds the "format=extended" option to the request flow: keyctl add tsm tsm_test "auth $(xxd -p -c 0 < pubkey) privlevel=2 format=extended" @u The output format from 'keyctl print' is: ...where the blobs are hex encoded and the descriptor string is either "sev" or "sev:extended" in this case. Note, the Keys subsystem frontend for the functionality that SNP_GET_DERIVED_KEY represents is saved for follow-on work that likely needs to become a new trusted-keys type. The old ioctls can be lazily deprecated, the main motivation of this effort is to stop the proliferation of new ioctls, and to increase cross-vendor colloboration. Note, only compile-tested. Link: http://lore.kernel.org/r/64961c3baf8ce_142af829436@dwillia2-xfh.jf.intel.com.notmuch [1] Cc: Borislav Petkov Cc: Tom Lendacky Cc: Dionna Glaze Cc: Brijesh Singh Signed-off-by: Dan Williams --- drivers/virt/coco/sev-guest/Kconfig | 2 + drivers/virt/coco/sev-guest/sev-guest.c | 87 +++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/drivers/virt/coco/sev-guest/Kconfig b/drivers/virt/coco/sev-guest/Kconfig index da2d7ca531f0..bce43d4639ce 100644 --- a/drivers/virt/coco/sev-guest/Kconfig +++ b/drivers/virt/coco/sev-guest/Kconfig @@ -2,9 +2,11 @@ config SEV_GUEST tristate "AMD SEV Guest driver" default m depends on AMD_MEM_ENCRYPT + depends on KEYS select CRYPTO select CRYPTO_AEAD2 select CRYPTO_GCM + select TSM_KEYS help SEV-SNP firmware provides the guest a mechanism to communicate with the PSP without risk from a malicious hypervisor who wishes to read, diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c index f48c4764a7a2..2bdca268272d 100644 --- a/drivers/virt/coco/sev-guest/sev-guest.c +++ b/drivers/virt/coco/sev-guest/sev-guest.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -769,6 +770,84 @@ static u8 *get_vmpck(int id, struct snp_secrets_page_layout *layout, u32 **seqno return key; } +static int sev_auth_new(struct tsm_key_payload *t, void *provider_data) +{ + struct snp_guest_dev *snp_dev = provider_data; + const int report_size = SZ_16K; + const int ext_size = + PAGE_ALIGN_DOWN(TSM_DATA_MAX - report_size - sizeof(*t)); + int ret; + + if (t->pubkey_len != 64) + return -EINVAL; + + if (t->auth_blob_format[0] && + strcmp(t->auth_blob_format, "extended") != 0) + return -EINVAL; + + if (t->auth_blob_format[0]) { + u8 *buf __free(kvfree) = + kvzalloc(report_size + ext_size, GFP_KERNEL); + + struct snp_ext_report_req req = { + .data = { .vmpl = t->privlevel }, + .certs_address = (__u64)buf + report_size, + .certs_len = ext_size, + }; + memcpy(&req.data.user_data, t->pubkey, 64); + + struct snp_guest_request_ioctl input = { + .msg_version = 1, + .req_data = (__u64) &req, + .resp_data = (__u64) buf, + }; + + ret = get_ext_report(snp_dev, &input, SNP_KARG); + if (ret) + return ret; + + no_free_ptr(buf); + t->auth_blob = buf; + t->auth_blob_len = report_size + ext_size; + t->auth_blob_desc = "sev"; + } else { + u8 *buf __free(kvfree) = kvzalloc(report_size, GFP_KERNEL); + + struct snp_report_req req = { + .vmpl = t->privlevel, + }; + memcpy(&req.user_data, t->pubkey, 64); + + struct snp_guest_request_ioctl input = { + .msg_version = 1, + .req_data = (__u64) &req, + .resp_data = (__u64) buf, + }; + + ret = get_report(snp_dev, &input, SNP_KARG); + if (ret) + return ret; + + no_free_ptr(buf); + t->auth_blob = buf; + t->auth_blob_len = report_size; + t->auth_blob_desc = "sev"; + } + + return 0; +} + +static const struct tsm_key_ops sev_tsm_ops = { + .name = KBUILD_MODNAME, + .module = THIS_MODULE, + .auth_new = sev_auth_new, +}; + +static void unregister_sev_tsm(void *data) +{ + unregister_tsm_provider(&sev_tsm_ops); +} + static int __init sev_guest_probe(struct platform_device *pdev) { struct snp_secrets_page_layout *layout; @@ -842,6 +921,14 @@ static int __init sev_guest_probe(struct platform_device *pdev) snp_dev->input.resp_gpa = __pa(snp_dev->response); snp_dev->input.data_gpa = __pa(snp_dev->certs_data); + ret = register_tsm_provider(&sev_tsm_ops, snp_dev); + if (ret) + goto e_free_cert_data; + + ret = devm_add_action_or_reset(&pdev->dev, unregister_sev_tsm, NULL); + if (ret) + goto e_free_cert_data; + ret = misc_register(misc); if (ret) goto e_free_cert_data;