lkml.org 
[lkml]   [2021]   [Apr]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectRe: [PATCH v2 8/8] KVM: SVM: Allocate SEV command structures on local stack
From
Date


Le 07/04/2021 à 00:49, Sean Christopherson a écrit :
> Use the local stack to "allocate" the structures used to communicate with
> the PSP. The largest struct used by KVM, sev_data_launch_secret, clocks
> in at 52 bytes, well within the realm of reasonable stack usage. The
> smallest structs are a mere 4 bytes, i.e. the pointer for the allocation
> is larger than the allocation itself.
>
> Now that the PSP driver plays nice with vmalloc pointers, putting the
> data on a virtually mapped stack (CONFIG_VMAP_STACK=y) will not cause
> explosions.
>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
> arch/x86/kvm/svm/sev.c | 262 +++++++++++++++--------------------------
> 1 file changed, 96 insertions(+), 166 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 5457138c7347..316fd39c7aef 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -150,35 +150,22 @@ static void sev_asid_free(int asid)
>
> static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
> {
> - struct sev_data_decommission *decommission;
> - struct sev_data_deactivate *data;
> + struct sev_data_decommission decommission;
> + struct sev_data_deactivate deactivate;
>
> if (!handle)
> return;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL);
> - if (!data)
> - return;
> -
> - /* deactivate handle */
> - data->handle = handle;
> + deactivate.handle = handle;
>
> /* Guard DEACTIVATE against WBINVD/DF_FLUSH used in ASID recycling */
> down_read(&sev_deactivate_lock);
> - sev_guest_deactivate(data, NULL);
> + sev_guest_deactivate(&deactivate, NULL);
> up_read(&sev_deactivate_lock);
>
> - kfree(data);
> -
> - decommission = kzalloc(sizeof(*decommission), GFP_KERNEL);
> - if (!decommission)
> - return;
> -
> /* decommission handle */
> - decommission->handle = handle;
> - sev_guest_decommission(decommission, NULL);
> -
> - kfree(decommission);
> + decommission.handle = handle;
> + sev_guest_decommission(&decommission, NULL);
> }
>
> static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
> @@ -216,19 +203,14 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
>
> static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
> {
> - struct sev_data_activate *data;
> + struct sev_data_activate activate;
> int asid = sev_get_asid(kvm);
> int ret;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> -
> /* activate ASID on the given handle */
> - data->handle = handle;
> - data->asid = asid;
> - ret = sev_guest_activate(data, error);
> - kfree(data);
> + activate.handle = handle;
> + activate.asid = asid;
> + ret = sev_guest_activate(&activate, error);
>
> return ret;
> }
> @@ -258,7 +240,7 @@ static int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error)
> static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_launch_start *start;
> + struct sev_data_launch_start start;

struct sev_data_launch_start start = {0, 0, 0, 0, 0, 0, 0};

> struct kvm_sev_launch_start params;
> void *dh_blob, *session_blob;
> int *error = &argp->error;
> @@ -270,20 +252,16 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
> if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
> return -EFAULT;
>
> - start = kzalloc(sizeof(*start), GFP_KERNEL_ACCOUNT);
> - if (!start)
> - return -ENOMEM;
> + memset(&start, 0, sizeof(start));

Not needed.

