From: Nikunj A Dadhania <nikunj@amd.com>
To: <linux-kernel@vger.kernel.org>, <thomas.lendacky@amd.com>,
<bp@alien8.de>, <x86@kernel.org>, <kvm@vger.kernel.org>
Cc: <mingo@redhat.com>, <tglx@linutronix.de>,
<dave.hansen@linux.intel.com>, <pgonda@google.com>,
<seanjc@google.com>, <pbonzini@redhat.com>, <nikunj@amd.com>
Subject: [PATCH v11 05/20] virt: sev-guest: Use AES GCM crypto library
Date: Wed, 31 Jul 2024 20:37:56 +0530 [thread overview]
Message-ID: <20240731150811.156771-6-nikunj@amd.com> (raw)
In-Reply-To: <20240731150811.156771-1-nikunj@amd.com>
The sev-guest driver encryption code uses the crypto API for SNP guest
messaging with the AMD Security processor. In order to enable secure TSC,
SEV-SNP guests need to send such a TSC_INFO message before the APs are
booted. Details from the TSC_INFO response will then be used to program the
VMSA before the APs are brought up.
However, the crypto API is not available this early in the boot process.
In preparation for moving the encryption code out of sev-guest to support
secure TSC and to ease review, switch to using the AES GCM library
implementation instead.
Drop __enc_payload() and dec_payload() helpers as both are small and can be
moved to the respective callers.
CC: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Tested-by: Peter Gonda <pgonda@google.com>
Acked-by: Borislav Petkov (AMD) <bp@alien8.de>
---
arch/x86/include/asm/sev.h | 3 +
drivers/virt/coco/sev-guest/sev-guest.c | 175 ++++++------------------
drivers/virt/coco/sev-guest/Kconfig | 4 +-
3 files changed, 43 insertions(+), 139 deletions(-)
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index ee34ab00a8d6..e7977f76d77e 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -120,6 +120,9 @@ struct snp_req_data {
};
#define MAX_AUTHTAG_LEN 32
+#define AUTHTAG_LEN 16
+#define AAD_LEN 48
+#define MSG_HDR_VER 1
/* See SNP spec SNP_GUEST_REQUEST section for the structure */
enum msg_type {
diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c
index 0b950069bfcb..39d90dd0b012 100644
--- a/drivers/virt/coco/sev-guest/sev-guest.c
+++ b/drivers/virt/coco/sev-guest/sev-guest.c
@@ -17,8 +17,7 @@
#include <linux/set_memory.h>
#include <linux/fs.h>
#include <linux/tsm.h>
-#include <crypto/aead.h>
-#include <linux/scatterlist.h>
+#include <crypto/gcm.h>
#include <linux/psp-sev.h>
#include <linux/sockptr.h>
#include <linux/cleanup.h>
@@ -31,26 +30,18 @@
#include <asm/sev.h>
#define DEVICE_NAME "sev-guest"
-#define AAD_LEN 48
-#define MSG_HDR_VER 1
#define SNP_REQ_MAX_RETRY_DURATION (60*HZ)
#define SNP_REQ_RETRY_DELAY (2*HZ)
#define SVSM_MAX_RETRIES 3
-struct snp_guest_crypto {
- struct crypto_aead *tfm;
- u8 *iv, *authtag;
- int iv_len, a_len;
-};
-
struct snp_guest_dev {
struct device *dev;
struct miscdevice misc;
void *certs_data;
- struct snp_guest_crypto *crypto;
+ struct aesgcm_ctx *ctx;
/* request and response are in unencrypted memory */
struct snp_guest_msg *request, *response;
@@ -169,132 +160,31 @@ static inline struct snp_guest_dev *to_snp_dev(struct file *file)
return container_of(dev, struct snp_guest_dev, misc);
}
-static struct snp_guest_crypto *init_crypto(struct snp_guest_dev *snp_dev, u8 *key, size_t keylen)
+static struct aesgcm_ctx *snp_init_crypto(u8 *key, size_t keylen)
{
- struct snp_guest_crypto *crypto;
+ struct aesgcm_ctx *ctx;
- crypto = kzalloc(sizeof(*crypto), GFP_KERNEL_ACCOUNT);
- if (!crypto)
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
+ if (!ctx)
return NULL;
- crypto->tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
- if (IS_ERR(crypto->tfm))
- goto e_free;
-
- if (crypto_aead_setkey(crypto->tfm, key, keylen))
- goto e_free_crypto;
-
- crypto->iv_len = crypto_aead_ivsize(crypto->tfm);
- crypto->iv = kmalloc(crypto->iv_len, GFP_KERNEL_ACCOUNT);
- if (!crypto->iv)
- goto e_free_crypto;
-
- if (crypto_aead_authsize(crypto->tfm) > MAX_AUTHTAG_LEN) {
- if (crypto_aead_setauthsize(crypto->tfm, MAX_AUTHTAG_LEN)) {
- dev_err(snp_dev->dev, "failed to set authsize to %d\n", MAX_AUTHTAG_LEN);
- goto e_free_iv;
- }
+ if (aesgcm_expandkey(ctx, key, keylen, AUTHTAG_LEN)) {
+ pr_err("Crypto context initialization failed\n");
+ kfree(ctx);
+ return NULL;
}
- crypto->a_len = crypto_aead_authsize(crypto->tfm);
- crypto->authtag = kmalloc(crypto->a_len, GFP_KERNEL_ACCOUNT);
- if (!crypto->authtag)
- goto e_free_iv;
-
- return crypto;
-
-e_free_iv:
- kfree(crypto->iv);
-e_free_crypto:
- crypto_free_aead(crypto->tfm);
-e_free:
- kfree(crypto);
-
- return NULL;
-}
-
-static void deinit_crypto(struct snp_guest_crypto *crypto)
-{
- crypto_free_aead(crypto->tfm);
- kfree(crypto->iv);
- kfree(crypto->authtag);
- kfree(crypto);
-}
-
-static int enc_dec_message(struct snp_guest_crypto *crypto, struct snp_guest_msg *msg,
- u8 *src_buf, u8 *dst_buf, size_t len, bool enc)
-{
- struct snp_guest_msg_hdr *hdr = &msg->hdr;
- struct scatterlist src[3], dst[3];
- DECLARE_CRYPTO_WAIT(wait);
- struct aead_request *req;
- int ret;
-
- req = aead_request_alloc(crypto->tfm, GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
- /*
- * AEAD memory operations:
- * +------ AAD -------+------- DATA -----+---- AUTHTAG----+
- * | msg header | plaintext | hdr->authtag |
- * | bytes 30h - 5Fh | or | |
- * | | cipher | |
- * +------------------+------------------+----------------+
- */
- sg_init_table(src, 3);
- sg_set_buf(&src[0], &hdr->algo, AAD_LEN);
- sg_set_buf(&src[1], src_buf, hdr->msg_sz);
- sg_set_buf(&src[2], hdr->authtag, crypto->a_len);
-
- sg_init_table(dst, 3);
- sg_set_buf(&dst[0], &hdr->algo, AAD_LEN);
- sg_set_buf(&dst[1], dst_buf, hdr->msg_sz);
- sg_set_buf(&dst[2], hdr->authtag, crypto->a_len);
-
- aead_request_set_ad(req, AAD_LEN);
- aead_request_set_tfm(req, crypto->tfm);
- aead_request_set_callback(req, 0, crypto_req_done, &wait);
-
- aead_request_set_crypt(req, src, dst, len, crypto->iv);
- ret = crypto_wait_req(enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req), &wait);
-
- aead_request_free(req);
- return ret;
-}
-
-static int __enc_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg,
- void *plaintext, size_t len)
-{
- struct snp_guest_crypto *crypto = snp_dev->crypto;
- struct snp_guest_msg_hdr *hdr = &msg->hdr;
-
- memset(crypto->iv, 0, crypto->iv_len);
- memcpy(crypto->iv, &hdr->msg_seqno, sizeof(hdr->msg_seqno));
-
- return enc_dec_message(crypto, msg, plaintext, msg->payload, len, true);
-}
-
-static int dec_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg,
- void *plaintext, size_t len)
-{
- struct snp_guest_crypto *crypto = snp_dev->crypto;
- struct snp_guest_msg_hdr *hdr = &msg->hdr;
-
- /* Build IV with response buffer sequence number */
- memset(crypto->iv, 0, crypto->iv_len);
- memcpy(crypto->iv, &hdr->msg_seqno, sizeof(hdr->msg_seqno));
-
- return enc_dec_message(crypto, msg, msg->payload, plaintext, len, false);
+ return ctx;
}
static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, u32 sz)
{
- struct snp_guest_crypto *crypto = snp_dev->crypto;
struct snp_guest_msg *resp_msg = &snp_dev->secret_response;
struct snp_guest_msg *req_msg = &snp_dev->secret_request;
struct snp_guest_msg_hdr *req_msg_hdr = &req_msg->hdr;
struct snp_guest_msg_hdr *resp_msg_hdr = &resp_msg->hdr;
+ struct aesgcm_ctx *ctx = snp_dev->ctx;
+ u8 iv[GCM_AES_IV_SIZE] = {};
pr_debug("response [seqno %lld type %d version %d sz %d]\n",
resp_msg_hdr->msg_seqno, resp_msg_hdr->msg_type, resp_msg_hdr->msg_version,
@@ -316,11 +206,16 @@ static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload,
* If the message size is greater than our buffer length then return
* an error.
*/
- if (unlikely((resp_msg_hdr->msg_sz + crypto->a_len) > sz))
+ if (unlikely((resp_msg_hdr->msg_sz + ctx->authsize) > sz))
return -EBADMSG;
/* Decrypt the payload */
- return dec_payload(snp_dev, resp_msg, payload, resp_msg_hdr->msg_sz + crypto->a_len);
+ memcpy(iv, &resp_msg_hdr->msg_seqno, min(sizeof(iv), sizeof(resp_msg_hdr->msg_seqno)));
+ if (!aesgcm_decrypt(ctx, payload, resp_msg->payload, resp_msg_hdr->msg_sz,
+ &resp_msg_hdr->algo, AAD_LEN, iv, resp_msg_hdr->authtag))
+ return -EBADMSG;
+
+ return 0;
}
static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 type,
@@ -328,6 +223,8 @@ static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8
{
struct snp_guest_msg *msg = &snp_dev->secret_request;
struct snp_guest_msg_hdr *hdr = &msg->hdr;
+ struct aesgcm_ctx *ctx = snp_dev->ctx;
+ u8 iv[GCM_AES_IV_SIZE] = {};
memset(msg, 0, sizeof(*msg));
@@ -347,7 +244,14 @@ static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8
pr_debug("request [seqno %lld type %d version %d sz %d]\n",
hdr->msg_seqno, hdr->msg_type, hdr->msg_version, hdr->msg_sz);
- return __enc_payload(snp_dev, msg, payload, sz);
+ if (WARN_ON((sz + ctx->authsize) > sizeof(msg->payload)))
+ return -EBADMSG;
+
+ memcpy(iv, &hdr->msg_seqno, min(sizeof(iv), sizeof(hdr->msg_seqno)));
+ aesgcm_encrypt(ctx, msg->payload, payload, sz, &hdr->algo, AAD_LEN,
+ iv, hdr->authtag);
+
+ return 0;
}
static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code,
@@ -495,7 +399,6 @@ struct snp_req_resp {
static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
{
- struct snp_guest_crypto *crypto = snp_dev->crypto;
struct snp_report_req *report_req = &snp_dev->req.report;
struct snp_report_resp *report_resp;
int rc, resp_len;
@@ -513,7 +416,7 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io
* response payload. Make sure that it has enough space to cover the
* authtag.
*/
- resp_len = sizeof(report_resp->data) + crypto->a_len;
+ resp_len = sizeof(report_resp->data) + snp_dev->ctx->authsize;
report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
if (!report_resp)
return -ENOMEM;
@@ -534,7 +437,6 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io
static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
{
struct snp_derived_key_req *derived_key_req = &snp_dev->req.derived_key;
- struct snp_guest_crypto *crypto = snp_dev->crypto;
struct snp_derived_key_resp derived_key_resp = {0};
int rc, resp_len;
/* Response data is 64 bytes and max authsize for GCM is 16 bytes. */
@@ -550,7 +452,7 @@ static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_reque
* response payload. Make sure that it has enough space to cover the
* authtag.
*/
- resp_len = sizeof(derived_key_resp.data) + crypto->a_len;
+ resp_len = sizeof(derived_key_resp.data) + snp_dev->ctx->authsize;
if (sizeof(buf) < resp_len)
return -ENOMEM;
@@ -579,7 +481,6 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
{
struct snp_ext_report_req *report_req = &snp_dev->req.ext_report;
- struct snp_guest_crypto *crypto = snp_dev->crypto;
struct snp_report_resp *report_resp;
int ret, npages = 0, resp_len;
sockptr_t certs_address;
@@ -622,7 +523,7 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
* response payload. Make sure that it has enough space to cover the
* authtag.
*/
- resp_len = sizeof(report_resp->data) + crypto->a_len;
+ resp_len = sizeof(report_resp->data) + snp_dev->ctx->authsize;
report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
if (!report_resp)
return -ENOMEM;
@@ -1148,8 +1049,8 @@ static int __init sev_guest_probe(struct platform_device *pdev)
goto e_free_response;
ret = -EIO;
- snp_dev->crypto = init_crypto(snp_dev, snp_dev->vmpck, VMPCK_KEY_LEN);
- if (!snp_dev->crypto)
+ snp_dev->ctx = snp_init_crypto(snp_dev->vmpck, VMPCK_KEY_LEN);
+ if (!snp_dev->ctx)
goto e_free_cert_data;
misc = &snp_dev->misc;
@@ -1175,11 +1076,13 @@ static int __init sev_guest_probe(struct platform_device *pdev)
ret = misc_register(misc);
if (ret)
- goto e_free_cert_data;
+ goto e_free_ctx;
dev_info(dev, "Initialized SEV guest driver (using VMPCK%d communication key)\n", vmpck_id);
return 0;
+e_free_ctx:
+ kfree(snp_dev->ctx);
e_free_cert_data:
free_shared_pages(snp_dev->certs_data, SEV_FW_BLOB_MAX_SIZE);
e_free_response:
@@ -1198,7 +1101,7 @@ static void __exit sev_guest_remove(struct platform_device *pdev)
free_shared_pages(snp_dev->certs_data, SEV_FW_BLOB_MAX_SIZE);
free_shared_pages(snp_dev->response, sizeof(struct snp_guest_msg));
free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg));
- deinit_crypto(snp_dev->crypto);
+ kfree(snp_dev->ctx);
misc_deregister(&snp_dev->misc);
}
diff --git a/drivers/virt/coco/sev-guest/Kconfig b/drivers/virt/coco/sev-guest/Kconfig
index 1cffc72c41cb..0b772bd921d8 100644
--- a/drivers/virt/coco/sev-guest/Kconfig
+++ b/drivers/virt/coco/sev-guest/Kconfig
@@ -2,9 +2,7 @@ config SEV_GUEST
tristate "AMD SEV Guest driver"
default m
depends on AMD_MEM_ENCRYPT
- select CRYPTO
- select CRYPTO_AEAD2
- select CRYPTO_GCM
+ select CRYPTO_LIB_AESGCM
select TSM_REPORTS
help
SEV-SNP firmware provides the guest a mechanism to communicate with
--
2.34.1
next prev parent reply other threads:[~2024-07-31 15:08 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-31 15:07 [PATCH v11 00/20] Add Secure TSC support for SNP guests Nikunj A Dadhania
2024-07-31 15:07 ` [PATCH v11 01/20] virt: sev-guest: Replace dev_dbg with pr_debug Nikunj A Dadhania
2024-07-31 15:07 ` [PATCH v11 02/20] virt: sev-guest: Rename local guest message variables Nikunj A Dadhania
2024-09-13 17:22 ` Tom Lendacky
2024-07-31 15:07 ` [PATCH v11 03/20] virt: sev-guest: Fix user-visible strings Nikunj A Dadhania
2024-09-13 17:26 ` Tom Lendacky
2024-07-31 15:07 ` [PATCH v11 04/20] virt: sev-guest: Ensure the SNP guest messages do not exceed a page Nikunj A Dadhania
2024-07-31 15:07 ` Nikunj A Dadhania [this message]
2024-07-31 15:07 ` [PATCH v11 06/20] x86/sev: Handle failures from snp_init() Nikunj A Dadhania
2024-08-27 11:32 ` Borislav Petkov
2024-08-28 4:47 ` Nikunj A. Dadhania
2024-08-28 9:49 ` Borislav Petkov
2024-08-28 10:16 ` Nikunj A. Dadhania
2024-08-28 10:23 ` Borislav Petkov
2024-07-31 15:07 ` [PATCH v11 07/20] x86/sev: Cache the secrets page address Nikunj A Dadhania
2024-07-31 15:07 ` [PATCH v11 08/20] virt: sev-guest: Consolidate SNP guest messaging parameters to a struct Nikunj A Dadhania
2024-09-04 14:31 ` Borislav Petkov
2024-09-05 4:35 ` Nikunj A. Dadhania
2024-07-31 15:08 ` [PATCH v11 09/20] virt: sev-guest: Reduce the scope of SNP command mutex Nikunj A Dadhania
2024-09-12 21:54 ` Tom Lendacky
2024-09-13 4:26 ` Nikunj A. Dadhania
2024-09-13 14:06 ` Tom Lendacky
2024-07-31 15:08 ` [PATCH v11 10/20] virt: sev-guest: Carve out SNP message context structure Nikunj A Dadhania
2024-09-13 15:52 ` Tom Lendacky
2024-07-31 15:08 ` [PATCH v11 11/20] x86/sev: Carve out and export SNP guest messaging init routines Nikunj A Dadhania
2024-09-13 15:53 ` Tom Lendacky
2024-07-31 15:08 ` [PATCH v11 12/20] x86/sev: Relocate SNP guest messaging routines to common code Nikunj A Dadhania
2024-09-13 16:27 ` Tom Lendacky
2024-09-16 4:42 ` Nikunj A. Dadhania
2024-07-31 15:08 ` [PATCH v11 13/20] x86/cc: Add CC_ATTR_GUEST_SECURE_TSC Nikunj A Dadhania
2024-09-13 15:21 ` Tom Lendacky
2024-09-16 4:53 ` Nikunj A. Dadhania
2024-07-31 15:08 ` [PATCH v11 14/20] x86/sev: Add Secure TSC support for SNP guests Nikunj A Dadhania
2024-09-13 16:29 ` Tom Lendacky
2024-07-31 15:08 ` [PATCH v11 15/20] x86/sev: Change TSC MSR behavior for Secure TSC enabled guests Nikunj A Dadhania
2024-07-31 15:08 ` [PATCH v11 16/20] x86/sev: Prevent RDTSC/RDTSCP interception " Nikunj A Dadhania
2024-09-13 16:49 ` Tom Lendacky
2024-07-31 15:08 ` [PATCH v11 17/20] x86/sev: Allow Secure TSC feature for SNP guests Nikunj A Dadhania
2024-09-13 16:53 ` Tom Lendacky
2024-09-16 6:23 ` Nikunj A. Dadhania
2024-07-31 15:08 ` [PATCH v11 18/20] x86/sev: Mark Secure TSC as reliable clocksource Nikunj A Dadhania
2024-09-13 16:59 ` Tom Lendacky
2024-07-31 15:08 ` [PATCH v11 19/20] x86/kvmclock: Skip kvmclock when Secure TSC is available Nikunj A Dadhania
2024-09-13 17:19 ` Tom Lendacky
2024-09-13 17:30 ` Sean Christopherson
2024-09-16 15:20 ` Nikunj A. Dadhania
2024-09-18 12:07 ` Sean Christopherson
2024-09-20 5:15 ` Nikunj A. Dadhania
2024-09-20 7:21 ` Sean Christopherson
2024-09-20 8:54 ` Nikunj A. Dadhania
2024-09-25 8:53 ` Nikunj A. Dadhania
2024-09-25 12:55 ` Sean Christopherson
2024-09-30 6:27 ` Nikunj A. Dadhania
2024-09-30 21:20 ` Thomas Gleixner
2024-10-01 4:26 ` Nikunj A. Dadhania
2024-10-01 14:36 ` Nikunj A. Dadhania
2024-07-31 15:08 ` [PATCH v11 20/20] x86/cpu/amd: Do not print FW_BUG for Secure TSC Nikunj A Dadhania
2024-09-13 17:21 ` Tom Lendacky
2024-09-13 17:42 ` Jim Mattson
2024-09-16 11:40 ` Nikunj A. Dadhania
2024-09-16 20:21 ` Jim Mattson
2024-08-14 4:14 ` [PATCH v11 00/20] Add Secure TSC support for SNP guests Nikunj A. Dadhania
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=20240731150811.156771-6-nikunj@amd.com \
--to=nikunj@amd.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=pgonda@google.com \
--cc=seanjc@google.com \
--cc=tglx@linutronix.de \
--cc=thomas.lendacky@amd.com \
--cc=x86@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