[PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests

Nikunj A Dadhania posted 13 patches 4 weeks ago
[PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A Dadhania 4 weeks ago
Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests
to securely use RDTSC/RDTSCP instructions, ensuring that the parameters
used cannot be altered by the hypervisor once the guest is launched.

Secure TSC-enabled guests need to query TSC information from the AMD
Security Processor. This communication channel is encrypted between the AMD
Security Processor and the guest, with the hypervisor acting merely as a
conduit to deliver the guest messages to the AMD Security Processor. Each
message is protected with AEAD (AES-256 GCM). Use a minimal AES GCM library
to encrypt and decrypt SNP guest messages for communication with the PSP.

Use mem_encrypt_init() to fetch SNP TSC information from the AMD Security
Processor and initialize snp_tsc_scale and snp_tsc_offset. During secondary
CPU initialization, set the VMSA fields GUEST_TSC_SCALE (offset 2F0h) and
GUEST_TSC_OFFSET (offset 2F8h) with snp_tsc_scale and snp_tsc_offset,
respectively.

Add confidential compute platform attribute CC_ATTR_GUEST_SNP_SECURE_TSC
that can be used by the guest to query whether the Secure TSC feature is
active.

Since handle_guest_request() is common routine used by both the SEV guest
driver and Secure TSC code, move it to the SEV header file.

Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
Tested-by: Peter Gonda <pgonda@google.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 arch/x86/include/asm/sev-common.h |  1 +
 arch/x86/include/asm/sev.h        | 46 ++++++++++++++++
 arch/x86/include/asm/svm.h        |  6 ++-
 include/linux/cc_platform.h       |  8 +++
 arch/x86/coco/core.c              |  3 ++
 arch/x86/coco/sev/core.c          | 90 +++++++++++++++++++++++++++++++
 arch/x86/mm/mem_encrypt.c         |  4 ++
 7 files changed, 156 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
index 50f5666938c0..6ef92432a5ce 100644
--- a/arch/x86/include/asm/sev-common.h
+++ b/arch/x86/include/asm/sev-common.h
@@ -206,6 +206,7 @@ struct snp_psc_desc {
 #define GHCB_TERM_NO_SVSM		7	/* SVSM is not advertised in the secrets page */
 #define GHCB_TERM_SVSM_VMPL0		8	/* SVSM is present but has set VMPL to 0 */
 #define GHCB_TERM_SVSM_CAA		9	/* SVSM is present but CAA is not page aligned */
+#define GHCB_TERM_SECURE_TSC		10	/* Secure TSC initialization failed */
 
 #define GHCB_RESP_CODE(v)		((v) & GHCB_MSR_INFO_MASK)
 
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 2c542b9e8dbf..d27c4e0f9f57 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -146,6 +146,9 @@ enum msg_type {
 	SNP_MSG_VMRK_REQ,
 	SNP_MSG_VMRK_RSP,
 
+	SNP_MSG_TSC_INFO_REQ = 17,
+	SNP_MSG_TSC_INFO_RSP,
+
 	SNP_MSG_TYPE_MAX
 };
 
@@ -174,6 +177,22 @@ struct snp_guest_msg {
 	u8 payload[PAGE_SIZE - sizeof(struct snp_guest_msg_hdr)];
 } __packed;
 
+#define SNP_TSC_INFO_REQ_SZ	128
+#define SNP_TSC_INFO_RESP_SZ	128
+
+struct snp_tsc_info_req {
+	u8 rsvd[SNP_TSC_INFO_REQ_SZ];
+} __packed;
+
+struct snp_tsc_info_resp {
+	u32 status;
+	u32 rsvd1;
+	u64 tsc_scale;
+	u64 tsc_offset;
+	u32 tsc_factor;
+	u8 rsvd2[100];
+} __packed;
+
 struct snp_guest_req {
 	void *req_buf;
 	size_t req_sz;
@@ -497,6 +516,27 @@ static inline void snp_msg_cleanup(struct snp_msg_desc *mdesc)
 int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
 			   struct snp_guest_request_ioctl *rio);
 
+static inline int handle_guest_request(struct snp_msg_desc *mdesc, u64 exit_code,
+				       struct snp_guest_request_ioctl *rio, u8 type,
+				       void *req_buf, size_t req_sz, void *resp_buf,
+				       u32 resp_sz)
+{
+	struct snp_guest_req req = {
+		.msg_version	= rio->msg_version,
+		.msg_type	= type,
+		.vmpck_id	= mdesc->vmpck_id,
+		.req_buf	= req_buf,
+		.req_sz		= req_sz,
+		.resp_buf	= resp_buf,
+		.resp_sz	= resp_sz,
+		.exit_code	= exit_code,
+	};
+
+	return snp_send_guest_request(mdesc, &req, rio);
+}
+
+void __init snp_secure_tsc_prepare(void);
+
 #else	/* !CONFIG_AMD_MEM_ENCRYPT */
 
 #define snp_vmpl 0
@@ -538,6 +578,12 @@ static inline struct snp_msg_desc *snp_msg_alloc(void) { return NULL; }
 static inline void snp_msg_cleanup(struct snp_msg_desc *mdesc) { }
 static inline int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
 					 struct snp_guest_request_ioctl *rio) { return -ENODEV; }
+static inline int handle_guest_request(struct snp_msg_desc *mdesc, u64 exit_code,
+				       struct snp_guest_request_ioctl *rio, u8 type,
+				       void *req_buf, size_t req_sz, void *resp_buf,
+				       u32 resp_sz) { return -ENODEV; }
+
+static inline void __init snp_secure_tsc_prepare(void) { }
 
 #endif	/* CONFIG_AMD_MEM_ENCRYPT */
 
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 2b59b9951c90..92e18798f197 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -417,7 +417,9 @@ struct sev_es_save_area {
 	u8 reserved_0x298[80];
 	u32 pkru;
 	u32 tsc_aux;
-	u8 reserved_0x2f0[24];
+	u64 tsc_scale;
+	u64 tsc_offset;
+	u8 reserved_0x300[8];
 	u64 rcx;
 	u64 rdx;
 	u64 rbx;
@@ -564,7 +566,7 @@ static inline void __unused_size_checks(void)
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x1c0);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x248);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x298);
-	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x2f0);
+	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x300);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x320);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x380);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x3f0);
diff --git a/include/linux/cc_platform.h b/include/linux/cc_platform.h
index caa4b4430634..cb7103dc124f 100644
--- a/include/linux/cc_platform.h
+++ b/include/linux/cc_platform.h
@@ -88,6 +88,14 @@ enum cc_attr {
 	 * enabled to run SEV-SNP guests.
 	 */
 	CC_ATTR_HOST_SEV_SNP,
+
+	/**
+	 * @CC_ATTR_GUEST_SNP_SECURE_TSC: SNP Secure TSC is active.
+	 *
+	 * The platform/OS is running as a guest/virtual machine and actively
+	 * using AMD SEV-SNP Secure TSC feature.
+	 */
+	CC_ATTR_GUEST_SNP_SECURE_TSC,
 };
 
 #ifdef CONFIG_ARCH_HAS_CC_PLATFORM
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c
index 0f81f70aca82..5b9a358a3254 100644
--- a/arch/x86/coco/core.c
+++ b/arch/x86/coco/core.c
@@ -100,6 +100,9 @@ static bool noinstr amd_cc_platform_has(enum cc_attr attr)
 	case CC_ATTR_HOST_SEV_SNP:
 		return cc_flags.host_sev_snp;
 
+	case CC_ATTR_GUEST_SNP_SECURE_TSC:
+		return sev_status & MSR_AMD64_SNP_SECURE_TSC;
+
 	default:
 		return false;
 	}
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index c96b742789c5..88cae62382c2 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -98,6 +98,10 @@ static u64 secrets_pa __ro_after_init;
 
 static struct snp_msg_desc *snp_mdesc;
 
+/* Secure TSC values read using TSC_INFO SNP Guest request */
+static u64 snp_tsc_scale __ro_after_init;
+static u64 snp_tsc_offset __ro_after_init;
+
 /* #VC handler runtime per-CPU data */
 struct sev_es_runtime_data {
 	struct ghcb ghcb_page;
@@ -1148,6 +1152,12 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
 	vmsa->vmpl		= snp_vmpl;
 	vmsa->sev_features	= sev_status >> 2;
 
+	/* Set Secure TSC parameters */
+	if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC)) {
+		vmsa->tsc_scale = snp_tsc_scale;
+		vmsa->tsc_offset = snp_tsc_offset;
+	}
+
 	/* Switch the page over to a VMSA page now that it is initialized */
 	ret = snp_set_vmsa(vmsa, caa, apic_id, true);
 	if (ret) {
@@ -2942,3 +2952,83 @@ int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snp_send_guest_request);
+
+static int __init snp_get_tsc_info(void)
+{
+	static u8 buf[SNP_TSC_INFO_RESP_SZ + AUTHTAG_LEN];
+	struct snp_guest_request_ioctl rio;
+	struct snp_tsc_info_resp tsc_resp;
+	struct snp_tsc_info_req *tsc_req;
+	struct snp_msg_desc *mdesc;
+	struct snp_guest_req req;
+	int rc;
+
+	/*
+	 * The intermediate response buffer is used while decrypting the
+	 * response payload. Make sure that it has enough space to cover the
+	 * authtag.
+	 */
+	BUILD_BUG_ON(sizeof(buf) < (sizeof(tsc_resp) + AUTHTAG_LEN));
+
+	mdesc = snp_msg_alloc();
+	if (IS_ERR_OR_NULL(mdesc))
+		return -ENOMEM;
+
+	rc = snp_msg_init(mdesc, snp_vmpl);
+	if (rc)
+		return rc;
+
+	tsc_req = kzalloc(sizeof(struct snp_tsc_info_req), GFP_KERNEL);
+	if (!tsc_req)
+		return -ENOMEM;
+
+	memset(&req, 0, sizeof(req));
+	memset(&rio, 0, sizeof(rio));
+	memset(buf, 0, sizeof(buf));
+
+	req.msg_version = MSG_HDR_VER;
+	req.msg_type = SNP_MSG_TSC_INFO_REQ;
+	req.vmpck_id = snp_vmpl;
+	req.req_buf = tsc_req;
+	req.req_sz = sizeof(*tsc_req);
+	req.resp_buf = buf;
+	req.resp_sz = sizeof(tsc_resp) + AUTHTAG_LEN;
+	req.exit_code = SVM_VMGEXIT_GUEST_REQUEST;
+
+	rc = snp_send_guest_request(mdesc, &req, &rio);
+	if (rc)
+		goto err_req;
+
+	memcpy(&tsc_resp, buf, sizeof(tsc_resp));
+	pr_debug("%s: response status %x scale %llx offset %llx factor %x\n",
+		 __func__, tsc_resp.status, tsc_resp.tsc_scale, tsc_resp.tsc_offset,
+		 tsc_resp.tsc_factor);
+
+	if (tsc_resp.status == 0) {
+		snp_tsc_scale = tsc_resp.tsc_scale;
+		snp_tsc_offset = tsc_resp.tsc_offset;
+	} else {
+		pr_err("Failed to get TSC info, response status %x\n", tsc_resp.status);
+		rc = -EIO;
+	}
+
+err_req:
+	/* The response buffer contains the sensitive data, explicitly clear it. */
+	memzero_explicit(buf, sizeof(buf));
+	memzero_explicit(&tsc_resp, sizeof(tsc_resp));
+
+	return rc;
+}
+
+void __init snp_secure_tsc_prepare(void)
+{
+	if (!cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC))
+		return;
+
+	if (snp_get_tsc_info()) {
+		pr_alert("Unable to retrieve Secure TSC info from ASP\n");
+		sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SECURE_TSC);
+	}
+
+	pr_debug("SecureTSC enabled");
+}
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 0a120d85d7bb..996ca27f0b72 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -94,6 +94,10 @@ void __init mem_encrypt_init(void)
 	/* Call into SWIOTLB to update the SWIOTLB DMA buffers */
 	swiotlb_update_mem_attributes();
 
+	/* Initialize SNP Secure TSC */
+	if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+		snp_secure_tsc_prepare();
+
 	print_mem_encrypt_feature_info();
 }
 
-- 
2.34.1
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 3 weeks, 2 days ago
On Mon, Oct 28, 2024 at 11:04:21AM +0530, Nikunj A Dadhania wrote:
> Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests
> to securely use RDTSC/RDTSCP instructions, ensuring that the parameters
> used cannot be altered by the hypervisor once the guest is launched.
> 
> Secure TSC-enabled guests need to query TSC information from the AMD
> Security Processor. This communication channel is encrypted between the AMD
> Security Processor and the guest, with the hypervisor acting merely as a
> conduit to deliver the guest messages to the AMD Security Processor. Each
> message is protected with AEAD (AES-256 GCM).

Zap all that text below or shorten it to the bits only which explain why
something is done the way it is.

> Use a minimal AES GCM library
> to encrypt and decrypt SNP guest messages for communication with the PSP.
> 
> Use mem_encrypt_init() to fetch SNP TSC information from the AMD Security
> Processor and initialize snp_tsc_scale and snp_tsc_offset. During secondary
> CPU initialization, set the VMSA fields GUEST_TSC_SCALE (offset 2F0h) and
> GUEST_TSC_OFFSET (offset 2F8h) with snp_tsc_scale and snp_tsc_offset,
> respectively.
> 
> Add confidential compute platform attribute CC_ATTR_GUEST_SNP_SECURE_TSC
> that can be used by the guest to query whether the Secure TSC feature is
> active.
> 
> Since handle_guest_request() is common routine used by both the SEV guest
> driver and Secure TSC code, move it to the SEV header file.

...

> diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
> index c96b742789c5..88cae62382c2 100644
> --- a/arch/x86/coco/sev/core.c
> +++ b/arch/x86/coco/sev/core.c
> @@ -98,6 +98,10 @@ static u64 secrets_pa __ro_after_init;
>  
>  static struct snp_msg_desc *snp_mdesc;
>  
> +/* Secure TSC values read using TSC_INFO SNP Guest request */
> +static u64 snp_tsc_scale __ro_after_init;
> +static u64 snp_tsc_offset __ro_after_init;

I don't understand the point of this: this is supposed to be per VMSA so
everytime you create a guest, that guest is supposed to query the PSP. What
are those for?

Or are those the guest's TSC values which you're supposed to replicate across
the APs?

If so, put that info in the comment above it - it is much more important than
what you have there now.

>  /* #VC handler runtime per-CPU data */
>  struct sev_es_runtime_data {
>  	struct ghcb ghcb_page;
> @@ -1148,6 +1152,12 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
>  	vmsa->vmpl		= snp_vmpl;
>  	vmsa->sev_features	= sev_status >> 2;
>  
> +	/* Set Secure TSC parameters */

That's obvious. Why are you setting them, is more important.

> +	if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC)) {
> +		vmsa->tsc_scale = snp_tsc_scale;
> +		vmsa->tsc_offset = snp_tsc_offset;
> +	}
> +
>  	/* Switch the page over to a VMSA page now that it is initialized */
>  	ret = snp_set_vmsa(vmsa, caa, apic_id, true);
>  	if (ret) {
> @@ -2942,3 +2952,83 @@ int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(snp_send_guest_request);
> +
> +static int __init snp_get_tsc_info(void)
> +{
> +	static u8 buf[SNP_TSC_INFO_RESP_SZ + AUTHTAG_LEN];

You're allocating stuff below dynamically. Why is this buffer allocated on the
stack?

> +	struct snp_guest_request_ioctl rio;
> +	struct snp_tsc_info_resp tsc_resp;

Ditto.

> +	struct snp_tsc_info_req *tsc_req;
> +	struct snp_msg_desc *mdesc;
> +	struct snp_guest_req req;
> +	int rc;
> +
> +	/*
> +	 * The intermediate response buffer is used while decrypting the
> +	 * response payload. Make sure that it has enough space to cover the
> +	 * authtag.
> +	 */

Yes, this is how you do comments - you comment stuff which is non-obvious.

> +	BUILD_BUG_ON(sizeof(buf) < (sizeof(tsc_resp) + AUTHTAG_LEN));
> +
> +	mdesc = snp_msg_alloc();
> +	if (IS_ERR_OR_NULL(mdesc))
> +		return -ENOMEM;
> +
> +	rc = snp_msg_init(mdesc, snp_vmpl);
> +	if (rc)
> +		return rc;
> +
> +	tsc_req = kzalloc(sizeof(struct snp_tsc_info_req), GFP_KERNEL);
> +	if (!tsc_req)
> +		return -ENOMEM;

You return here and you leak mdesc. Where are those mdesc things even freed?
I see snp_msg_alloc() but not a "free" counterpart...

> +	memset(&req, 0, sizeof(req));
> +	memset(&rio, 0, sizeof(rio));
> +	memset(buf, 0, sizeof(buf));
> +
> +	req.msg_version = MSG_HDR_VER;
> +	req.msg_type = SNP_MSG_TSC_INFO_REQ;
> +	req.vmpck_id = snp_vmpl;
> +	req.req_buf = tsc_req;
> +	req.req_sz = sizeof(*tsc_req);
> +	req.resp_buf = buf;
> +	req.resp_sz = sizeof(tsc_resp) + AUTHTAG_LEN;
> +	req.exit_code = SVM_VMGEXIT_GUEST_REQUEST;
> +
> +	rc = snp_send_guest_request(mdesc, &req, &rio);
> +	if (rc)
> +		goto err_req;
> +
> +	memcpy(&tsc_resp, buf, sizeof(tsc_resp));
> +	pr_debug("%s: response status %x scale %llx offset %llx factor %x\n",

Prefix all hex values with "0x" so that it is unambiguous.

> +		 __func__, tsc_resp.status, tsc_resp.tsc_scale, tsc_resp.tsc_offset,
> +		 tsc_resp.tsc_factor);
> +

	if (!tsc_resp.status)

> +	if (tsc_resp.status == 0) {
> +		snp_tsc_scale = tsc_resp.tsc_scale;
> +		snp_tsc_offset = tsc_resp.tsc_offset;
> +	} else {
> +		pr_err("Failed to get TSC info, response status %x\n", tsc_resp.status);

								Ox

> +		rc = -EIO;
> +	}
> +
> +err_req:
> +	/* The response buffer contains the sensitive data, explicitly clear it. */

s/the //

> +	memzero_explicit(buf, sizeof(buf));
> +	memzero_explicit(&tsc_resp, sizeof(tsc_resp));
> +
> +	return rc;
> +}
> +
> +void __init snp_secure_tsc_prepare(void)
> +{
> +	if (!cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC))
> +		return;
> +
> +	if (snp_get_tsc_info()) {
> +		pr_alert("Unable to retrieve Secure TSC info from ASP\n");
> +		sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SECURE_TSC);
> +	}
> +
> +	pr_debug("SecureTSC enabled");
> +}
> diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
> index 0a120d85d7bb..996ca27f0b72 100644
> --- a/arch/x86/mm/mem_encrypt.c
> +++ b/arch/x86/mm/mem_encrypt.c
> @@ -94,6 +94,10 @@ void __init mem_encrypt_init(void)
>  	/* Call into SWIOTLB to update the SWIOTLB DMA buffers */
>  	swiotlb_update_mem_attributes();
>  
> +	/* Initialize SNP Secure TSC */

Useless comment.

> +	if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
> +		snp_secure_tsc_prepare();

Why don't you call this one in the same if-condition in
mem_encrypt_setup_arch() ?

> +
>  	print_mem_encrypt_feature_info();
>  }
>  
> -- 
> 2.34.1
> 

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 2 weeks ago