>
> dh_blob = NULL;
> if (params.dh_uaddr) {
> dh_blob = psp_copy_user_blob(params.dh_uaddr, params.dh_len);
> - if (IS_ERR(dh_blob)) {
> - ret = PTR_ERR(dh_blob);
> - goto e_free;
> - }
> + if (IS_ERR(dh_blob))
> + return PTR_ERR(dh_blob);
>
> - start->dh_cert_address = __sme_set(__pa(dh_blob));
> - start->dh_cert_len = params.dh_len;
> + start.dh_cert_address = __sme_set(__pa(dh_blob));
> + start.dh_cert_len = params.dh_len;
> }
>
> session_blob = NULL;
> @@ -294,40 +272,38 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
> goto e_free_dh;
> }
>
> - start->session_address = __sme_set(__pa(session_blob));
> - start->session_len = params.session_len;
> + start.session_address = __sme_set(__pa(session_blob));
> + start.session_len = params.session_len;
> }
>
> - start->handle = params.handle;
> - start->policy = params.policy;
> + start.handle = params.handle;
> + start.policy = params.policy;
>
> /* create memory encryption context */
> - ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, start, error);
> + ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, &start, error);
> if (ret)
> goto e_free_session;
>
> /* Bind ASID to this guest */
> - ret = sev_bind_asid(kvm, start->handle, error);
> + ret = sev_bind_asid(kvm, start.handle, error);
> if (ret)
> goto e_free_session;
>
> /* return handle to userspace */
> - params.handle = start->handle;
> + params.handle = start.handle;
> if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params))) {
> - sev_unbind_asid(kvm, start->handle);
> + sev_unbind_asid(kvm, start.handle);
> ret = -EFAULT;
> goto e_free_session;
> }
>
> - sev->handle = start->handle;
> + sev->handle = start.handle;
> sev->fd = argp->sev_fd;
>
> e_free_session:
> kfree(session_blob);
> e_free_dh:
> kfree(dh_blob);
> -e_free:
> - kfree(start);
> return ret;
> }
>
> @@ -446,7 +422,7 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
> unsigned long vaddr, vaddr_end, next_vaddr, npages, pages, size, i;
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> struct kvm_sev_launch_update_data params;
> - struct sev_data_launch_update_data *data;
> + struct sev_data_launch_update_data data;
> struct page **inpages;
> int ret;
>
> @@ -456,20 +432,14 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
> if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
> return -EFAULT;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> -
> vaddr = params.uaddr;
> size = params.len;
> vaddr_end = vaddr + size;
>
> /* Lock the user memory. */
> inpages = sev_pin_memory(kvm, vaddr, size, &npages, 1);
> - if (IS_ERR(inpages)) {
> - ret = PTR_ERR(inpages);
> - goto e_free;
> - }
> + if (IS_ERR(inpages))
> + return PTR_ERR(inpages);
>
> /*
> * Flush (on non-coherent CPUs) before LAUNCH_UPDATE encrypts pages in
> @@ -477,6 +447,9 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
> */
> sev_clflush_pages(inpages, npages);
>
> + data.reserved = 0;
> + data.handle = sev->handle;
> +
> for (i = 0; vaddr < vaddr_end; vaddr = next_vaddr, i += pages) {
> int offset, len;
>
> @@ -491,10 +464,9 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
>
> len = min_t(size_t, ((pages * PAGE_SIZE) - offset), size);
>
> - data->handle = sev->handle;
> - data->len = len;
> - data->address = __sme_page_pa(inpages[i]) + offset;
> - ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA, data, &argp->error);
> + data.len = len;
> + data.address = __sme_page_pa(inpages[i]) + offset;
> + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA, &data, &argp->error);
> if (ret)
> goto e_unpin;
>
> @@ -510,8 +482,6 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
> }
> /* unlock the user pages */
> sev_unpin_memory(kvm, inpages, npages);
> -e_free:
> - kfree(data);
> return ret;
> }
>
> @@ -563,16 +533,14 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm)
> static int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_launch_update_vmsa *vmsa;
> + struct sev_data_launch_update_vmsa vmsa;
> struct kvm_vcpu *vcpu;
> int i, ret;
>
> if (!sev_es_guest(kvm))
> return -ENOTTY;
>
> - vmsa = kzalloc(sizeof(*vmsa), GFP_KERNEL);
> - if (!vmsa)
> - return -ENOMEM;
> + vmsa.reserved = 0;
>
> kvm_for_each_vcpu(i, vcpu, kvm) {
> struct vcpu_svm *svm = to_svm(vcpu);
> @@ -580,7 +548,7 @@ static int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
> /* Perform some pre-encryption checks against the VMSA */
> ret = sev_es_sync_vmsa(svm);
> if (ret)
> - goto e_free;
> + return ret;
>
> /*
> * The LAUNCH_UPDATE_VMSA command will perform in-place
> @@ -590,27 +558,25 @@ static int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
> */
> clflush_cache_range(svm->vmsa, PAGE_SIZE);
>
> - vmsa->handle = sev->handle;
> - vmsa->address = __sme_pa(svm->vmsa);
> - vmsa->len = PAGE_SIZE;
> - ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_VMSA, vmsa,
> + vmsa.handle = sev->handle;
> + vmsa.address = __sme_pa(svm->vmsa);
> + vmsa.len = PAGE_SIZE;
> + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_VMSA, &vmsa,
> &argp->error);
> if (ret)
> - goto e_free;
> + return ret;
>
> svm->vcpu.arch.guest_state_protected = true;
> }
>
> -e_free:
> - kfree(vmsa);
> - return ret;
> + return 0;
> }
>
> static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> void __user *measure = (void __user *)(uintptr_t)argp->data;
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_launch_measure *data;
> + struct sev_data_launch_measure data;

struct sev_data_launch_measure data = {0, 0, 0, 0};

> struct kvm_sev_launch_measure params;
> void __user *p = NULL;
> void *blob = NULL;
> @@ -622,9 +588,7 @@ static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
> if (copy_from_user(&params, measure, sizeof(params)))
> return -EFAULT;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> + memset(&data, 0, sizeof(data));

Not needed

>
> /* User wants to query the blob length */
> if (!params.len)
> @@ -632,23 +596,20 @@ static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
>
> p = (void __user *)(uintptr_t)params.uaddr;
> if (p) {
> - if (params.len > SEV_FW_BLOB_MAX_SIZE) {
> - ret = -EINVAL;
> - goto e_free;
> - }
> + if (params.len > SEV_FW_BLOB_MAX_SIZE)
> + return -EINVAL;
>
> - ret = -ENOMEM;
> blob = kmalloc(params.len, GFP_KERNEL_ACCOUNT);
> if (!blob)
> - goto e_free;
> + return -ENOMEM;
>
> - data->address = __psp_pa(blob);
> - data->len = params.len;
> + data.address = __psp_pa(blob);
> + data.len = params.len;
> }
>
> cmd:
> - data->handle = sev->handle;
> - ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_MEASURE, data, &argp->error);
> + data.handle = sev->handle;
> + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_MEASURE, &data, &argp->error);
>
> /*
> * If we query the session length, FW responded with expected data.
> @@ -665,63 +626,50 @@ static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
> }
>
> done:
> - params.len = data->len;
> + params.len = data.len;
> if (copy_to_user(measure, &params, sizeof(params)))
> ret = -EFAULT;
> e_free_blob:
> kfree(blob);
> -e_free:
> - kfree(data);
> return ret;
> }
>
> static int sev_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_launch_finish *data;
> - int ret;
> + struct sev_data_launch_finish data;
>
> if (!sev_guest(kvm))
> return -ENOTTY;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> -
> - data->handle = sev->handle;
> - ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_FINISH, data, &argp->error);
> -
> - kfree(data);
> - return ret;
> + data.handle = sev->handle;
> + return sev_issue_cmd(kvm, SEV_CMD_LAUNCH_FINISH, &data, &argp->error);
> }
>
> static int sev_guest_status(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> struct kvm_sev_guest_status params;
> - struct sev_data_guest_status *data;
> + struct sev_data_guest_status data = {0, 0, 0, 0};
> int ret;
>
> if (!sev_guest(kvm))
> return -ENOTTY;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> + memset(&data, 0, sizeof(data));

not needed

>
> - data->handle = sev->handle;
> - ret = sev_issue_cmd(kvm, SEV_CMD_GUEST_STATUS, data, &argp->error);
> + data.handle = sev->handle;
> + ret = sev_issue_cmd(kvm, SEV_CMD_GUEST_STATUS, &data, &argp->error);
> if (ret)
> - goto e_free;
> + return ret;
>
> - params.policy = data->policy;
> - params.state = data->state;
> - params.handle = data->handle;
> + params.policy = data.policy;
> + params.state = data.state;
> + params.handle = data.handle;
>
> if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params)))
> ret = -EFAULT;
> -e_free:
> - kfree(data);
> +
> return ret;
> }
>
> @@ -730,23 +678,17 @@ static int __sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src,
> int *error, bool enc)
> {
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_dbg *data;
> - int ret;
> + struct sev_data_dbg data;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> + data.reserved = 0;
> + data.handle = sev->handle;
> + data.dst_addr = dst;
> + data.src_addr = src;
> + data.len = size;
>
> - data->handle = sev->handle;
> - data->dst_addr = dst;
> - data->src_addr = src;
> - data->len = size;
> -
> - ret = sev_issue_cmd(kvm,
> - enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT,
> - data, error);
> - kfree(data);
> - return ret;
> + return sev_issue_cmd(kvm,
> + enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT,
> + &data, error);
> }
>
> static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr,
> @@ -966,7 +908,7 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
> static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_launch_secret *data;
> + struct sev_data_launch_secret data;
> struct kvm_sev_launch_secret params;
> struct page **pages;
> void *blob, *hdr;
> @@ -998,41 +940,36 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
> goto e_unpin_memory;
> }
>
> - ret = -ENOMEM;
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - goto e_unpin_memory;
> + memset(&data, 0, sizeof(data));
>
> offset = params.guest_uaddr & (PAGE_SIZE - 1);
> - data->guest_address = __sme_page_pa(pages[0]) + offset;
> - data->guest_len = params.guest_len;
> + data.guest_address = __sme_page_pa(pages[0]) + offset;
> + data.guest_len = params.guest_len;
>
> blob = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
> if (IS_ERR(blob)) {
> ret = PTR_ERR(blob);
> - goto e_free;
> + goto e_unpin_memory;
> }
>
> - data->trans_address = __psp_pa(blob);
> - data->trans_len = params.trans_len;
> + data.trans_address = __psp_pa(blob);
> + data.trans_len = params.trans_len;
>
> hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
> if (IS_ERR(hdr)) {
> ret = PTR_ERR(hdr);
> goto e_free_blob;
> }
> - data->hdr_address = __psp_pa(hdr);
> - data->hdr_len = params.hdr_len;
> + data.hdr_address = __psp_pa(hdr);
> + data.hdr_len = params.hdr_len;
>
> - data->handle = sev->handle;
> - ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, data, &argp->error);
> + data.handle = sev->handle;
> + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, &data, &argp->error);
>
> kfree(hdr);
>
> e_free_blob:
> kfree(blob);
> -e_free:
> - kfree(data);
> e_unpin_memory:
> /* content of memory is updated, mark pages dirty */
> for (i = 0; i < n; i++) {
> @@ -1047,7 +984,7 @@ static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> void __user *report = (void __user *)(uintptr_t)argp->data;
> struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> - struct sev_data_attestation_report *data;
> + struct sev_data_attestation_report data;
> struct kvm_sev_attestation_report params;
> void __user *p;
> void *blob = NULL;
> @@ -1059,9 +996,7 @@ static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd *argp)
> if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
> return -EFAULT;
>
> - data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> - if (!data)
> - return -ENOMEM;
> + memset(&data, 0, sizeof(data));
>
> /* User wants to query the blob length */
> if (!params.len)
> @@ -1069,23 +1004,20 @@ static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd *argp)
>
> p = (void __user *)(uintptr_t)params.uaddr;
> if (p) {
> - if (params.len > SEV_FW_BLOB_MAX_SIZE) {
> - ret = -EINVAL;
> - goto e_free;
> - }
> + if (params.len > SEV_FW_BLOB_MAX_SIZE)
> + return -EINVAL;
>
> - ret = -ENOMEM;
> blob = kmalloc(params.len, GFP_KERNEL_ACCOUNT);
> if (!blob)
> - goto e_free;
> + return -ENOMEM;
>
> - data->address = __psp_pa(blob);
> - data->len = params.len;
> - memcpy(data->mnonce, params.mnonce, sizeof(params.mnonce));
> + data.address = __psp_pa(blob);
> + data.len = params.len;
> + memcpy(data.mnonce, params.mnonce, sizeof(params.mnonce));
> }
> cmd:
> - data->handle = sev->handle;
> - ret = sev_issue_cmd(kvm, SEV_CMD_ATTESTATION_REPORT, data, &argp->error);
> + data.handle = sev->handle;
> + ret = sev_issue_cmd(kvm, SEV_CMD_ATTESTATION_REPORT, &data, &argp->error);
> /*
> * If we query the session length, FW responded with expected data.
> */
> @@ -1101,13 +1033,11 @@ static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd *argp)
> }
>
> done:
> - params.len = data->len;
> + params.len = data.len;
> if (copy_to_user(report, &params, sizeof(params)))
> ret = -EFAULT;
> e_free_blob:
> kfree(blob);
> -e_free:
> - kfree(data);
> return ret;
> }
>
>

\
 
 \ /
  Last update: 2021-04-07 07:26    [W:0.195 / U:0.068 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site