Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

virt: sevguest: Fix passing a stack buffer as a scatterlist target

CONFIG_DEBUG_SG highlights that get_{report,ext_report,derived_key)()}
are passing stack buffers as the @req_buf argument to
handle_guest_request(), generating a Call Trace of the following form:

WARNING: CPU: 0 PID: 1175 at include/linux/scatterlist.h:187 enc_dec_message+0x518/0x5b0 [sev_guest]
[..]
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/26/2023
RIP: 0010:enc_dec_message+0x518/0x5b0 [sev_guest]
Call Trace:
<TASK>
[..]
handle_guest_request+0x135/0x520 [sev_guest]
get_ext_report+0x1ec/0x3e0 [sev_guest]
snp_guest_ioctl+0x157/0x200 [sev_guest]

Note that the above Call Trace was with the DEBUG_SG BUG_ON()s converted
to WARN_ON()s.

This is benign as long as there are no hardware crypto accelerators
loaded for the aead cipher, and no subsequent dma_map_sg() is performed
on the scatterlist. However, sev-guest can not assume the presence of
an aead accelerator nor can it assume that CONFIG_DEBUG_SG is disabled.

Resolve this bug by allocating virt_addr_valid() memory, similar to the
other buffers am @snp_dev instance carries, to marshal requests from
user buffers to kernel buffers.

Reported-by: Peter Gonda <pgonda@google.com>
Closes: http://lore.kernel.org/r/CAMkAt6r2VPPMZ__SQfJse8qWsUyYW3AgYbOUVM0S_Vtk=KvkxQ@mail.gmail.com
Fixes: fce96cf04430 ("virt: Add SEV-SNP guest driver")
Cc: Borislav Petkov <bp@alien8.de>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Dionna Glaze <dionnaglaze@google.com>
Cc: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com>
Tested-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+25 -20
+25 -20
drivers/virt/coco/sev-guest/sev-guest.c
··· 57 57 58 58 struct snp_secrets_page_layout *layout; 59 59 struct snp_req_data input; 60 + union { 61 + struct snp_report_req report; 62 + struct snp_derived_key_req derived_key; 63 + struct snp_ext_report_req ext_report; 64 + } req; 60 65 u32 *os_area_msg_seqno; 61 66 u8 *vmpck; 62 67 }; ··· 478 473 static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg) 479 474 { 480 475 struct snp_guest_crypto *crypto = snp_dev->crypto; 476 + struct snp_report_req *req = &snp_dev->req.report; 481 477 struct snp_report_resp *resp; 482 - struct snp_report_req req; 483 478 int rc, resp_len; 484 479 485 480 lockdep_assert_held(&snp_cmd_mutex); ··· 487 482 if (!arg->req_data || !arg->resp_data) 488 483 return -EINVAL; 489 484 490 - if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) 485 + if (copy_from_user(req, (void __user *)arg->req_data, sizeof(*req))) 491 486 return -EFAULT; 492 487 493 488 /* ··· 501 496 return -ENOMEM; 502 497 503 498 rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, 504 - SNP_MSG_REPORT_REQ, &req, sizeof(req), resp->data, 499 + SNP_MSG_REPORT_REQ, req, sizeof(*req), resp->data, 505 500 resp_len); 506 501 if (rc) 507 502 goto e_free; ··· 516 511 517 512 static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg) 518 513 { 514 + struct snp_derived_key_req *req = &snp_dev->req.derived_key; 519 515 struct snp_guest_crypto *crypto = snp_dev->crypto; 520 516 struct snp_derived_key_resp resp = {0}; 521 - struct snp_derived_key_req req; 522 517 int rc, resp_len; 523 518 /* Response data is 64 bytes and max authsize for GCM is 16 bytes. */ 524 519 u8 buf[64 + 16]; ··· 537 532 if (sizeof(buf) < resp_len) 538 533 return -ENOMEM; 539 534 540 - if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) 535 + if (copy_from_user(req, (void __user *)arg->req_data, sizeof(*req))) 541 536 return -EFAULT; 542 537 543 538 rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, 544 - SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len); 539 + SNP_MSG_KEY_REQ, req, sizeof(*req), buf, resp_len); 545 540 if (rc) 546 541 return rc; 547 542 ··· 557 552 558 553 static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg) 559 554 { 555 + struct snp_ext_report_req *req = &snp_dev->req.ext_report; 560 556 struct snp_guest_crypto *crypto = snp_dev->crypto; 561 - struct snp_ext_report_req req; 562 557 struct snp_report_resp *resp; 563 558 int ret, npages = 0, resp_len; 564 559 ··· 567 562 if (!arg->req_data || !arg->resp_data) 568 563 return -EINVAL; 569 564 570 - if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) 565 + if (copy_from_user(req, (void __user *)arg->req_data, sizeof(*req))) 571 566 return -EFAULT; 572 567 573 568 /* userspace does not want certificate data */ 574 - if (!req.certs_len || !req.certs_address) 569 + if (!req->certs_len || !req->certs_address) 575 570 goto cmd; 576 571 577 - if (req.certs_len > SEV_FW_BLOB_MAX_SIZE || 578 - !IS_ALIGNED(req.certs_len, PAGE_SIZE)) 572 + if (req->certs_len > SEV_FW_BLOB_MAX_SIZE || 573 + !IS_ALIGNED(req->certs_len, PAGE_SIZE)) 579 574 return -EINVAL; 580 575 581 - if (!access_ok((const void __user *)req.certs_address, req.certs_len)) 576 + if (!access_ok((const void __user *)req->certs_address, req->certs_len)) 582 577 return -EFAULT; 583 578 584 579 /* ··· 587 582 * the host. If host does not supply any certs in it, then copy 588 583 * zeros to indicate that certificate data was not provided. 589 584 */ 590 - memset(snp_dev->certs_data, 0, req.certs_len); 591 - npages = req.certs_len >> PAGE_SHIFT; 585 + memset(snp_dev->certs_data, 0, req->certs_len); 586 + npages = req->certs_len >> PAGE_SHIFT; 592 587 cmd: 593 588 /* 594 589 * The intermediate response buffer is used while decrypting the ··· 602 597 603 598 snp_dev->input.data_npages = npages; 604 599 ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg, 605 - SNP_MSG_REPORT_REQ, &req.data, 606 - sizeof(req.data), resp->data, resp_len); 600 + SNP_MSG_REPORT_REQ, &req->data, 601 + sizeof(req->data), resp->data, resp_len); 607 602 608 603 /* If certs length is invalid then copy the returned length */ 609 604 if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) { 610 - req.certs_len = snp_dev->input.data_npages << PAGE_SHIFT; 605 + req->certs_len = snp_dev->input.data_npages << PAGE_SHIFT; 611 606 612 - if (copy_to_user((void __user *)arg->req_data, &req, sizeof(req))) 607 + if (copy_to_user((void __user *)arg->req_data, req, sizeof(*req))) 613 608 ret = -EFAULT; 614 609 } 615 610 ··· 617 612 goto e_free; 618 613 619 614 if (npages && 620 - copy_to_user((void __user *)req.certs_address, snp_dev->certs_data, 621 - req.certs_len)) { 615 + copy_to_user((void __user *)req->certs_address, snp_dev->certs_data, 616 + req->certs_len)) { 622 617 ret = -EFAULT; 623 618 goto e_free; 624 619 }