Lines Matching +full:asp +full:- +full:v2
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2021-2024 Advanced Micro Devices, Inc.
22 #include <linux/psp-sev.h>
27 #include <uapi/linux/sev-guest.h>
28 #include <uapi/linux/psp-sev.h>
33 #define DEVICE_NAME "sev-guest"
58 * Avoid information leakage by double-buffering shared messages
76 * SEV firmware in the AMD Secure Processor (ASP, aka PSP). By default, the key
81 static int vmpck_id = -1;
92 if (snp_dev->vmpck) in is_vmpck_empty()
93 return !memcmp(snp_dev->vmpck, zero_key, VMPCK_KEY_LEN); in is_vmpck_empty()
99 * If an error is received from the host or AMD Secure Processor (ASP) there
103 * This is because in the current encryption scheme GHCB v2 uses AES-GCM to
107 * The ASP FW v1.51 only increments the sequence numbers on a successful
108 * guest<->ASP back and forth and only accepts messages at its exact sequence
112 * vulnerable. If the sequence number were incremented for a fresh IV the ASP
117 dev_alert(snp_dev->dev, "Disabling VMPCK%d communication key to prevent IV reuse.\n", in snp_disable_vmpck()
119 memzero_explicit(snp_dev->vmpck, VMPCK_KEY_LEN); in snp_disable_vmpck()
120 snp_dev->vmpck = NULL; in snp_disable_vmpck()
130 count = *snp_dev->os_area_msg_seqno; in __snp_get_msg_seqno()
135 /* Return a non-zero on success */
141 * The message sequence counter for the SNP guest request is a 64-bit in snp_get_msg_seqno()
142 * value but the version 2 of GHCB specification defines a 32-bit storage in snp_get_msg_seqno()
143 * for it. If the counter exceeds the 32-bit value then return zero. in snp_get_msg_seqno()
149 dev_err(snp_dev->dev, "request message sequence counter overflow\n"); in snp_get_msg_seqno()
162 *snp_dev->os_area_msg_seqno += 2; in snp_inc_msg_seqno()
167 struct miscdevice *dev = file->private_data; in to_snp_dev()
180 crypto->tfm = crypto_alloc_aead("gcm(aes)", 0, 0); in init_crypto()
181 if (IS_ERR(crypto->tfm)) in init_crypto()
184 if (crypto_aead_setkey(crypto->tfm, key, keylen)) in init_crypto()
187 crypto->iv_len = crypto_aead_ivsize(crypto->tfm); in init_crypto()
188 crypto->iv = kmalloc(crypto->iv_len, GFP_KERNEL_ACCOUNT); in init_crypto()
189 if (!crypto->iv) in init_crypto()
192 if (crypto_aead_authsize(crypto->tfm) > MAX_AUTHTAG_LEN) { in init_crypto()
193 if (crypto_aead_setauthsize(crypto->tfm, MAX_AUTHTAG_LEN)) { in init_crypto()
194 dev_err(snp_dev->dev, "failed to set authsize to %d\n", MAX_AUTHTAG_LEN); in init_crypto()
199 crypto->a_len = crypto_aead_authsize(crypto->tfm); in init_crypto()
200 crypto->authtag = kmalloc(crypto->a_len, GFP_KERNEL_ACCOUNT); in init_crypto()
201 if (!crypto->authtag) in init_crypto()
207 kfree(crypto->iv); in init_crypto()
209 crypto_free_aead(crypto->tfm); in init_crypto()
218 crypto_free_aead(crypto->tfm); in deinit_crypto()
219 kfree(crypto->iv); in deinit_crypto()
220 kfree(crypto->authtag); in deinit_crypto()
227 struct snp_guest_msg_hdr *hdr = &msg->hdr; in enc_dec_message()
233 req = aead_request_alloc(crypto->tfm, GFP_KERNEL); in enc_dec_message()
235 return -ENOMEM; in enc_dec_message()
239 * +------ AAD -------+------- DATA -----+---- AUTHTAG----+ in enc_dec_message()
240 * | msg header | plaintext | hdr->authtag | in enc_dec_message()
241 * | bytes 30h - 5Fh | or | | in enc_dec_message()
243 * +------------------+------------------+----------------+ in enc_dec_message()
246 sg_set_buf(&src[0], &hdr->algo, AAD_LEN); in enc_dec_message()
247 sg_set_buf(&src[1], src_buf, hdr->msg_sz); in enc_dec_message()
248 sg_set_buf(&src[2], hdr->authtag, crypto->a_len); in enc_dec_message()
251 sg_set_buf(&dst[0], &hdr->algo, AAD_LEN); in enc_dec_message()
252 sg_set_buf(&dst[1], dst_buf, hdr->msg_sz); in enc_dec_message()
253 sg_set_buf(&dst[2], hdr->authtag, crypto->a_len); in enc_dec_message()
256 aead_request_set_tfm(req, crypto->tfm); in enc_dec_message()
259 aead_request_set_crypt(req, src, dst, len, crypto->iv); in enc_dec_message()
269 struct snp_guest_crypto *crypto = snp_dev->crypto; in __enc_payload()
270 struct snp_guest_msg_hdr *hdr = &msg->hdr; in __enc_payload()
272 memset(crypto->iv, 0, crypto->iv_len); in __enc_payload()
273 memcpy(crypto->iv, &hdr->msg_seqno, sizeof(hdr->msg_seqno)); in __enc_payload()
275 return enc_dec_message(crypto, msg, plaintext, msg->payload, len, true); in __enc_payload()
281 struct snp_guest_crypto *crypto = snp_dev->crypto; in dec_payload()
282 struct snp_guest_msg_hdr *hdr = &msg->hdr; in dec_payload()
285 memset(crypto->iv, 0, crypto->iv_len); in dec_payload()
286 memcpy(crypto->iv, &hdr->msg_seqno, sizeof(hdr->msg_seqno)); in dec_payload()
288 return enc_dec_message(crypto, msg, msg->payload, plaintext, len, false); in dec_payload()
293 struct snp_guest_crypto *crypto = snp_dev->crypto; in verify_and_dec_payload()
294 struct snp_guest_msg *resp_msg = &snp_dev->secret_response; in verify_and_dec_payload()
295 struct snp_guest_msg *req_msg = &snp_dev->secret_request; in verify_and_dec_payload()
296 struct snp_guest_msg_hdr *req_msg_hdr = &req_msg->hdr; in verify_and_dec_payload()
297 struct snp_guest_msg_hdr *resp_msg_hdr = &resp_msg->hdr; in verify_and_dec_payload()
300 resp_msg_hdr->msg_seqno, resp_msg_hdr->msg_type, resp_msg_hdr->msg_version, in verify_and_dec_payload()
301 resp_msg_hdr->msg_sz); in verify_and_dec_payload()
304 memcpy(resp_msg, snp_dev->response, sizeof(*resp_msg)); in verify_and_dec_payload()
307 if (unlikely(resp_msg_hdr->msg_seqno != (req_msg_hdr->msg_seqno + 1))) in verify_and_dec_payload()
308 return -EBADMSG; in verify_and_dec_payload()
311 if (resp_msg_hdr->msg_type != (req_msg_hdr->msg_type + 1) || in verify_and_dec_payload()
312 resp_msg_hdr->msg_version != req_msg_hdr->msg_version) in verify_and_dec_payload()
313 return -EBADMSG; in verify_and_dec_payload()
319 if (unlikely((resp_msg_hdr->msg_sz + crypto->a_len) > sz)) in verify_and_dec_payload()
320 return -EBADMSG; in verify_and_dec_payload()
323 return dec_payload(snp_dev, resp_msg, payload, resp_msg_hdr->msg_sz + crypto->a_len); in verify_and_dec_payload()
329 struct snp_guest_msg *msg = &snp_dev->secret_request; in enc_payload()
330 struct snp_guest_msg_hdr *hdr = &msg->hdr; in enc_payload()
334 hdr->algo = SNP_AEAD_AES_256_GCM; in enc_payload()
335 hdr->hdr_version = MSG_HDR_VER; in enc_payload()
336 hdr->hdr_sz = sizeof(*hdr); in enc_payload()
337 hdr->msg_type = type; in enc_payload()
338 hdr->msg_version = version; in enc_payload()
339 hdr->msg_seqno = seqno; in enc_payload()
340 hdr->msg_vmpck = vmpck_id; in enc_payload()
341 hdr->msg_sz = sz; in enc_payload()
343 /* Verify the sequence number is non-zero */ in enc_payload()
344 if (!hdr->msg_seqno) in enc_payload()
345 return -ENOSR; in enc_payload()
348 hdr->msg_seqno, hdr->msg_type, hdr->msg_version, hdr->msg_sz); in enc_payload()
368 rc = snp_issue_guest_request(exit_code, &snp_dev->input, rio); in __handle_guest_request()
370 case -ENOSPC: in __handle_guest_request()
378 override_npages = snp_dev->input.data_npages; in __handle_guest_request()
403 case -EAGAIN: in __handle_guest_request()
404 if (jiffies - req_start > SNP_REQ_MAX_RETRY_DURATION) { in __handle_guest_request()
405 rc = -ETIMEDOUT; in __handle_guest_request()
421 rio->exitinfo2 = override_err; in __handle_guest_request()
426 * prevent IV reuse. If the standard request was successful, return -EIO in __handle_guest_request()
430 rc = -EIO; in __handle_guest_request()
434 snp_dev->input.data_npages = override_npages; in __handle_guest_request()
447 /* Get message sequence and verify that its a non-zero */ in handle_guest_request()
450 return -EIO; in handle_guest_request()
453 memset(snp_dev->response, 0, sizeof(struct snp_guest_msg)); in handle_guest_request()
455 /* Encrypt the userspace provided payload in snp_dev->secret_request. */ in handle_guest_request()
456 rc = enc_payload(snp_dev, seqno, rio->msg_version, type, req_buf, req_sz); in handle_guest_request()
464 memcpy(snp_dev->request, &snp_dev->secret_request, in handle_guest_request()
465 sizeof(snp_dev->secret_request)); in handle_guest_request()
469 if (rc == -EIO && in handle_guest_request()
470 rio->exitinfo2 == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) in handle_guest_request()
473 dev_alert(snp_dev->dev, in handle_guest_request()
474 "Detected error from ASP request. rc: %d, exitinfo2: 0x%llx\n", in handle_guest_request()
475 rc, rio->exitinfo2); in handle_guest_request()
483 dev_alert(snp_dev->dev, "Detected unexpected decode failure from ASP. rc: %d\n", rc); in handle_guest_request()
498 struct snp_guest_crypto *crypto = snp_dev->crypto; in get_report()
499 struct snp_report_req *report_req = &snp_dev->req.report; in get_report()
505 if (!arg->req_data || !arg->resp_data) in get_report()
506 return -EINVAL; in get_report()
508 if (copy_from_user(report_req, (void __user *)arg->req_data, sizeof(*report_req))) in get_report()
509 return -EFAULT; in get_report()
516 resp_len = sizeof(report_resp->data) + crypto->a_len; in get_report()
519 return -ENOMEM; in get_report()
522 report_req, sizeof(*report_req), report_resp->data, resp_len); in get_report()
526 if (copy_to_user((void __user *)arg->resp_data, report_resp, sizeof(*report_resp))) in get_report()
527 rc = -EFAULT; in get_report()
536 struct snp_derived_key_req *derived_key_req = &snp_dev->req.derived_key; in get_derived_key()
537 struct snp_guest_crypto *crypto = snp_dev->crypto; in get_derived_key()
545 if (!arg->req_data || !arg->resp_data) in get_derived_key()
546 return -EINVAL; in get_derived_key()
553 resp_len = sizeof(derived_key_resp.data) + crypto->a_len; in get_derived_key()
555 return -ENOMEM; in get_derived_key()
557 if (copy_from_user(derived_key_req, (void __user *)arg->req_data, in get_derived_key()
559 return -EFAULT; in get_derived_key()
567 if (copy_to_user((void __user *)arg->resp_data, &derived_key_resp, in get_derived_key()
569 rc = -EFAULT; in get_derived_key()
581 struct snp_ext_report_req *report_req = &snp_dev->req.ext_report; in get_ext_report()
582 struct snp_guest_crypto *crypto = snp_dev->crypto; in get_ext_report()
589 if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data)) in get_ext_report()
590 return -EINVAL; in get_ext_report()
592 if (copy_from_sockptr(report_req, io->req_data, sizeof(*report_req))) in get_ext_report()
593 return -EFAULT; in get_ext_report()
596 if (!report_req->certs_len || !report_req->certs_address) in get_ext_report()
599 if (report_req->certs_len > SEV_FW_BLOB_MAX_SIZE || in get_ext_report()
600 !IS_ALIGNED(report_req->certs_len, PAGE_SIZE)) in get_ext_report()
601 return -EINVAL; in get_ext_report()
603 if (sockptr_is_kernel(io->resp_data)) { in get_ext_report()
604 certs_address = KERNEL_SOCKPTR((void *)report_req->certs_address); in get_ext_report()
606 certs_address = USER_SOCKPTR((void __user *)report_req->certs_address); in get_ext_report()
607 if (!access_ok(certs_address.user, report_req->certs_len)) in get_ext_report()
608 return -EFAULT; in get_ext_report()
617 memset(snp_dev->certs_data, 0, report_req->certs_len); in get_ext_report()
618 npages = report_req->certs_len >> PAGE_SHIFT; in get_ext_report()
625 resp_len = sizeof(report_resp->data) + crypto->a_len; in get_ext_report()
628 return -ENOMEM; in get_ext_report()
630 snp_dev->input.data_npages = npages; in get_ext_report()
632 &report_req->data, sizeof(report_req->data), in get_ext_report()
633 report_resp->data, resp_len); in get_ext_report()
636 if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) { in get_ext_report()
637 report_req->certs_len = snp_dev->input.data_npages << PAGE_SHIFT; in get_ext_report()
639 if (copy_to_sockptr(io->req_data, report_req, sizeof(*report_req))) in get_ext_report()
640 ret = -EFAULT; in get_ext_report()
646 if (npages && copy_to_sockptr(certs_address, snp_dev->certs_data, report_req->certs_len)) { in get_ext_report()
647 ret = -EFAULT; in get_ext_report()
651 if (copy_to_sockptr(io->resp_data, report_resp, sizeof(*report_resp))) in get_ext_report()
652 ret = -EFAULT; in get_ext_report()
665 int ret = -ENOTTY; in snp_guest_ioctl()
668 return -EFAULT; in snp_guest_ioctl()
672 /* Message version must be non-zero */ in snp_guest_ioctl()
674 return -EINVAL; in snp_guest_ioctl()
680 dev_err_ratelimited(snp_dev->dev, "VMPCK is disabled\n"); in snp_guest_ioctl()
682 return -ENOTTY; in snp_guest_ioctl()
695 * kernel internal path (configfs-tsm), decorate the passed in snp_guest_ioctl()
709 return -EFAULT; in snp_guest_ioctl()
762 *seqno = &secrets->os_area.msg_seqno_0; in get_vmpck()
763 key = secrets->vmpck0; in get_vmpck()
766 *seqno = &secrets->os_area.msg_seqno_1; in get_vmpck()
767 key = secrets->vmpck1; in get_vmpck()
770 *seqno = &secrets->os_area.msg_seqno_2; in get_vmpck()
771 key = secrets->vmpck2; in get_vmpck()
774 *seqno = &secrets->os_area.msg_seqno_3; in get_vmpck()
775 key = secrets->vmpck3; in get_vmpck()
799 struct tsm_desc *desc = &report->desc; in sev_svsm_report_new()
812 * - Report blob (4K) in sev_svsm_report_new()
813 * - Manifest blob (4K) in sev_svsm_report_new()
814 * - Certificate blob (16K) in sev_svsm_report_new()
824 if (guid_is_null(&desc->service_guid)) { in sev_svsm_report_new()
827 export_guid(ac.service_guid, &desc->service_guid); in sev_svsm_report_new()
828 ac.service_manifest_ver = desc->service_manifest_version; in sev_svsm_report_new()
841 return -ENOMEM; in sev_svsm_report_new()
855 ac.nonce.pa = __pa(desc->inblob); in sev_svsm_report_new()
856 ac.nonce.len = desc->inblob_len; in sev_svsm_report_new()
887 return -EINVAL; in sev_svsm_report_new()
891 return -EINVAL; in sev_svsm_report_new()
911 return -ENOMEM; in sev_svsm_report_new()
915 report->outblob = no_free_ptr(rbuf); in sev_svsm_report_new()
916 report->outblob_len = rep_len; in sev_svsm_report_new()
919 report->manifestblob = no_free_ptr(mbuf); in sev_svsm_report_new()
920 report->manifestblob_len = man_len; in sev_svsm_report_new()
924 report->auxblob = no_free_ptr(cbuf); in sev_svsm_report_new()
925 report->auxblob_len = certs_len; in sev_svsm_report_new()
936 struct tsm_desc *desc = &report->desc; in sev_report_new()
944 if (desc->inblob_len != SNP_REPORT_USER_DATA_SIZE) in sev_report_new()
945 return -EINVAL; in sev_report_new()
947 if (desc->service_provider) { in sev_report_new()
948 if (strcmp(desc->service_provider, "svsm")) in sev_report_new()
949 return -EINVAL; in sev_report_new()
956 return -ENOMEM; in sev_report_new()
962 dev_err_ratelimited(snp_dev->dev, "VMPCK is disabled\n"); in sev_report_new()
963 return -ENOTTY; in sev_report_new()
968 .data = { .vmpl = desc->privlevel }, in sev_report_new()
972 memcpy(&ext_req.data.user_data, desc->inblob, desc->inblob_len); in sev_report_new()
991 return -EINVAL; in sev_report_new()
993 return -EINVAL; in sev_report_new()
995 return -ENXIO; in sev_report_new()
997 return -ENOMEM; in sev_report_new()
1001 return -ENOMEM; in sev_report_new()
1004 report->outblob = no_free_ptr(rbuf); in sev_report_new()
1005 report->outblob_len = hdr.report_size; in sev_report_new()
1011 if (guid_is_null(&ent->guid) && !ent->offset && !ent->length) in sev_report_new()
1013 certs_size = max(certs_size, ent->offset + ent->length); in sev_report_new()
1018 dev_warn_ratelimited(snp_dev->dev, "certificate slots conveyed without size\n"); in sev_report_new()
1027 dev_warn_ratelimited(snp_dev->dev, "certificate data truncated\n"); in sev_report_new()
1033 return -ENOMEM; in sev_report_new()
1036 report->auxblob = no_free_ptr(cbuf); in sev_report_new()
1037 report->auxblob_len = certs_size; in sev_report_new()
1089 struct device *dev = &pdev->dev; in sev_guest_probe()
1098 return -ENODEV; in sev_guest_probe()
1100 if (!dev->platform_data) in sev_guest_probe()
1101 return -ENODEV; in sev_guest_probe()
1103 data = (struct sev_guest_platform_data *)dev->platform_data; in sev_guest_probe()
1104 mapping = ioremap_encrypted(data->secrets_gpa, PAGE_SIZE); in sev_guest_probe()
1106 return -ENODEV; in sev_guest_probe()
1110 ret = -ENOMEM; in sev_guest_probe()
1111 snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL); in sev_guest_probe()
1116 if (vmpck_id == -1) in sev_guest_probe()
1119 ret = -EINVAL; in sev_guest_probe()
1120 snp_dev->vmpck = get_vmpck(vmpck_id, secrets, &snp_dev->os_area_msg_seqno); in sev_guest_probe()
1121 if (!snp_dev->vmpck) { in sev_guest_probe()
1133 snp_dev->dev = dev; in sev_guest_probe()
1134 snp_dev->secrets = secrets; in sev_guest_probe()
1137 snp_dev->request = alloc_shared_pages(dev, sizeof(struct snp_guest_msg)); in sev_guest_probe()
1138 if (!snp_dev->request) in sev_guest_probe()
1141 snp_dev->response = alloc_shared_pages(dev, sizeof(struct snp_guest_msg)); in sev_guest_probe()
1142 if (!snp_dev->response) in sev_guest_probe()
1145 snp_dev->certs_data = alloc_shared_pages(dev, SEV_FW_BLOB_MAX_SIZE); in sev_guest_probe()
1146 if (!snp_dev->certs_data) in sev_guest_probe()
1149 ret = -EIO; in sev_guest_probe()
1150 snp_dev->crypto = init_crypto(snp_dev, snp_dev->vmpck, VMPCK_KEY_LEN); in sev_guest_probe()
1151 if (!snp_dev->crypto) in sev_guest_probe()
1154 misc = &snp_dev->misc; in sev_guest_probe()
1155 misc->minor = MISC_DYNAMIC_MINOR; in sev_guest_probe()
1156 misc->name = DEVICE_NAME; in sev_guest_probe()
1157 misc->fops = &snp_guest_fops; in sev_guest_probe()
1160 snp_dev->input.req_gpa = __pa(snp_dev->request); in sev_guest_probe()
1161 snp_dev->input.resp_gpa = __pa(snp_dev->response); in sev_guest_probe()
1162 snp_dev->input.data_gpa = __pa(snp_dev->certs_data); in sev_guest_probe()
1171 ret = devm_add_action_or_reset(&pdev->dev, unregister_sev_tsm, NULL); in sev_guest_probe()
1183 free_shared_pages(snp_dev->certs_data, SEV_FW_BLOB_MAX_SIZE); in sev_guest_probe()
1185 free_shared_pages(snp_dev->response, sizeof(struct snp_guest_msg)); in sev_guest_probe()
1187 free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg)); in sev_guest_probe()
1197 free_shared_pages(snp_dev->certs_data, SEV_FW_BLOB_MAX_SIZE); in sev_guest_remove()
1198 free_shared_pages(snp_dev->response, sizeof(struct snp_guest_msg)); in sev_guest_remove()
1199 free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg)); in sev_guest_remove()
1200 deinit_crypto(snp_dev->crypto); in sev_guest_remove()
1201 misc_deregister(&snp_dev->misc); in sev_guest_remove()
1207 * with the SEV-SNP support, it is named "sev-guest".
1217 .name = "sev-guest",
1227 MODULE_ALIAS("platform:sev-guest");