On 11/1/2024 9:30 PM, Borislav Petkov wrote:
> On Mon, Oct 28, 2024 at 11:04:21AM +0530, Nikunj A Dadhania wrote:
>> Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests
>> to securely use RDTSC/RDTSCP instructions, ensuring that the parameters
>> used cannot be altered by the hypervisor once the guest is launched.
>>
>> Secure TSC-enabled guests need to query TSC information from the AMD
>> Security Processor. This communication channel is encrypted between the AMD
>> Security Processor and the guest, with the hypervisor acting merely as a
>> conduit to deliver the guest messages to the AMD Security Processor. Each
>> message is protected with AEAD (AES-256 GCM).
> 
> Zap all that text below or shorten it to the bits only which explain why
> something is done the way it is.

Sure, I will update.

> 
>> Use a minimal AES GCM library
>> to encrypt and decrypt SNP guest messages for communication with the PSP.
>>
>> Use mem_encrypt_init() to fetch SNP TSC information from the AMD Security
>> Processor and initialize snp_tsc_scale and snp_tsc_offset. During secondary
>> CPU initialization, set the VMSA fields GUEST_TSC_SCALE (offset 2F0h) and
>> GUEST_TSC_OFFSET (offset 2F8h) with snp_tsc_scale and snp_tsc_offset,
>> respectively.
>>
>> Add confidential compute platform attribute CC_ATTR_GUEST_SNP_SECURE_TSC
>> that can be used by the guest to query whether the Secure TSC feature is
>> active.
>>
>> Since handle_guest_request() is common routine used by both the SEV guest
>> driver and Secure TSC code, move it to the SEV header file.
> 
> ...
> 
>> diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
>> index c96b742789c5..88cae62382c2 100644
>> --- a/arch/x86/coco/sev/core.c
>> +++ b/arch/x86/coco/sev/core.c
>> @@ -98,6 +98,10 @@ static u64 secrets_pa __ro_after_init;
>>  
>>  static struct snp_msg_desc *snp_mdesc;
>>  
>> +/* Secure TSC values read using TSC_INFO SNP Guest request */
>> +static u64 snp_tsc_scale __ro_after_init;
>> +static u64 snp_tsc_offset __ro_after_init;
> 
> I don't understand the point of this: this is supposed to be per VMSA so
> everytime you create a guest, that guest is supposed to query the PSP. What
> are those for?
> 
> Or are those the guest's TSC values which you're supposed to replicate across
> the APs?

Yes, that is correct. The BP makes the SNP guest requests and initializes 
both the values. These are later used by APs to initialize the VMSA fields
(TSC_SCALE and TSC_OFFSET).

> If so, put that info in the comment above it - it is much more important than
> what you have there now.

Make sense, I will update the comment.

> 
>>  /* #VC handler runtime per-CPU data */
>>  struct sev_es_runtime_data {
>>  	struct ghcb ghcb_page;
>> @@ -1148,6 +1152,12 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
>>  	vmsa->vmpl		= snp_vmpl;
>>  	vmsa->sev_features	= sev_status >> 2;
>>  
>> +	/* Set Secure TSC parameters */
> 
> That's obvious. Why are you setting them, is more important.

Sure will update.

> 
>> +	if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC)) {
>> +		vmsa->tsc_scale = snp_tsc_scale;
>> +		vmsa->tsc_offset = snp_tsc_offset;
>> +	}
>> +
>>  	/* Switch the page over to a VMSA page now that it is initialized */
>>  	ret = snp_set_vmsa(vmsa, caa, apic_id, true);
>>  	if (ret) {
>> @@ -2942,3 +2952,83 @@ int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL_GPL(snp_send_guest_request);
>> +
>> +static int __init snp_get_tsc_info(void)
>> +{
>> +	static u8 buf[SNP_TSC_INFO_RESP_SZ + AUTHTAG_LEN];
> 
> You're allocating stuff below dynamically. Why is this buffer allocated on the
> stack?
> 
>> +	struct snp_guest_request_ioctl rio;
>> +	struct snp_tsc_info_resp tsc_resp;
> 
> Ditto.

Ok, will allocate dynamically.

>>> +	struct snp_tsc_info_req *tsc_req;
>> +	struct snp_msg_desc *mdesc;
>> +	struct snp_guest_req req;
>> +	int rc;
>> +
>> +	/*
>> +	 * The intermediate response buffer is used while decrypting the
>> +	 * response payload. Make sure that it has enough space to cover the
>> +	 * authtag.
>> +	 */
> 
> Yes, this is how you do comments - you comment stuff which is non-obvious.
> 
>> +	BUILD_BUG_ON(sizeof(buf) < (sizeof(tsc_resp) + AUTHTAG_LEN));
>> +
>> +	mdesc = snp_msg_alloc();
>> +	if (IS_ERR_OR_NULL(mdesc))
>> +		return -ENOMEM;
>> +
>> +	rc = snp_msg_init(mdesc, snp_vmpl);
>> +	if (rc)
>> +		return rc;
>> +
>> +	tsc_req = kzalloc(sizeof(struct snp_tsc_info_req), GFP_KERNEL);
>> +	if (!tsc_req)
>> +		return -ENOMEM;
> 
> You return here and you leak mdesc. Where are those mdesc things even freed?
> I see snp_msg_alloc() but not a "free" counterpart...

Right, will add snp_msg_free().

> 
>> +	memset(&req, 0, sizeof(req));
>> +	memset(&rio, 0, sizeof(rio));
>> +	memset(buf, 0, sizeof(buf));
>> +
>> +	req.msg_version = MSG_HDR_VER;
>> +	req.msg_type = SNP_MSG_TSC_INFO_REQ;
>> +	req.vmpck_id = snp_vmpl;
>> +	req.req_buf = tsc_req;
>> +	req.req_sz = sizeof(*tsc_req);
>> +	req.resp_buf = buf;
>> +	req.resp_sz = sizeof(tsc_resp) + AUTHTAG_LEN;
>> +	req.exit_code = SVM_VMGEXIT_GUEST_REQUEST;
>> +
>> +	rc = snp_send_guest_request(mdesc, &req, &rio);
>> +	if (rc)
>> +		goto err_req;
>> +
>> +	memcpy(&tsc_resp, buf, sizeof(tsc_resp));
>> +	pr_debug("%s: response status %x scale %llx offset %llx factor %x\n",
> 
> Prefix all hex values with "0x" so that it is unambiguous.

Sure.

> 
>> +		 __func__, tsc_resp.status, tsc_resp.tsc_scale, tsc_resp.tsc_offset,
>> +		 tsc_resp.tsc_factor);
>> +
> 
> 	if (!tsc_resp.status)
> 
>> +	if (tsc_resp.status == 0) {
>> +		snp_tsc_scale = tsc_resp.tsc_scale;
>> +		snp_tsc_offset = tsc_resp.tsc_offset;
>> +	} else {
>> +		pr_err("Failed to get TSC info, response status %x\n", tsc_resp.status);
> 
> 								Ox
> 
>> +		rc = -EIO;
>> +	}
>> +
>> +err_req:
>> +	/* The response buffer contains the sensitive data, explicitly clear it. */
> 
> s/the //

Sure.

> 
>> +	memzero_explicit(buf, sizeof(buf));
>> +	memzero_explicit(&tsc_resp, sizeof(tsc_resp));
>> +
>> +	return rc;
>> +}
>> +
>> +void __init snp_secure_tsc_prepare(void)
>> +{
>> +	if (!cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC))
>> +		return;
>> +
>> +	if (snp_get_tsc_info()) {
>> +		pr_alert("Unable to retrieve Secure TSC info from ASP\n");
>> +		sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SECURE_TSC);
>> +	}
>> +
>> +	pr_debug("SecureTSC enabled");
>> +}
>> diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
>> index 0a120d85d7bb..996ca27f0b72 100644
>> --- a/arch/x86/mm/mem_encrypt.c
>> +++ b/arch/x86/mm/mem_encrypt.c
>> @@ -94,6 +94,10 @@ void __init mem_encrypt_init(void)
>>  	/* Call into SWIOTLB to update the SWIOTLB DMA buffers */
>>  	swiotlb_update_mem_attributes();
>>  
>> +	/* Initialize SNP Secure TSC */
> 
> Useless comment.
> 
>> +	if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
>> +		snp_secure_tsc_prepare();
> 
> Why don't you call this one in the same if-condition in
> mem_encrypt_setup_arch() ?

