On Wed, Apr 24, 2019 at 04:09:59PM +0000, Singh, Brijesh wrote: > The command is used to create an outgoing SEV guest encryption context. > > Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> > Cc: Ingo Molnar <mingo@xxxxxxxxxx> > Cc: "H. Peter Anvin" <hpa@xxxxxxxxx> > Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> > Cc: "Radim Krčmář" <rkrcmar@xxxxxxxxxx> > Cc: Joerg Roedel <joro@xxxxxxxxxx> > Cc: Borislav Petkov <bp@xxxxxxx> > Cc: Tom Lendacky <thomas.lendacky@xxxxxxx> > Cc: x86@xxxxxxxxxx > Cc: kvm@xxxxxxxxxxxxxxx > Cc: linux-kernel@xxxxxxxxxxxxxxx > Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx> > --- > .../virtual/kvm/amd-memory-encryption.rst | 24 +++++ > arch/x86/kvm/svm.c | 101 ++++++++++++++++++ > include/uapi/linux/kvm.h | 12 +++ > 3 files changed, 137 insertions(+) > > diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst > index 659bbc093b52..340ac4f87321 100644 > --- a/Documentation/virtual/kvm/amd-memory-encryption.rst > +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst > @@ -238,6 +238,30 @@ Returns: 0 on success, -negative on error > __u32 trans_len; > }; > > +10. KVM_SEV_SEND_START > +---------------------- > + > +The KVM_SEV_SEND_START command can be used by the hypervisor to create an > +outgoing guest encryption context. > + > +Parameters (in): struct kvm_sev_send_start > + > +Returns: 0 on success, -negative on error > + > +:: > + struct kvm_sev_send_start { > + __u32 policy; /* guest policy */ > + > + __u64 pdh_cert_uaddr; /* platform Diffie-Hellman certificate */ > + __u32 pdh_cert_len; > + > + __u64 plat_cert_uaddr; /* platform certificate chain */ > + __u32 plat_cert_len; > + > + __u64 amd_cert_uaddr; /* AMD certificate */ > + __u32 amd_cert_len; __u64 session_uaddr; __u32 session_len; too, right? > + }; > + > References > ========== > > diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c > index 406b558abfef..4c2a225ba546 100644 > --- a/arch/x86/kvm/svm.c > +++ b/arch/x86/kvm/svm.c > @@ -6955,6 +6955,104 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp) > return ret; > } > > +static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp) > +{ > + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; > + void *amd_cert = NULL, *session_data = NULL; > + void *pdh_cert = NULL, *plat_cert = NULL; > + struct sev_data_send_start *data = NULL; > + struct kvm_sev_send_start params; > + int ret; > + > + if (!sev_guest(kvm)) > + return -ENOTTY; > + > + if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data, > + sizeof(struct kvm_sev_send_start))) > + return -EFAULT; > + > + data = kzalloc(sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + /* userspace wants to query the session length */ > + if (!params.session_len) > + goto cmd; > + > + if (!params.pdh_cert_uaddr || !params.pdh_cert_len || > + !params.session_uaddr) > + return -EINVAL; > + > + /* copy the certificate blobs from userspace */ > + pdh_cert = psp_copy_user_blob(params.pdh_cert_uaddr, params.pdh_cert_len); > + if (IS_ERR(pdh_cert)) { > + ret = PTR_ERR(pdh_cert); > + goto e_free; > + } > + > + data->pdh_cert_address = __psp_pa(pdh_cert); > + data->pdh_cert_len = params.pdh_cert_len; > + > + plat_cert = psp_copy_user_blob(params.plat_cert_uaddr, params.plat_cert_len); > + if (IS_ERR(plat_cert)) { > + ret = PTR_ERR(plat_cert); > + goto e_free_pdh; > + } > + > + data->plat_cert_address = __psp_pa(plat_cert); > + data->plat_cert_len = params.plat_cert_len; > + > + amd_cert = psp_copy_user_blob(params.amd_cert_uaddr, params.amd_cert_len); > + if (IS_ERR(amd_cert)) { > + ret = PTR_ERR(amd_cert); > + goto e_free_plat_cert; > + } > + > + data->amd_cert_address = __psp_pa(amd_cert); > + data->amd_cert_len = params.amd_cert_len; > + > + ret = -ENOMEM; > + session_data = kmalloc(params.session_len, GFP_KERNEL); If the user is supposed to query the session length first, you could save it in a global variable perhaps and use that value instead of trusting the user to give you the correct one in params.session_len for the allocation... > + if (!session_data) > + goto e_free_amd_cert; > + > + data->session_address = __psp_pa(session_data); > + data->session_len = params.session_len; > +cmd: > + data->handle = sev->handle; > + ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, data, &argp->error); > + > + /* if we queried the session length, FW responded with expected data */ <--- ... here you have the session length from the fw. -- Regards/Gruss, Boris. Good mailing practices for 400: avoid top-posting and trim the reply.