linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] KVM/SVM: add support for SEV attestation command
@ 2020-12-04 21:28 Brijesh Singh
  2020-12-08 16:43 ` Tom Lendacky
  2020-12-09  7:51 ` Ard Biesheuvel
  0 siblings, 2 replies; 6+ messages in thread
From: Brijesh Singh @ 2020-12-04 21:28 UTC (permalink / raw)
  To: kvm
  Cc: linux-kernel, linux-doc, Brijesh Singh, James Bottomley,
	Tom Lendacky, David Rientjes, Paolo Bonzini, Sean Christopherson,
	Borislav Petkov, John Allen, Herbert Xu, linux-crypto

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@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../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(&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;
@@ -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)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM/SVM: add support for SEV attestation command
  2020-12-04 21:28 [PATCH] KVM/SVM: add support for SEV attestation command Brijesh Singh
@ 2020-12-08 16:43 ` Tom Lendacky
  2020-12-09  7:51 ` Ard Biesheuvel
  1 sibling, 0 replies; 6+ messages in thread
From: Tom Lendacky @ 2020-12-08 16:43 UTC (permalink / raw)
  To: Brijesh Singh, kvm
  Cc: linux-kernel, linux-doc, James Bottomley, David Rientjes,
	Paolo Bonzini, Sean Christopherson, Borislav Petkov, John Allen,
	Herbert Xu, linux-crypto

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@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>

Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>

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(&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;
> @@ -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)
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM/SVM: add support for SEV attestation command
  2020-12-04 21:28 [PATCH] KVM/SVM: add support for SEV attestation command Brijesh Singh
  2020-12-08 16:43 ` Tom Lendacky
@ 2020-12-09  7:51 ` Ard Biesheuvel
  2020-12-10  3:25   ` Brijesh Singh
  1 sibling, 1 reply; 6+ messages in thread
From: Ard Biesheuvel @ 2020-12-09  7:51 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: kvm, Linux Kernel Mailing List, Linux Doc Mailing List,
	James Bottomley, Tom Lendacky, David Rientjes, Paolo Bonzini,
	Sean Christopherson, Borislav Petkov, John Allen, Herbert Xu,
	Linux Crypto Mailing List

On Fri, 4 Dec 2020 at 22:30, Brijesh Singh <brijesh.singh@amd.com> 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

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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  .../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

KVM_SEV_GET_ATTESTATION_REPORT

> +---------------------------------
> +
> +The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to query the attestation

KVM_SEV_GET_ATTESTATION_REPORT

> +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(&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;
> @@ -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)
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM/SVM: add support for SEV attestation command
  2020-12-09  7:51 ` Ard Biesheuvel
@ 2020-12-10  3:25   ` Brijesh Singh
  2020-12-10 23:28     ` David Rientjes
  2020-12-13 22:28     ` James Bottomley
  0 siblings, 2 replies; 6+ messages in thread
From: Brijesh Singh @ 2020-12-10  3:25 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: brijesh.singh, kvm, Linux Kernel Mailing List,
	Linux Doc Mailing List, James Bottomley, Tom Lendacky,
	David Rientjes, Paolo Bonzini, Sean Christopherson,
	Borislav Petkov, John Allen, Herbert Xu,
	Linux Crypto Mailing List


On 12/9/20 1:51 AM, Ard Biesheuvel wrote:
> On Fri, 4 Dec 2020 at 22:30, Brijesh Singh <brijesh.singh@amd.com> 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
> 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
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>>  .../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
> KVM_SEV_GET_ATTESTATION_REPORT
>
>> +---------------------------------
>> +
>> +The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to query the attestation
> KVM_SEV_GET_ATTESTATION_REPORT


Noted, I will send v2 with these fixed.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM/SVM: add support for SEV attestation command
  2020-12-10  3:25   ` Brijesh Singh
@ 2020-12-10 23:28     ` David Rientjes
  2020-12-13 22:28     ` James Bottomley
  1 sibling, 0 replies; 6+ messages in thread
From: David Rientjes @ 2020-12-10 23:28 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: Ard Biesheuvel, kvm, Linux Kernel Mailing List,
	Linux Doc Mailing List, James Bottomley, Tom Lendacky,
	Paolo Bonzini, Sean Christopherson, Borislav Petkov, John Allen,
	Herbert Xu, Linux Crypto Mailing List

On Wed, 9 Dec 2020, Brijesh Singh wrote:

> Noted, I will send v2 with these fixed.
> 

And with those changes:

Acked-by: David Rientjes <rientjes@google.com>

Thanks Brijesh!

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM/SVM: add support for SEV attestation command
  2020-12-10  3:25   ` Brijesh Singh
  2020-12-10 23:28     ` David Rientjes
@ 2020-12-13 22:28     ` James Bottomley
  1 sibling, 0 replies; 6+ messages in thread
From: James Bottomley @ 2020-12-13 22:28 UTC (permalink / raw)
  To: Brijesh Singh, Ard Biesheuvel
  Cc: kvm, Linux Kernel Mailing List, Linux Doc Mailing List,
	Tom Lendacky, David Rientjes, Paolo Bonzini, Sean Christopherson,
	Borislav Petkov, John Allen, Herbert Xu,
	Linux Crypto Mailing List

On Wed, 2020-12-09 at 21:25 -0600, Brijesh Singh wrote:
> Noted, I will send v2 with these fixed.

I ran a test on this.  It turns out for rome systems you need firmware
md_sev_fam17h_model3xh_0.24b0A (or later) installed to get this and the
QEMU patch with the base64 decoding fixed, but with that

Tested-by: James Bottomley <jejb@linux.ibm.com>

Attached is the test programme I used.

James

---

#!/usr/bin/python3
##
# Python script get an attestation and verify it with the PEK
#
# This assumes you've already exported the pek.cert with sev-tool
# from https://github.com/AMDESE/sev-tool.git
#
# sev-tool --export_cert_chain
#
# creates several files, the only one this script needs is pek.cert
#
# Tables and chapters refer to the amd 55766.pdf document
#
# https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
##
import sys
import os 
import base64
import hashlib
from argparse import ArgumentParser
from Crypto.PublicKey import ECC
from Crypto.Math.Numbers import Integer
from git.qemu.python.qemu import qmp

if __name__ == "__main__":
    parser = ArgumentParser(description='Inject secret into SEV')
    parser.add_argument('--pek-cert',
                        help='The Platform DH certificate in binary form',
                        default='pek.cert')
    parser.add_argument('--socket',
                        help='Socket to connect to QMP on, defaults to localhost:6550',
                        default='localhost:6550')
    args = parser.parse_args()

    if (args.socket[0] == '/'):
        socket = args.socket
    elif (':' in args.socket):
        s = args.socket.split(':')
        socket = (s[0], int(s[1]))
    else:
        parse.error('--socket must be <host>:<port> or /path/to/unix')

    fh = open(args.pek_cert, 'rb')
    pek = bytearray(fh.read())
    curve = int.from_bytes(pek[16:20], byteorder='little')
    curves = {
        1: 'p256',
        2: 'p384'
        }
    Qx = int.from_bytes(bytes(pek[20:92]), byteorder='little')
    Qy = int.from_bytes(bytes(pek[92:164]), byteorder='little')

    pubkey = ECC.construct(point_x=Qx, point_y=Qy, curve=curves[curve])

    Qmp = qmp.QEMUMonitorProtocol(address=socket);
    Qmp.connect()
    caps = Qmp.command('query-sev')
    print('SEV query found API={api-major}.{api-minor} build={build-id} policy={policy}\n'.format(**caps))

    nonce=os.urandom(16)

    report = Qmp.command('query-sev-attestation-report',
                         mnonce=base64.b64encode(nonce).decode())

    a = base64.b64decode(report['data'])

    ##
    # returned data is formulated as Table 60. Attestation Report Buffer
    ##
    rnonce = a[0:16]
    rmeas = a[16:48]

    if (nonce != rnonce):
        sys.exit('returned nonce doesn\'t match input nonce')

    policy = int.from_bytes(a[48:52], byteorder='little')
    usage = int.from_bytes(a[52:56], byteorder='little')
    algo = int.from_bytes(a[56:60], byteorder='little')

    if (policy != caps['policy']):
        sys.exit('Policy mismatch:', policy, '!=', caps['policy'])

    if (usage != 0x1002):
        sys.exit('error PEK is not specified in usage: ', usage)

    if (algo == 0x2):
        h = hashlib.sha256()
    elif (algo == 0x102):
        ##
        # The spec (6.8) says the signature must be ECDSA-SHA256 so this
        # should be impossible, but it turns out to be the way our
        # current test hardware produces its signature
        ##
        h = hashlib.sha384()
    else:
        sys.exit('unrecognized signing algorithm: ', algo)

    h.update(a[0:52])

    sig = a[64:208]
    r = int.from_bytes(sig[0:72],byteorder='little')
    s = int.from_bytes(sig[72:144],byteorder='little')
    ##
    # subtlety: r and s are little (AMD defined) z is big (crypto requirement)
    ##
    z = int.from_bytes(h.digest(), byteorder='big')

    ##
    # python crypto doesn't have a way of passing in r and s as
    # integers and I'm not inclined to wrap them up as a big endian
    # binary signature to have Signature.DSS unwrap them again, so
    # call the _verify() private interface that does take integers
    ##
    if (not pubkey._verify(Integer(z), (Integer(r), Integer(s)))):
        sys.exit('returned signature did not verify')

    print('usage={usage}, algorithm={algo}'.format(usage=hex(usage),
                                                   algo=hex(algo)))
    print('ovmf-hash: ', rmeas.hex())


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-12-13 22:30 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-04 21:28 [PATCH] KVM/SVM: add support for SEV attestation command Brijesh Singh
2020-12-08 16:43 ` Tom Lendacky
2020-12-09  7:51 ` Ard Biesheuvel
2020-12-10  3:25   ` Brijesh Singh
2020-12-10 23:28     ` David Rientjes
2020-12-13 22:28     ` James Bottomley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).