On 12/4/20 3:28 PM, Brijesh Singh wrote: > The SEV FW version >= 0.23 added a new command that can be used to query > the attestation report containing the SHA-256 digest of the guest memory > encrypted through the KVM_SEV_LAUNCH_UPDATE_{DATA, VMSA} commands and > sign the report with the Platform Endorsement Key (PEK). > > See the SEV FW API spec section 6.8 for more details. > > Note there already exist a command (KVM_SEV_LAUNCH_MEASURE) that can be > used to get the SHA-256 digest. The main difference between the > KVM_SEV_LAUNCH_MEASURE and KVM_SEV_ATTESTATION_REPORT is that the later > can be called while the guest is running and the measurement value is > signed with PEK. > > Cc: James Bottomley <jejb@xxxxxxxxxxxxx> > Cc: Tom Lendacky <Thomas.Lendacky@xxxxxxx> > Cc: David Rientjes <rientjes@xxxxxxxxxx> > Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> > Cc: Sean Christopherson <seanjc@xxxxxxxxxx> > Cc: Borislav Petkov <bp@xxxxxxxxx> > Cc: John Allen <john.allen@xxxxxxx> > Cc: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> > Cc: linux-crypto@xxxxxxxxxxxxxxx > Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx> Reviewed-by: Tom Lendacky <thomas.lendacky@xxxxxxx> Not sure if Paolo or Herbert would like the crypto/psp changes to be split out from the kvm changes as separate patches or not. Thanks, Tom > --- > .../virt/kvm/amd-memory-encryption.rst | 21 ++++++ > arch/x86/kvm/svm/sev.c | 71 +++++++++++++++++++ > drivers/crypto/ccp/sev-dev.c | 1 + > include/linux/psp-sev.h | 17 +++++ > include/uapi/linux/kvm.h | 8 +++ > 5 files changed, 118 insertions(+) > > diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst > index 09a8f2a34e39..4c6685d0fddd 100644 > --- a/Documentation/virt/kvm/amd-memory-encryption.rst > +++ b/Documentation/virt/kvm/amd-memory-encryption.rst > @@ -263,6 +263,27 @@ Returns: 0 on success, -negative on error > __u32 trans_len; > }; > > +10. KVM_SEV_GET_ATTESATION_REPORT > +--------------------------------- > + > +The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to query the attestation > +report containing the SHA-256 digest of the guest memory and VMSA passed through the KVM_SEV_LAUNCH > +commands and signed with the PEK. The digest returned by the command should match the digest > +used by the guest owner with the KVM_SEV_LAUNCH_MEASURE. > + > +Parameters (in): struct kvm_sev_attestation > + > +Returns: 0 on success, -negative on error > + > +:: > + > + struct kvm_sev_attestation_report { > + __u8 mnonce[16]; /* A random mnonce that will be placed in the report */ > + > + __u64 uaddr; /* userspace address where the report should be copied */ > + __u32 len; > + }; > + > References > ========== > > diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c > index 566f4d18185b..c4d3ee6be362 100644 > --- a/arch/x86/kvm/svm/sev.c > +++ b/arch/x86/kvm/svm/sev.c > @@ -927,6 +927,74 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp) > return ret; > } > > +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 kvm_sev_attestation_report params; > + void __user *p; > + void *blob = NULL; > + int ret; > + > + if (!sev_guest(kvm)) > + return -ENOTTY; > + > + if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data, sizeof(params))) > + return -EFAULT; > + > + data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT); > + if (!data) > + return -ENOMEM; > + > + /* User wants to query the blob length */ > + if (!params.len) > + goto cmd; > + > + p = (void __user *)(uintptr_t)params.uaddr; > + if (p) { > + if (params.len > SEV_FW_BLOB_MAX_SIZE) { > + ret = -EINVAL; > + goto e_free; > + } > + > + ret = -ENOMEM; > + blob = kmalloc(params.len, GFP_KERNEL); > + if (!blob) > + goto e_free; > + > + 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); > + /* > + * If we query the session length, FW responded with expected data. > + */ > + if (!params.len) > + goto done; > + > + if (ret) > + goto e_free_blob; > + > + if (blob) { > + if (copy_to_user(p, blob, params.len)) > + ret = -EFAULT; > + } > + > +done: > + params.len = data->len; > + if (copy_to_user(report, ¶ms, sizeof(params))) > + ret = -EFAULT; > +e_free_blob: > + kfree(blob); > +e_free: > + kfree(data); > + return ret; > +} > + > int svm_mem_enc_op(struct kvm *kvm, void __user *argp) > { > struct kvm_sev_cmd sev_cmd; > @@ -971,6 +1039,9 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp) > case KVM_SEV_LAUNCH_SECRET: > r = sev_launch_secret(kvm, &sev_cmd); > break; > + case KVM_SEV_GET_ATTESTATION_REPORT: > + r = sev_get_attestation_report(kvm, &sev_cmd); > + break; > default: > r = -EINVAL; > goto out; > diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c > index 476113e12489..cb9b4c4e371e 100644 > --- a/drivers/crypto/ccp/sev-dev.c > +++ b/drivers/crypto/ccp/sev-dev.c > @@ -128,6 +128,7 @@ static int sev_cmd_buffer_len(int cmd) > case SEV_CMD_LAUNCH_UPDATE_SECRET: return sizeof(struct sev_data_launch_secret); > case SEV_CMD_DOWNLOAD_FIRMWARE: return sizeof(struct sev_data_download_firmware); > case SEV_CMD_GET_ID: return sizeof(struct sev_data_get_id); > + case SEV_CMD_ATTESTATION_REPORT: return sizeof(struct sev_data_attestation_report); > default: return 0; > } > > diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h > index 49d155cd2dfe..b801ead1e2bb 100644 > --- a/include/linux/psp-sev.h > +++ b/include/linux/psp-sev.h > @@ -66,6 +66,7 @@ enum sev_cmd { > SEV_CMD_LAUNCH_MEASURE = 0x033, > SEV_CMD_LAUNCH_UPDATE_SECRET = 0x034, > SEV_CMD_LAUNCH_FINISH = 0x035, > + SEV_CMD_ATTESTATION_REPORT = 0x036, > > /* Guest migration commands (outgoing) */ > SEV_CMD_SEND_START = 0x040, > @@ -483,6 +484,22 @@ struct sev_data_dbg { > u32 len; /* In */ > } __packed; > > +/** > + * struct sev_data_attestation_report - SEV_ATTESTATION_REPORT command parameters > + * > + * @handle: handle of the VM > + * @mnonce: a random nonce that will be included in the report. > + * @address: physical address where the report will be copied. > + * @len: length of the physical buffer. > + */ > +struct sev_data_attestation_report { > + u32 handle; /* In */ > + u32 reserved; > + u64 address; /* In */ > + u8 mnonce[16]; /* In */ > + u32 len; /* In/Out */ > +} __packed; > + > #ifdef CONFIG_CRYPTO_DEV_SP_PSP > > /** > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index ca41220b40b8..d3385f7f08a2 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -1585,6 +1585,8 @@ enum sev_cmd_id { > KVM_SEV_DBG_ENCRYPT, > /* Guest certificates commands */ > KVM_SEV_CERT_EXPORT, > + /* Attestation report */ > + KVM_SEV_GET_ATTESTATION_REPORT, > > KVM_SEV_NR_MAX, > }; > @@ -1637,6 +1639,12 @@ struct kvm_sev_dbg { > __u32 len; > }; > > +struct kvm_sev_attestation_report { > + __u8 mnonce[16]; > + __u64 uaddr; > + __u32 len; > +}; > + > #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) > #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) > #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) >