KVM/SVM: add support for SEV attestation command
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 latter can be called while the guest is running and the measurement value is signed with PEK. Cc: James Bottomley <jejb@linux.ibm.com> Cc: Tom Lendacky <Thomas.Lendacky@amd.com> Cc: David Rientjes <rientjes@google.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Borislav Petkov <bp@alien8.de> Cc: John Allen <john.allen@amd.com> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: linux-crypto@vger.kernel.org Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com> Acked-by: David Rientjes <rientjes@google.com> Tested-by: James Bottomley <jejb@linux.ibm.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> Message-Id: <20210104151749.30248-1-brijesh.singh@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Родитель
c1d1650f55
Коммит
2c07ded064
|
@ -263,6 +263,27 @@ Returns: 0 on success, -negative on error
|
|||
__u32 trans_len;
|
||||
};
|
||||
|
||||
10. KVM_SEV_GET_ATTESTATION_REPORT
|
||||
----------------------------------
|
||||
|
||||
The KVM_SEV_GET_ATTESTATION_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
|
||||
==========
|
||||
|
||||
|
|
|
@ -1041,6 +1041,74 @@ e_unpin_memory:
|
|||
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;
|
||||
|
@ -1091,6 +1159,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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -1593,6 +1593,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,
|
||||
};
|
||||
|
@ -1645,6 +1647,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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче