virt: sevguest: Prep for kernel internal get_ext_report()
In preparation for using the configs-tsm facility to convey attestation blobs to userspace, switch to using the 'sockptr' api for copying payloads to provided buffers where 'sockptr' handles user vs kernel buffers. While configfs-tsm is meant to replace existing confidential computing ioctl() implementations for attestation report retrieval the old ioctl() path needs to stick around for a deprecation period. No behavior change intended. Cc: Borislav Petkov <bp@alien8.de> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Dionna Glaze <dionnaglaze@google.com> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.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>
This commit is contained in:
parent
70e6f7e2b9
commit
2df2135366
@ -19,6 +19,7 @@
|
||||
#include <crypto/aead.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/psp-sev.h>
|
||||
#include <linux/sockptr.h>
|
||||
#include <uapi/linux/sev-guest.h>
|
||||
#include <uapi/linux/psp-sev.h>
|
||||
|
||||
@ -475,6 +476,11 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snp_req_resp {
|
||||
sockptr_t req_data;
|
||||
sockptr_t resp_data;
|
||||
};
|
||||
|
||||
static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
|
||||
{
|
||||
struct snp_guest_crypto *crypto = snp_dev->crypto;
|
||||
@ -555,22 +561,25 @@ 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,
|
||||
struct snp_req_resp *io)
|
||||
|
||||
{
|
||||
struct snp_ext_report_req *req = &snp_dev->req.ext_report;
|
||||
struct snp_guest_crypto *crypto = snp_dev->crypto;
|
||||
struct snp_report_resp *resp;
|
||||
int ret, npages = 0, resp_len;
|
||||
sockptr_t certs_address;
|
||||
|
||||
lockdep_assert_held(&snp_cmd_mutex);
|
||||
|
||||
if (!arg->req_data || !arg->resp_data)
|
||||
if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(req, (void __user *)arg->req_data, sizeof(*req)))
|
||||
if (copy_from_sockptr(req, io->req_data, sizeof(*req)))
|
||||
return -EFAULT;
|
||||
|
||||
/* userspace does not want certificate data */
|
||||
/* caller does not want certificate data */
|
||||
if (!req->certs_len || !req->certs_address)
|
||||
goto cmd;
|
||||
|
||||
@ -578,8 +587,13 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
|
||||
!IS_ALIGNED(req->certs_len, PAGE_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
if (!access_ok((const void __user *)req->certs_address, req->certs_len))
|
||||
return -EFAULT;
|
||||
if (sockptr_is_kernel(io->resp_data)) {
|
||||
certs_address = KERNEL_SOCKPTR((void *)req->certs_address);
|
||||
} else {
|
||||
certs_address = USER_SOCKPTR((void __user *)req->certs_address);
|
||||
if (!access_ok(certs_address.user, req->certs_len))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the intermediate buffer with all zeros. This buffer
|
||||
@ -609,21 +623,19 @@ cmd:
|
||||
if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) {
|
||||
req->certs_len = snp_dev->input.data_npages << PAGE_SHIFT;
|
||||
|
||||
if (copy_to_user((void __user *)arg->req_data, req, sizeof(*req)))
|
||||
if (copy_to_sockptr(io->req_data, req, sizeof(*req)))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
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_sockptr(certs_address, snp_dev->certs_data, req->certs_len)) {
|
||||
ret = -EFAULT;
|
||||
goto e_free;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *)arg->resp_data, resp, sizeof(*resp)))
|
||||
if (copy_to_sockptr(io->resp_data, resp, sizeof(*resp)))
|
||||
ret = -EFAULT;
|
||||
|
||||
e_free:
|
||||
@ -636,6 +648,7 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long
|
||||
struct snp_guest_dev *snp_dev = to_snp_dev(file);
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct snp_guest_request_ioctl input;
|
||||
struct snp_req_resp io;
|
||||
int ret = -ENOTTY;
|
||||
|
||||
if (copy_from_user(&input, argp, sizeof(input)))
|
||||
@ -664,7 +677,14 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long
|
||||
ret = get_derived_key(snp_dev, &input);
|
||||
break;
|
||||
case SNP_GET_EXT_REPORT:
|
||||
ret = get_ext_report(snp_dev, &input);
|
||||
/*
|
||||
* As get_ext_report() may be called from the ioctl() path and a
|
||||
* kernel internal path (configfs-tsm), decorate the passed
|
||||
* buffers as user pointers.
|
||||
*/
|
||||
io.req_data = USER_SOCKPTR((void __user *)input.req_data);
|
||||
io.resp_data = USER_SOCKPTR((void __user *)input.resp_data);
|
||||
ret = get_ext_report(snp_dev, &input, &io);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user