kmalloc() does not work at this stage. Moreover, mem_encrypt_setup_arch() does not have
CC_ATTR_GUEST_SEV_SNP check.

Regards
Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 2 weeks ago
On Mon, Nov 11, 2024 at 12:33:28PM +0530, Nikunj A. Dadhania wrote:
> kmalloc() does not work at this stage. Moreover, mem_encrypt_setup_arch()
> does not have CC_ATTR_GUEST_SEV_SNP check.

Bah, let's simplify it then:

diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 996ca27f0b72..95bae74fdab2 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -94,9 +94,7 @@ void __init mem_encrypt_init(void)
 	/* Call into SWIOTLB to update the SWIOTLB DMA buffers */
 	swiotlb_update_mem_attributes();
 
-	/* Initialize SNP Secure TSC */
-	if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
-		snp_secure_tsc_prepare();
+	snp_secure_tsc_prepare();
 
 	print_mem_encrypt_feature_info();
 }

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 2 weeks ago
On 11/11/2024 12:33 PM, Nikunj A. Dadhania wrote:
> On 11/1/2024 9:30 PM, Borislav Petkov wrote:
>> On Mon, Oct 28, 2024 at 11:04:21AM +0530, Nikunj A Dadhania wrote:

>>> +	BUILD_BUG_ON(sizeof(buf) < (sizeof(tsc_resp) + AUTHTAG_LEN));
>>> +
>>> +	mdesc = snp_msg_alloc();
>>> +	if (IS_ERR_OR_NULL(mdesc))
>>> +		return -ENOMEM;
>>> +
>>> +	rc = snp_msg_init(mdesc, snp_vmpl);
>>> +	if (rc)
>>> +		return rc;
>>> +
>>> +	tsc_req = kzalloc(sizeof(struct snp_tsc_info_req), GFP_KERNEL);
>>> +	if (!tsc_req)
>>> +		return -ENOMEM;
>>
>> You return here and you leak mdesc. 

mdesc is allocated only once in snp_msg_alloc() and is stored in static
variable snp_mdesc, subsequent snp_msg_alloc() calls from the sev-guest
driver will return snp_mdesc.

>> Where are those mdesc things even freed?

snp_mdesc is initialized once and is not freed.

>> I see snp_msg_alloc() but not a "free" counterpart...

That was the reason I had not implemented "free" counterpart.

Regards
Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 2 weeks ago
On Mon, Nov 11, 2024 at 02:16:00PM +0530, Nikunj A. Dadhania wrote:
> That was the reason I had not implemented "free" counterpart.

Then let's simplify this too because it is kinda silly right now:

---
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index a72400704421..efddccf4b2c6 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -96,7 +96,7 @@ static u64 sev_hv_features __ro_after_init;
 /* Secrets page physical address from the CC blob */
 static u64 secrets_pa __ro_after_init;
 
-static struct snp_msg_desc *snp_mdesc;
+static struct snp_msg_desc snp_mdesc;
 
 /* Secure TSC values read using TSC_INFO SNP Guest request */
 static u64 snp_tsc_scale __ro_after_init;
@@ -2749,19 +2749,13 @@ EXPORT_SYMBOL_GPL(snp_msg_init);
 
 struct snp_msg_desc *snp_msg_alloc(void)
 {
-	struct snp_msg_desc *mdesc;
+	struct snp_msg_desc *mdesc = &snp_mdesc;
 
 	BUILD_BUG_ON(sizeof(struct snp_guest_msg) > PAGE_SIZE);
 
-	if (snp_mdesc)
-		return snp_mdesc;
-
-	mdesc = kzalloc(sizeof(struct snp_msg_desc), GFP_KERNEL);
-	if (!mdesc)
-		return ERR_PTR(-ENOMEM);
+	memset(mdesc, 0, sizeof(struct snp_msg_desc));
 
-	mdesc->secrets = (__force struct snp_secrets_page *)ioremap_encrypted(secrets_pa,
-									      PAGE_SIZE);
+	mdesc->secrets = (__force struct snp_secrets_page *)ioremap_encrypted(secrets_pa, PAGE_SIZE);
 	if (!mdesc->secrets)
 		return ERR_PTR(-ENODEV);
 
@@ -2783,8 +2777,6 @@ struct snp_msg_desc *snp_msg_alloc(void)
 	mdesc->input.resp_gpa = __pa(mdesc->response);
 	mdesc->input.data_gpa = __pa(mdesc->certs_data);
 
-	snp_mdesc = mdesc;
-
 	return mdesc;
 
 e_free_response:

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 2 weeks ago

On 11/11/2024 4:21 PM, Borislav Petkov wrote:
> On Mon, Nov 11, 2024 at 02:16:00PM +0530, Nikunj A. Dadhania wrote:
>> That was the reason I had not implemented "free" counterpart.
> 
> Then let's simplify this too because it is kinda silly right now:

When snp_msg_alloc() is called by the sev-guest driver, secrets will
be reinitialized and buffers will be re-allocated, leaking memory
allocated during snp_get_tsc_info()::snp_msg_alloc(). 

As you suggested, implementing a "free" counterpart will be better.


diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 8ecac0ca419b..12b167fd6475 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -488,14 +488,7 @@ static inline bool snp_is_vmpck_empty(struct snp_msg_desc *mdesc)
 
 int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id);
 struct snp_msg_desc *snp_msg_alloc(void);
-
-static inline void snp_msg_cleanup(struct snp_msg_desc *mdesc)
-{
-	mdesc->vmpck = NULL;
-	mdesc->os_area_msg_seqno = NULL;
-	kfree(mdesc->ctx);
-}
-
+void snp_msg_free(struct snp_msg_desc *mdesc);
 int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
 			   struct snp_guest_request_ioctl *rio);
 
@@ -541,7 +534,7 @@ static inline void snp_kexec_begin(void) { }
 static inline bool snp_is_vmpck_empty(struct snp_msg_desc *mdesc) { return false; }
 static inline int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id) { return -1; }
 static inline struct snp_msg_desc *snp_msg_alloc(void) { return NULL; }
-static inline void snp_msg_cleanup(struct snp_msg_desc *mdesc) { }
+static inline void snp_msg_free(struct snp_msg_desc *mdesc) { }
 static inline int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
 					 struct snp_guest_request_ioctl *rio) { return -ENODEV; }
 static inline void __init snp_secure_tsc_prepare(void) { }
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index d40d4528c1eb..25fb8e79eb9b 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -96,8 +96,6 @@ static u64 sev_hv_features __ro_after_init;
 /* Secrets page physical address from the CC blob */
 static u64 secrets_pa __ro_after_init;
 
-static struct snp_msg_desc *snp_mdesc;
-
 /* Secure TSC values read using TSC_INFO SNP Guest request */
 static u64 snp_tsc_scale __ro_after_init;
 static u64 snp_tsc_offset __ro_after_init;
@@ -2818,9 +2816,6 @@ struct snp_msg_desc *snp_msg_alloc(void)
 
 	BUILD_BUG_ON(sizeof(struct snp_guest_msg) > PAGE_SIZE);
 
-	if (snp_mdesc)
-		return snp_mdesc;
-
 	mdesc = kzalloc(sizeof(struct snp_msg_desc), GFP_KERNEL);
 	if (!mdesc)
 		return ERR_PTR(-ENOMEM);
@@ -2848,8 +2843,6 @@ struct snp_msg_desc *snp_msg_alloc(void)
 	mdesc->input.resp_gpa = __pa(mdesc->response);
 	mdesc->input.data_gpa = __pa(mdesc->certs_data);
 
-	snp_mdesc = mdesc;
-
 	return mdesc;
 
 e_free_response:
@@ -2858,11 +2851,29 @@ struct snp_msg_desc *snp_msg_alloc(void)
 	free_shared_pages(mdesc->request, sizeof(struct snp_guest_msg));
 e_unmap:
 	iounmap((__force void __iomem *)mdesc->secrets);
+	kfree(mdesc);
 
 	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL_GPL(snp_msg_alloc);
 
+void snp_msg_free(struct snp_msg_desc *mdesc)
+{
+	if (!mdesc)
+		return;
+
+	mdesc->vmpck = NULL;
+	mdesc->os_area_msg_seqno = NULL;
+	kfree(mdesc->ctx);
+
+	free_shared_pages(mdesc->response, sizeof(struct snp_guest_msg));
+	free_shared_pages(mdesc->request, sizeof(struct snp_guest_msg));
+	iounmap((__force void __iomem *)mdesc->secrets);
+
+	kfree(mdesc);
+}
+EXPORT_SYMBOL_GPL(snp_msg_free);
+
 /* Mutex to serialize the shared buffer access and command handling. */
 static DEFINE_MUTEX(snp_cmd_mutex);
 
@@ -3179,8 +3190,10 @@ static int __init snp_get_tsc_info(void)
 		return rc;
 
 	tsc_req = kzalloc(sizeof(struct snp_tsc_info_req), GFP_KERNEL);
-	if (!tsc_req)
-		return -ENOMEM;
+	if (!tsc_req) {
+		rc = -ENOMEM;
+		goto e_free_mdesc;
+	}
 
 	memset(&req, 0, sizeof(req));
 	memset(&rio, 0, sizeof(rio));
@@ -3197,7 +3210,7 @@ static int __init snp_get_tsc_info(void)
 
 	rc = snp_send_guest_request(mdesc, &req, &rio);
 	if (rc)
-		goto err_req;
+		goto e_request;
 
 	memcpy(&tsc_resp, buf, sizeof(tsc_resp));
 	pr_debug("%s: response status %x scale %llx offset %llx factor %x\n",
@@ -3212,11 +3225,14 @@ static int __init snp_get_tsc_info(void)
 		rc = -EIO;
 	}
 
-err_req:
+e_request:
 	/* The response buffer contains the sensitive data, explicitly clear it. */
 	memzero_explicit(buf, sizeof(buf));
 	memzero_explicit(&tsc_resp, sizeof(tsc_resp));
 
+e_free_mdesc:
+	snp_msg_free(mdesc);
+
 	return rc;
 }
 
diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c
index d64efc489686..084ea9499e75 100644
--- a/drivers/virt/coco/sev-guest/sev-guest.c
+++ b/drivers/virt/coco/sev-guest/sev-guest.c
@@ -647,7 +647,7 @@ static int __init sev_guest_probe(struct platform_device *pdev)
 	return 0;
 
 e_msg_init:
-	snp_msg_cleanup(mdesc);
+	snp_msg_free(mdesc);
 
 	return ret;
 }
@@ -656,7 +656,7 @@ static void __exit sev_guest_remove(struct platform_device *pdev)
 {
 	struct snp_guest_dev *snp_dev = platform_get_drvdata(pdev);
 
-	snp_msg_cleanup(snp_dev->msg_desc);
+	snp_msg_free(snp_dev->msg_desc);
 	misc_deregister(&snp_dev->misc);
 }
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 2 weeks ago
On Mon, Nov 11, 2024 at 04:53:30PM +0530, Nikunj A. Dadhania wrote:
> When snp_msg_alloc() is called by the sev-guest driver, secrets will
> be reinitialized and buffers will be re-allocated, leaking memory
> allocated during snp_get_tsc_info()::snp_msg_alloc(). 

Huh?

How do you leak memory when you clear all buffers before that?!?

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 2 weeks ago

On 11/11/2024 5:00 PM, Borislav Petkov wrote:
> On Mon, Nov 11, 2024 at 04:53:30PM +0530, Nikunj A. Dadhania wrote:
>> When snp_msg_alloc() is called by the sev-guest driver, secrets will
>> be reinitialized and buffers will be re-allocated, leaking memory
>> allocated during snp_get_tsc_info()::snp_msg_alloc(). 
> 
> Huh?
> 
> How do you leak memory when you clear all buffers before that?!?

Memory allocated for the request, response and certs_data is not
freed and we will clear the mdesc when sev-guest driver calls
snp_msg_alloc().

Let me try again to explain what I mean:

snp_msg_alloc() will be called by snp_get_tsc_info() and later by
sev-guest driver.

