Skip to content

Commit

Permalink
KVM/SVM: add support for SEV attestation command
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
codomania authored and bonzini committed Feb 4, 2021
1 parent c1d1650 commit 2c07ded
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 0 deletions.
21 changes: 21 additions & 0 deletions Documentation/virt/kvm/amd-memory-encryption.rst
Expand Up @@ -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
==========

Expand Down
71 changes: 71 additions & 0 deletions arch/x86/kvm/svm/sev.c
Expand Up @@ -1041,6 +1041,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(&params, (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, &params, 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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/crypto/ccp/sev-dev.c
Expand Up @@ -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;
}

Expand Down
17 changes: 17 additions & 0 deletions include/linux/psp-sev.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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

/**
Expand Down
8 changes: 8 additions & 0 deletions include/uapi/linux/kvm.h
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 2c07ded

Please sign in to comment.