Skip to content

Commit f3476bc

Browse files
nikunjadbp3tk0v
authored andcommitted
virt: sev-guest: Use AES GCM crypto library
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. Signed-off-by: Nikunj A Dadhania <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Tom Lendacky <[email protected]> Acked-by: Borislav Petkov (AMD) <[email protected]> Tested-by: Peter Gonda <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2db67aa commit f3476bc

File tree

3 files changed

+43
-139
lines changed

3 files changed

+43
-139
lines changed

arch/x86/include/asm/sev.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ struct snp_req_data {
120120
};
121121

122122
#define MAX_AUTHTAG_LEN 32
123+
#define AUTHTAG_LEN 16
124+
#define AAD_LEN 48
125+
#define MSG_HDR_VER 1
123126

124127
/* See SNP spec SNP_GUEST_REQUEST section for the structure */
125128
enum msg_type {

drivers/virt/coco/sev-guest/Kconfig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ config SEV_GUEST
22
tristate "AMD SEV Guest driver"
33
default m
44
depends on AMD_MEM_ENCRYPT
5-
select CRYPTO
6-
select CRYPTO_AEAD2
7-
select CRYPTO_GCM
5+
select CRYPTO_LIB_AESGCM
86
select TSM_REPORTS
97
help
108
SEV-SNP firmware provides the guest a mechanism to communicate with

drivers/virt/coco/sev-guest/sev-guest.c

Lines changed: 39 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
#include <linux/set_memory.h>
1818
#include <linux/fs.h>
1919
#include <linux/tsm.h>
20-
#include <crypto/aead.h>
21-
#include <linux/scatterlist.h>
20+
#include <crypto/gcm.h>
2221
#include <linux/psp-sev.h>
2322
#include <linux/sockptr.h>
2423
#include <linux/cleanup.h>
@@ -31,26 +30,18 @@
3130
#include <asm/sev.h>
3231

3332
#define DEVICE_NAME "sev-guest"
34-
#define AAD_LEN 48
35-
#define MSG_HDR_VER 1
3633

3734
#define SNP_REQ_MAX_RETRY_DURATION (60*HZ)
3835
#define SNP_REQ_RETRY_DELAY (2*HZ)
3936

4037
#define SVSM_MAX_RETRIES 3
4138

42-
struct snp_guest_crypto {
43-
struct crypto_aead *tfm;
44-
u8 *iv, *authtag;
45-
int iv_len, a_len;
46-
};
47-
4839
struct snp_guest_dev {
4940
struct device *dev;
5041
struct miscdevice misc;
5142

5243
void *certs_data;
53-
struct snp_guest_crypto *crypto;
44+
struct aesgcm_ctx *ctx;
5445
/* request and response are in unencrypted memory */
5546
struct snp_guest_msg *request, *response;
5647

@@ -169,132 +160,31 @@ static inline struct snp_guest_dev *to_snp_dev(struct file *file)
169160
return container_of(dev, struct snp_guest_dev, misc);
170161
}
171162

172-
static struct snp_guest_crypto *init_crypto(struct snp_guest_dev *snp_dev, u8 *key, size_t keylen)
163+
static struct aesgcm_ctx *snp_init_crypto(u8 *key, size_t keylen)
173164
{
174-
struct snp_guest_crypto *crypto;
165+
struct aesgcm_ctx *ctx;
175166

176-
crypto = kzalloc(sizeof(*crypto), GFP_KERNEL_ACCOUNT);
177-
if (!crypto)
167+
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
168+
if (!ctx)
178169
return NULL;
179170

180-
crypto->tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
181-
if (IS_ERR(crypto->tfm))
182-
goto e_free;
183-
184-
if (crypto_aead_setkey(crypto->tfm, key, keylen))
185-
goto e_free_crypto;
186-
187-
crypto->iv_len = crypto_aead_ivsize(crypto->tfm);
188-
crypto->iv = kmalloc(crypto->iv_len, GFP_KERNEL_ACCOUNT);
189-
if (!crypto->iv)
190-
goto e_free_crypto;
191-
192-
if (crypto_aead_authsize(crypto->tfm) > MAX_AUTHTAG_LEN) {
193-
if (crypto_aead_setauthsize(crypto->tfm, MAX_AUTHTAG_LEN)) {
194-
dev_err(snp_dev->dev, "failed to set authsize to %d\n", MAX_AUTHTAG_LEN);
195-
goto e_free_iv;
196-
}
171+
if (aesgcm_expandkey(ctx, key, keylen, AUTHTAG_LEN)) {
172+
pr_err("Crypto context initialization failed\n");
173+
kfree(ctx);
174+
return NULL;
197175
}
198176

199-
crypto->a_len = crypto_aead_authsize(crypto->tfm);
200-
crypto->authtag = kmalloc(crypto->a_len, GFP_KERNEL_ACCOUNT);
201-
if (!crypto->authtag)
202-
goto e_free_iv;
203-
204-
return crypto;
205-
206-
e_free_iv:
207-
kfree(crypto->iv);
208-
e_free_crypto:
209-
crypto_free_aead(crypto->tfm);
210-
e_free:
211-
kfree(crypto);
212-
213-
return NULL;
214-
}
215-
216-
static void deinit_crypto(struct snp_guest_crypto *crypto)
217-
{
218-
crypto_free_aead(crypto->tfm);
219-
kfree(crypto->iv);
220-
kfree(crypto->authtag);
221-
kfree(crypto);
222-
}
223-
224-
static int enc_dec_message(struct snp_guest_crypto *crypto, struct snp_guest_msg *msg,
225-
u8 *src_buf, u8 *dst_buf, size_t len, bool enc)
226-
{
227-
struct snp_guest_msg_hdr *hdr = &msg->hdr;
228-
struct scatterlist src[3], dst[3];
229-
DECLARE_CRYPTO_WAIT(wait);
230-
struct aead_request *req;
231-
int ret;
232-
233-
req = aead_request_alloc(crypto->tfm, GFP_KERNEL);
234-
if (!req)
235-
return -ENOMEM;
236-
237-
/*
238-
* AEAD memory operations:
239-
* +------ AAD -------+------- DATA -----+---- AUTHTAG----+
240-
* | msg header | plaintext | hdr->authtag |
241-
* | bytes 30h - 5Fh | or | |
242-
* | | cipher | |
243-
* +------------------+------------------+----------------+
244-
*/
245-
sg_init_table(src, 3);
246-
sg_set_buf(&src[0], &hdr->algo, AAD_LEN);
247-
sg_set_buf(&src[1], src_buf, hdr->msg_sz);
248-
sg_set_buf(&src[2], hdr->authtag, crypto->a_len);
249-
250-
sg_init_table(dst, 3);
251-
sg_set_buf(&dst[0], &hdr->algo, AAD_LEN);
252-
sg_set_buf(&dst[1], dst_buf, hdr->msg_sz);
253-
sg_set_buf(&dst[2], hdr->authtag, crypto->a_len);
254-
255-
aead_request_set_ad(req, AAD_LEN);
256-
aead_request_set_tfm(req, crypto->tfm);
257-
aead_request_set_callback(req, 0, crypto_req_done, &wait);
258-
259-
aead_request_set_crypt(req, src, dst, len, crypto->iv);
260-
ret = crypto_wait_req(enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req), &wait);
261-
262-
aead_request_free(req);
263-
return ret;
264-
}
265-
266-
static int __enc_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg,
267-
void *plaintext, size_t len)
268-
{
269-
struct snp_guest_crypto *crypto = snp_dev->crypto;
270-
struct snp_guest_msg_hdr *hdr = &msg->hdr;
271-
272-
memset(crypto->iv, 0, crypto->iv_len);
273-
memcpy(crypto->iv, &hdr->msg_seqno, sizeof(hdr->msg_seqno));
274-
275-
return enc_dec_message(crypto, msg, plaintext, msg->payload, len, true);
276-
}
277-
278-
static int dec_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg,
279-
void *plaintext, size_t len)
280-
{
281-
struct snp_guest_crypto *crypto = snp_dev->crypto;
282-
struct snp_guest_msg_hdr *hdr = &msg->hdr;
283-
284-
/* Build IV with response buffer sequence number */
285-
memset(crypto->iv, 0, crypto->iv_len);
286-
memcpy(crypto->iv, &hdr->msg_seqno, sizeof(hdr->msg_seqno));
287-
288-
return enc_dec_message(crypto, msg, msg->payload, plaintext, len, false);
177+
return ctx;
289178
}
290179

291180
static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, u32 sz)
292181
{
293-
struct snp_guest_crypto *crypto = snp_dev->crypto;
294182
struct snp_guest_msg *resp_msg = &snp_dev->secret_response;
295183
struct snp_guest_msg *req_msg = &snp_dev->secret_request;
296184
struct snp_guest_msg_hdr *req_msg_hdr = &req_msg->hdr;
297185
struct snp_guest_msg_hdr *resp_msg_hdr = &resp_msg->hdr;
186+
struct aesgcm_ctx *ctx = snp_dev->ctx;
187+
u8 iv[GCM_AES_IV_SIZE] = {};
298188

299189
pr_debug("response [seqno %lld type %d version %d sz %d]\n",
300190
resp_msg_hdr->msg_seqno, resp_msg_hdr->msg_type, resp_msg_hdr->msg_version,
@@ -316,18 +206,25 @@ static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload,
316206
* If the message size is greater than our buffer length then return
317207
* an error.
318208
*/
319-
if (unlikely((resp_msg_hdr->msg_sz + crypto->a_len) > sz))
209+
if (unlikely((resp_msg_hdr->msg_sz + ctx->authsize) > sz))
320210
return -EBADMSG;
321211

322212
/* Decrypt the payload */
323-
return dec_payload(snp_dev, resp_msg, payload, resp_msg_hdr->msg_sz + crypto->a_len);
213+
memcpy(iv, &resp_msg_hdr->msg_seqno, min(sizeof(iv), sizeof(resp_msg_hdr->msg_seqno)));
214+
if (!aesgcm_decrypt(ctx, payload, resp_msg->payload, resp_msg_hdr->msg_sz,
215+
&resp_msg_hdr->algo, AAD_LEN, iv, resp_msg_hdr->authtag))
216+
return -EBADMSG;
217+
218+
return 0;
324219
}
325220

326221
static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 type,
327222
void *payload, size_t sz)
328223
{
329224
struct snp_guest_msg *msg = &snp_dev->secret_request;
330225
struct snp_guest_msg_hdr *hdr = &msg->hdr;
226+
struct aesgcm_ctx *ctx = snp_dev->ctx;
227+
u8 iv[GCM_AES_IV_SIZE] = {};
331228

332229
memset(msg, 0, sizeof(*msg));
333230

@@ -347,7 +244,14 @@ static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8
347244
pr_debug("request [seqno %lld type %d version %d sz %d]\n",
348245
hdr->msg_seqno, hdr->msg_type, hdr->msg_version, hdr->msg_sz);
349246

350-
return __enc_payload(snp_dev, msg, payload, sz);
247+
if (WARN_ON((sz + ctx->authsize) > sizeof(msg->payload)))
248+
return -EBADMSG;
249+
250+
memcpy(iv, &hdr->msg_seqno, min(sizeof(iv), sizeof(hdr->msg_seqno)));
251+
aesgcm_encrypt(ctx, msg->payload, payload, sz, &hdr->algo, AAD_LEN,
252+
iv, hdr->authtag);
253+
254+
return 0;
351255
}
352256

353257
static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code,
@@ -495,7 +399,6 @@ struct snp_req_resp {
495399

496400
static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
497401
{
498-
struct snp_guest_crypto *crypto = snp_dev->crypto;
499402
struct snp_report_req *report_req = &snp_dev->req.report;
500403
struct snp_report_resp *report_resp;
501404
int rc, resp_len;
@@ -513,7 +416,7 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io
513416
* response payload. Make sure that it has enough space to cover the
514417
* authtag.
515418
*/
516-
resp_len = sizeof(report_resp->data) + crypto->a_len;
419+
resp_len = sizeof(report_resp->data) + snp_dev->ctx->authsize;
517420
report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
518421
if (!report_resp)
519422
return -ENOMEM;
@@ -534,7 +437,6 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io
534437
static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
535438
{
536439
struct snp_derived_key_req *derived_key_req = &snp_dev->req.derived_key;
537-
struct snp_guest_crypto *crypto = snp_dev->crypto;
538440
struct snp_derived_key_resp derived_key_resp = {0};
539441
int rc, resp_len;
540442
/* 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
550452
* response payload. Make sure that it has enough space to cover the
551453
* authtag.
552454
*/
553-
resp_len = sizeof(derived_key_resp.data) + crypto->a_len;
455+
resp_len = sizeof(derived_key_resp.data) + snp_dev->ctx->authsize;
554456
if (sizeof(buf) < resp_len)
555457
return -ENOMEM;
556458

@@ -579,7 +481,6 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
579481

580482
{
581483
struct snp_ext_report_req *report_req = &snp_dev->req.ext_report;
582-
struct snp_guest_crypto *crypto = snp_dev->crypto;
583484
struct snp_report_resp *report_resp;
584485
int ret, npages = 0, resp_len;
585486
sockptr_t certs_address;
@@ -622,7 +523,7 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
622523
* response payload. Make sure that it has enough space to cover the
623524
* authtag.
624525
*/
625-
resp_len = sizeof(report_resp->data) + crypto->a_len;
526+
resp_len = sizeof(report_resp->data) + snp_dev->ctx->authsize;
626527
report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
627528
if (!report_resp)
628529
return -ENOMEM;
@@ -1147,8 +1048,8 @@ static int __init sev_guest_probe(struct platform_device *pdev)
11471048
goto e_free_response;
11481049

11491050
ret = -EIO;
1150-
snp_dev->crypto = init_crypto(snp_dev, snp_dev->vmpck, VMPCK_KEY_LEN);
1151-
if (!snp_dev->crypto)
1051+
snp_dev->ctx = snp_init_crypto(snp_dev->vmpck, VMPCK_KEY_LEN);
1052+
if (!snp_dev->ctx)
11521053
goto e_free_cert_data;
11531054

11541055
misc = &snp_dev->misc;
@@ -1174,11 +1075,13 @@ static int __init sev_guest_probe(struct platform_device *pdev)
11741075

11751076
ret = misc_register(misc);
11761077
if (ret)
1177-
goto e_free_cert_data;
1078+
goto e_free_ctx;
11781079

11791080
dev_info(dev, "Initialized SEV guest driver (using VMPCK%d communication key)\n", vmpck_id);
11801081
return 0;
11811082

1083+
e_free_ctx:
1084+
kfree(snp_dev->ctx);
11821085
e_free_cert_data:
11831086
free_shared_pages(snp_dev->certs_data, SEV_FW_BLOB_MAX_SIZE);
11841087
e_free_response:
@@ -1197,7 +1100,7 @@ static void __exit sev_guest_remove(struct platform_device *pdev)
11971100
free_shared_pages(snp_dev->certs_data, SEV_FW_BLOB_MAX_SIZE);
11981101
free_shared_pages(snp_dev->response, sizeof(struct snp_guest_msg));
11991102
free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg));
1200-
deinit_crypto(snp_dev->crypto);
1103+
kfree(snp_dev->ctx);
12011104
misc_deregister(&snp_dev->misc);
12021105
}
12031106

0 commit comments

Comments
 (0)