snp_prepare_tsc()
 ->snp_get_tsc_info()
    ->snp_msg_alloc()
      -> clears mdesc
      ->ioremaps secrets_pa
      ->request = alloc_shared_pages()
                   -> alloc_pages()
      ->response = alloc_shared_pages()
                    -> alloc_pages()
      ->certs_data = alloc_shared_pages()
                      -> alloc_pages()


sev-guest driver
sev_guest_probe()
 ->snp_msg_alloc()
   ->clears mdesc
   ->ioremaps secrets_pa
   ->request = alloc_shared_pages()
                -> alloc_pages()
   ->response = alloc_shared_pages()
                 -> alloc_pages()
   ->certs_data = alloc_shared_pages()
                   -> alloc_pages()

request, response and certs_data are re-allocated. Am I missing something ?

Regards
Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 1 week, 6 days ago
On Mon, Nov 11, 2024 at 05:14:43PM +0530, Nikunj A. Dadhania wrote:
> Memory allocated for the request, response and certs_data is not
> freed and we will clear the mdesc when sev-guest driver calls
> snp_msg_alloc().

Ah, right.

Yeah, this was a weird scheme anyway - a static pointer mdesc but then the
things it points to get dynamically allocated. So yeah, a full dynamic
allocation makes it a much more normal pattern.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 1 week, 6 days ago

On 11/11/2024 7:12 PM, Borislav Petkov wrote:
> On Mon, Nov 11, 2024 at 05:14:43PM +0530, Nikunj A. Dadhania wrote:
>> Memory allocated for the request, response and certs_data is not
>> freed and we will clear the mdesc when sev-guest driver calls
>> snp_msg_alloc().
> 
> Ah, right.
> 
> Yeah, this was a weird scheme anyway - a static pointer mdesc but then the
> things it points to get dynamically allocated. So yeah, a full dynamic
> allocation makes it a much more normal pattern.

I have pushed the updated tree here: https://github.com/AMDESE/linux-kvm/commits/sectsc-guest-wip/

Will wait for your comments on rest of the patches before I post the next version.

Regards
Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 3 weeks, 4 days ago

On 10/28/2024 11:04 AM, Nikunj A Dadhania wrote:
> @@ -497,6 +516,27 @@ static inline void snp_msg_cleanup(struct snp_msg_desc *mdesc)
>  int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
>  			   struct snp_guest_request_ioctl *rio);
>  
> +static inline int handle_guest_request(struct snp_msg_desc *mdesc, u64 exit_code,
> +				       struct snp_guest_request_ioctl *rio, u8 type,
> +				       void *req_buf, size_t req_sz, void *resp_buf,
> +				       u32 resp_sz)
> +{
> +	struct snp_guest_req req = {
> +		.msg_version	= rio->msg_version,
> +		.msg_type	= type,
> +		.vmpck_id	= mdesc->vmpck_id,
> +		.req_buf	= req_buf,
> +		.req_sz		= req_sz,
> +		.resp_buf	= resp_buf,
> +		.resp_sz	= resp_sz,
> +		.exit_code	= exit_code,
> +	};
> +
> +	return snp_send_guest_request(mdesc, &req, rio);
> +}

I realized that the above is not required anymore. I will remove in my next version.

> @@ -538,6 +578,12 @@ static inline struct snp_msg_desc *snp_msg_alloc(void) { return NULL; }
>  static inline void snp_msg_cleanup(struct snp_msg_desc *mdesc) { }
>  static inline int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
>  					 struct snp_guest_request_ioctl *rio) { return -ENODEV; }
> +static inline int handle_guest_request(struct snp_msg_desc *mdesc, u64 exit_code,
> +				       struct snp_guest_request_ioctl *rio, u8 type,
> +				       void *req_buf, size_t req_sz, void *resp_buf,
> +				       u32 resp_sz) { return -ENODEV; }
> +

Ditto.

Regards
Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Xiaoyao Li 3 weeks, 6 days ago
On 10/28/2024 1:34 PM, Nikunj A Dadhania wrote:
> Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests
> to securely use RDTSC/RDTSCP instructions, ensuring that the parameters
> used cannot be altered by the hypervisor once the guest is launched.
> 
> Secure TSC-enabled guests need to query TSC information from the AMD
> Security Processor. This communication channel is encrypted between the AMD
> Security Processor and the guest, with the hypervisor acting merely as a
> conduit to deliver the guest messages to the AMD Security Processor. Each
> message is protected with AEAD (AES-256 GCM). Use a minimal AES GCM library
> to encrypt and decrypt SNP guest messages for communication with the PSP.
> 
> Use mem_encrypt_init() to fetch SNP TSC information from the AMD Security
> Processor and initialize snp_tsc_scale and snp_tsc_offset.

Why do it inside mem_encrypt_init()?

It's better to introduce a snp_guest_init/setup() like tdx_early_init() 
to do all the SNP related setup stuff instead of scattering them all 
around the kernel code.

> During secondary
> CPU initialization, set the VMSA fields GUEST_TSC_SCALE (offset 2F0h) and
> GUEST_TSC_OFFSET (offset 2F8h) with snp_tsc_scale and snp_tsc_offset,
> respectively.
>
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Nikunj A. Dadhania 3 weeks, 6 days ago

On 10/29/2024 2:11 PM, Xiaoyao Li wrote:
> On 10/28/2024 1:34 PM, Nikunj A Dadhania wrote:
>> Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests
>> to securely use RDTSC/RDTSCP instructions, ensuring that the parameters
>> used cannot be altered by the hypervisor once the guest is launched.
>>
>> Secure TSC-enabled guests need to query TSC information from the AMD
>> Security Processor. This communication channel is encrypted between the AMD
>> Security Processor and the guest, with the hypervisor acting merely as a
>> conduit to deliver the guest messages to the AMD Security Processor. Each
>> message is protected with AEAD (AES-256 GCM). Use a minimal AES GCM library
>> to encrypt and decrypt SNP guest messages for communication with the PSP.
>>
>> Use mem_encrypt_init() to fetch SNP TSC information from the AMD Security
>> Processor and initialize snp_tsc_scale and snp_tsc_offset.
> 
> Why do it inside mem_encrypt_init()?

It was discussed here: https://lore.kernel.org/lkml/20240422132058.GBZiZkOqU0zFviMzoC@fat_crate.local/

Regards
Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Xiaoyao Li 3 weeks, 6 days ago
On 10/29/2024 4:46 PM, Nikunj A. Dadhania wrote:
> 
> 
> On 10/29/2024 2:11 PM, Xiaoyao Li wrote:
>> On 10/28/2024 1:34 PM, Nikunj A Dadhania wrote:
>>> Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests
>>> to securely use RDTSC/RDTSCP instructions, ensuring that the parameters
>>> used cannot be altered by the hypervisor once the guest is launched.
>>>
>>> Secure TSC-enabled guests need to query TSC information from the AMD
>>> Security Processor. This communication channel is encrypted between the AMD
>>> Security Processor and the guest, with the hypervisor acting merely as a
>>> conduit to deliver the guest messages to the AMD Security Processor. Each
>>> message is protected with AEAD (AES-256 GCM). Use a minimal AES GCM library
>>> to encrypt and decrypt SNP guest messages for communication with the PSP.
>>>
>>> Use mem_encrypt_init() to fetch SNP TSC information from the AMD Security
>>> Processor and initialize snp_tsc_scale and snp_tsc_offset.
>>
>> Why do it inside mem_encrypt_init()?
> 
> It was discussed here: https://lore.kernel.org/lkml/20240422132058.GBZiZkOqU0zFviMzoC@fat_crate.local/

IMHO, it's a bad starter. As more and more SNP features will be enabled 
in the future, a SNP init function like tdx_early_init() would be a good 
place for all SNP guest stuff.

Just my 2 cents.

> Regards
> Nikunj
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 3 weeks, 5 days ago
On Tue, Oct 29, 2024 at 05:19:29PM +0800, Xiaoyao Li wrote:
> IMHO, it's a bad starter.

What does a "bad starter" mean exactly?

> As more and more SNP features will be enabled in the future, a SNP init
> function like tdx_early_init() would be a good place for all SNP guest
> stuff.

There is already a call to sme_early_init() around that area. It could be
repurposed for SEV/SNP stuff too...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Xiaoyao Li 3 weeks, 5 days ago
On 10/29/2024 10:27 PM, Borislav Petkov wrote:
> On Tue, Oct 29, 2024 at 05:19:29PM +0800, Xiaoyao Li wrote:
>> IMHO, it's a bad starter.
> 
> What does a "bad starter" mean exactly?

I meant the starter to add SNP guest specific feature initialization 
code in somewhat in proper place.
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 3 weeks, 5 days ago
On Tue, Oct 29, 2024 at 10:50:18PM +0800, Xiaoyao Li wrote:
> I meant the starter to add SNP guest specific feature initialization code in
> somewhat in proper place.

https://lore.kernel.org/r/20241029144948.GIZyD2DBjyg6FBLdo4@fat_crate.local

IOW, I don't think we really have a "proper" place yet. There are vendor
checks all over the memory encryption code for different reasons.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Xiaoyao Li 3 weeks, 5 days ago
On 10/29/2024 11:03 PM, Borislav Petkov wrote:
> On Tue, Oct 29, 2024 at 10:50:18PM +0800, Xiaoyao Li wrote:
>> I meant the starter to add SNP guest specific feature initialization code in
>> somewhat in proper place.
> 
> https://lore.kernel.org/r/20241029144948.GIZyD2DBjyg6FBLdo4@fat_crate.local
> 
> IOW, I don't think we really have a "proper" place yet. 

Then why can't we create one for it?

> There are vendor
> checks all over the memory encryption code for different reasons.

But they are at least related to memory encryption, I think.

However, how secure TSC related to memory encryption?
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Dave Hansen 3 weeks, 5 days ago
On 10/29/24 08:14, Xiaoyao Li wrote:
> On 10/29/2024 11:03 PM, Borislav Petkov wrote:
>> On Tue, Oct 29, 2024 at 10:50:18PM +0800, Xiaoyao Li wrote:
>>> I meant the starter to add SNP guest specific feature initialization
>>> code in
>>> somewhat in proper place.
>>
>> https://lore.kernel.org/r/20241029144948.GIZyD2DBjyg6FBLdo4@fat_crate.local
>>
>> IOW, I don't think we really have a "proper" place yet. 
> 
> Then why can't we create one for it?

The code looks fine to me as-is.  If anyone sees a better way to
refactor it and stash it elsewhere to make it cleaner and simpler, I'd
love to see the patch.
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 3 weeks, 5 days ago
On Tue, Oct 29, 2024 at 09:50:11AM -0700, Dave Hansen wrote:
> The code looks fine to me as-is.  If anyone sees a better way to
> refactor it and stash it elsewhere to make it cleaner and simpler, I'd
> love to see the patch.

You basically read my mind!

:-)

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 3 weeks, 5 days ago
On Tue, Oct 29, 2024 at 11:14:29PM +0800, Xiaoyao Li wrote:
> However, how secure TSC related to memory encryption?

Are you kidding me?

Secure TSC is a SNP feature.

I don't think you're getting it so lemme elaborate:

mem_encrypt.c is only *trying* to be somewhat generic but there is stuff like:

        if (cc_platform_has(CC_ATTR_HOST_SEV_SNP))
                snp_fixup_e820_tables();

for example.

Both TDX and SEV/SNP need to call *something* at different times during boot
for various reasons.

We could aim for generalizing things by doing per-vendor early init functions,
which is ok, but hasn't been the main goal so far. So far the goal is to do
the proper init/setup calls at the right time during boot and not allow the
code to grow into an unmaintainable mess while doing so.

But both vendors need to do different things at different times during the
lifetime of the kernel depending on what they need/want to support.

IOW, the memory encryption code is still shaping up...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Tom Lendacky 3 weeks, 5 days ago
On 10/29/24 09:27, Borislav Petkov wrote:
> On Tue, Oct 29, 2024 at 05:19:29PM +0800, Xiaoyao Li wrote:
>> IMHO, it's a bad starter.
> 
> What does a "bad starter" mean exactly?
> 
>> As more and more SNP features will be enabled in the future, a SNP init
>> function like tdx_early_init() would be a good place for all SNP guest
>> stuff.
> 
> There is already a call to sme_early_init() around that area. It could be
> repurposed for SEV/SNP stuff too...

Yes, the early call to sme_early_init() is meant for SME, SEV, SEV-ES and
SEV-SNP since we have to support them all and currently does
initialization for all of these. It is analogous to the tdx_early_init() call.

TDX also makes use of initialization that happens in mem_encrypt_init()
and mem_encrypt_setup_arch(), so it doesn't only use tdx_early_init().

Thanks,
Tom

>
Re: [PATCH v14 03/13] x86/sev: Add Secure TSC support for SNP guests
Posted by Borislav Petkov 3 weeks, 5 days ago
On Tue, Oct 29, 2024 at 09:34:40AM -0500, Tom Lendacky wrote:
> TDX also makes use of initialization that happens in mem_encrypt_init()
> and mem_encrypt_setup_arch(), so it doesn't only use tdx_early_init().

I think he means that mem_encrypt_init() should do some more "generic" memory
encryption setup while the vendor-specific one should be concentrated in
vendor-specific calls.

But this is all meh - there are vendor checks in all the memory encryption
paths so I'm not sure what we're even discussing here actually...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette