mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic
@ 2026-09-30 10:30 Peter Fang
  2026-09-30 10:30 ` [PATCH v6 1/6] x86/tdx: Take the Quote buffer as a generic pointer Peter Fang
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

Hi,

This is a quick v6 of the dynamic Quote buffer size series. It mainly
simplifies the buffer size helper. It no longer caches the size in a
static variable and leaves the page alignment decision to the callers.
So overall this version adds fewer LOC (7 lines fewer).

The no-cache implementation is based on the expectation that the TDX
module always reports the same size limit. So there is no need to do
defensive programming against it. If the host somehow manages to load a
broken TDX module, the guest is already compromised.

Another behavioral change versus v5 is in the existing -EFBIG defense
against a weird data size (introduced in [1]). v5 uses the page-aligned
buffer size for the check, while v6 uses the actual maximum size without
the page padding. Even though v5 doesn't cause the kernel to expose an
innocent page, v6 is the more correct behavior. Thanks to Rick for
calling out the page alignment issues [2].

Newer TDX modules have an ABI that tells the guest how big a Quote can
get. The Quote buffer no longer has to be a fixed size. So effectively:

  s/FIXED_BUF_SIZE/queried_buf_size/

... in the TDX guest driver.

Terminology
===========

A "TD Quote" is an attestation structure signed with a platform key. It
contains information about a TDX guest and the platform it's running on.

The "Quote buffer" in the TDX guest driver is a memory buffer shared
between the TDX guest and the host VMM to retrieve TD Quotes. It has a
header defined in the GHCI spec [3].

Device Identifier Composition Engine ("DICE") provides a framework for
layering attestation evidence. This replaces the SGX model of contacting
an Intel server to obtain a certificate.

Problem
=======

The fixed-size Quote buffer approach is not sustainable. As
cryptographic algorithms evolve, TD Quote sizes also grow. A previous
commit [4] increased the guest driver's fixed-size Quote buffer to 128KB
to accommodate DICE Quotes, but it may still be insufficient when those
Quotes use post-quantum cryptography (PQC). PQC certificate chains are
roughly 10x-15x larger than conventional ones, which can increase Quote
sizes significantly.

What's in this series
=====================

To avoid changing the driver whenever the Quote buffer becomes too
small, newer TDX modules report their largest possible Quote size via a
metadata field [5]. The guest driver uses this value, plus room for the
header, for its Quote buffer when available. Older TDX modules continue
to use the 128KB buffer.

Patches 1-4 refactor the existing fixed buffer handling. Patch 5 adds a
helper to query the new metadata field, and patch 6 then makes the
buffer size dynamic.

Patch 1/6: Take the Quote buffer as a generic pointer.
Patch 2/6: Give the Quote buffer an explicit type.
Patch 3/6: Calculate the Quote buffer size with struct_size().
Patch 4/6: Read the Quote buffer size from a helper.
Patch 5/6: Add a helper to read the QUOTE_MAX_SIZE metadata field.
Patch 6/6: The final s/FIXED_BUF_SIZE/queried_buf_size/, when available.

Base
====

This is based on tip/x86/tdx.

AI use
======

I used AI to help edit this cover letter and the changelogs, and to
collect and apply the review feedback on lore under my supervision. The
series also underwent AI code review. In v6, it caught a missing page
alignment for the GetQuote hypercall. The other comments were limited to
style suggestions and existing issues. Sashiko's __GFP_NOWARN suggestion
was adopted in v2, but it was dropped in v3.

v5: https://lore.kernel.org/all/20260928100913.2265687-1-peter.fang@intel.com/

Changes in v6:
 - Rebase onto tip/x86/tdx.
 - Use struct_size()/struct_size_t() directly, without the macro. [Dave]
 - Don't cache the Quote buffer size in the helper. [Rick]
 - Let the callers page-align the Quote buffer size. [Rick]
 - Add a comment for the Quote buffer size helper. [Dave]
 - Document that the reported size is fixed. [Dave, Rick]
 - Improve comments and changelogs. [Dave, Rick, Binbin]
 - Add Reviewed-by tags to patches 1 and 2. [Rick, Sathya, Binbin]

v4: https://lore.kernel.org/all/20260915092632.2822169-1-peter.fang@intel.com/

Changes in v5:
 - Give the Quote buffer an explicit type. [Dave]
 - Replace the quote_data_len global with a helper. [Dave, Xiaoyao]
 - Simplify tdx_get_max_quote_size(). [Dave]
 - Use EXPORT_SYMBOL_FOR_MODULES() instead of EXPORT_SYMBOL_GPL().
   [Xiaoyao, Dave]
 - Rename GET_QUOTE_DEFAULT_BUF_SIZE to TDX_DEFAULT_QUOTE_SIZE. [Dave]
 - Pick "size" over "len" when renaming TDX_QUOTE_BUF_LEN(). [Dave]
 - Drop the comment about the buddy allocator. [Dave]
 - Reorder the patches so that cleanups/refactoring come before the
   feature.
 - Add Kiryl's Reviewed-by to patch 3.
 - Drop the Reviewed-by tags from patches 4-6 as they were reworked.
 - Change the author of patch 6 to me, and credit Sathya in the log.

v3: https://lore.kernel.org/all/20260729122939.1340412-1-peter.fang@intel.com/

Changes in v4:
 - Update the TDCS_QUOTE_MAX_SIZE encoding to 0x9010000200000007.
 - Provide documentation for the metadata field. [Rick, Kiryl]
 - Document the reported size's properties. [Xiaoyao, Tony]
 - Page align quote_data_len unconditionally. [Xiaoyao]
 - Collect Reviewed-by tags. [Sathya, Tony, Xiaoyao, Binbin]

v2: https://lore.kernel.org/all/20260717214349.4075994-1-peter.fang@intel.com/

Changes in v3:
 - Split the v2 "Allocate Quote buffer dynamically" patch to do the
   refactoring first, then make the buffer size dynamic. [Dave]
 - Improve patterns for readability. [Dave]
 - Drop __GFP_NOWARN so an allocation failure warns. [Dave, Rick, Kiryl]
 - Add Binbin's Reviewed-by to patch 1.
 - Drop the Reviewed-by tags (Kiryl, Binbin) as the patch was reworked.

v1: https://lore.kernel.org/all/20260612110853.3188196-1-peter.fang@intel.com/

Changes in v2:
 - Collect Reviewed-by tags. [Kiryl, Xiaoyao, Binbin, Sathya]
 - Keep the explicit (u32) cast in tdx_get_max_quote_size(). [Binbin]
 - Calculate the Quote buffer size with struct_size_t(). [Kiryl, Binbin]
 - Add __GFP_NOWARN to the allocation since its size comes from the
   host. [sashiko]
 - Rename quote_data_size to quote_data_len. [Sathya]
 - Drop the Assisted-by tags, as AI was not used to write the code.

[1] c3fd16c3b98e ("virt: tdx-guest: Fix handling of host controlled
    'quote' buffer length")
[2] https://lore.kernel.org/all/42975a72efc3a0f96200c065cb86970e8f452625.camel@intel.com/
[3] Guest Hypervisor Communication Interface (GHCI) Specification,
    Version 1.5, Section "TDG.VP.VMCALL<GetQuote>"
[4] 43185067c6fd ("configfs-tsm-report: tdx_guest: Increase Quote buffer
    size to 128KB")
[5] Intel TDX Module ABI Definitions, August 2026 (community review),
    TD-scope metadata field "TD_QUOTE_MAX_SIZE"

Peter Fang (6):
  x86/tdx: Take the Quote buffer as a generic pointer
  virt: tdx-guest: Give the Quote buffer an explicit type
  virt: tdx-guest: Calculate the Quote buffer size safely
  virt: tdx-guest: Add a helper for the Quote buffer size
  x86/tdx: Add a helper to query maximum Quote size
  virt: tdx-guest: Make the Quote buffer size dynamic

 arch/x86/coco/tdx/tdx.c                 | 19 ++++++-
 arch/x86/include/asm/shared/tdx.h       |  1 +
 arch/x86/include/asm/tdx.h              |  4 +-
 drivers/virt/coco/tdx-guest/tdx-guest.c | 76 ++++++++++++++++---------
 4 files changed, 70 insertions(+), 30 deletions(-)


base-commit: a49e2d257594931772ab8f0024708c3076f3aa1d
-- 
2.53.0


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

* [PATCH v6 1/6] x86/tdx: Take the Quote buffer as a generic pointer
  2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
@ 2026-09-30 10:30 ` Peter Fang
  2026-09-30 10:30 ` [PATCH v6 2/6] virt: tdx-guest: Give the Quote buffer an explicit type Peter Fang
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

tdx_hcall_get_quote() takes a "u8 *" buffer unnecessarily. It is never
used as such, since only the buffer's memory address matters.

Accept a "void *" buffer instead. This avoids a cast to "u8 *" when a
later change gives the guest driver's Quote buffer an explicit type.

AI was used under supervision to collect/apply feedback, review code and
workshop logs.

Signed-off-by: Peter Fang <peter.fang@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
v6:
 - No code changes.
 - Explain the connection to the explicit Quote buffer type. [Rick]
 - Add Sathya's Reviewed-by.
v5:
 - New patch. Prepare for a typed Quote buffer. [Dave]
---
 arch/x86/coco/tdx/tdx.c    | 2 +-
 arch/x86/include/asm/tdx.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index a38e44401840..92c243851171 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -191,7 +191,7 @@ EXPORT_SYMBOL_FOR_MODULES(tdx_mcall_extend_rtmr, "tdx-guest");
  *
  * Return 0 on success or error code on failure.
  */
-u64 tdx_hcall_get_quote(u8 *buf, size_t size)
+u64 tdx_hcall_get_quote(void *buf, size_t size)
 {
 	/* Since buf is a shared memory, set the shared (decrypted) bits */
 	return _tdx_hypercall(TDVMCALL_GET_QUOTE, cc_mkdec(virt_to_phys(buf)), size, 0, 0);
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index e186dfe5bf88..97bf6c8e0d89 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -82,7 +82,7 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport);
 
 int tdx_mcall_extend_rtmr(u8 index, u8 *data);
 
-u64 tdx_hcall_get_quote(u8 *buf, size_t size);
+u64 tdx_hcall_get_quote(void *buf, size_t size);
 
 void __init tdx_dump_attributes(u64 td_attr);
 void __init tdx_dump_td_ctls(u64 td_ctls);
-- 
2.53.0


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

* [PATCH v6 2/6] virt: tdx-guest: Give the Quote buffer an explicit type
  2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
  2026-09-30 10:30 ` [PATCH v6 1/6] x86/tdx: Take the Quote buffer as a generic pointer Peter Fang
@ 2026-09-30 10:30 ` Peter Fang
  2026-09-30 10:30 ` [PATCH v6 3/6] virt: tdx-guest: Calculate the Quote buffer size safely Peter Fang
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

The Quote buffer is always a "struct tdx_quote_buf", but its global
pointer is a "void *". A function would have to convert it back to make
sense of it.

Declare the global with its actual type, and give it a better name.

This creates variable shadowing in wait_for_quote_completion(), so
rename its parameter for clarity.

AI was used under supervision to collect/apply feedback, review code and
workshop logs.

Signed-off-by: Peter Fang <peter.fang@intel.com>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
---
v6:
 - Drop the comment about the Quote buffer global. [Binbin]
 - Add Reviewed-by tags. [Rick, Sathya, Binbin]
v5:
 - New patch. [Dave]
---
 drivers/virt/coco/tdx-guest/tdx-guest.c | 36 ++++++++++++-------------
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index a21bd0376b74..83322cd7673a 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -191,8 +191,7 @@ struct tdx_quote_buf {
 	u8 data[];
 };
 
-/* Quote data buffer */
-static void *quote_data;
+static struct tdx_quote_buf *quote_buf;
 
 /* Lock to streamline quote requests */
 static DEFINE_MUTEX(quote_lock);
@@ -209,7 +208,7 @@ static long tdx_get_report0(struct tdx_report_req __user *req)
 			     USER_SOCKPTR(req->tdreport));
 }
 
-static void free_quote_buf(void *buf)
+static void free_quote_buf(struct tdx_quote_buf *buf)
 {
 	size_t len = PAGE_ALIGN(GET_QUOTE_BUF_SIZE);
 	unsigned int count = len >> PAGE_SHIFT;
@@ -222,25 +221,25 @@ static void free_quote_buf(void *buf)
 	free_pages_exact(buf, len);
 }
 
-static void *alloc_quote_buf(void)
+static struct tdx_quote_buf *alloc_quote_buf(void)
 {
 	size_t len = PAGE_ALIGN(GET_QUOTE_BUF_SIZE);
 	unsigned int count = len >> PAGE_SHIFT;
-	void *addr;
+	struct tdx_quote_buf *buf;
 
-	addr = alloc_pages_exact(len, GFP_KERNEL | __GFP_ZERO);
-	if (!addr)
+	buf = alloc_pages_exact(len, GFP_KERNEL | __GFP_ZERO);
+	if (!buf)
 		return NULL;
 
-	if (set_memory_decrypted((unsigned long)addr, count))
+	if (set_memory_decrypted((unsigned long)buf, count))
 		return NULL;
 
-	return addr;
+	return buf;
 }
 
 /*
  * wait_for_quote_completion() - Wait for Quote request completion
- * @quote_buf: Address of Quote buffer.
+ * @buf: Address of Quote buffer.
  * @timeout: Timeout in seconds to wait for the Quote generation.
  *
  * As per TDX GHCI v1.0 specification, sec titled "TDG.VP.VMCALL<GetQuote>",
@@ -249,7 +248,7 @@ static void *alloc_quote_buf(void)
  * or error code after processing is complete. So wait till the status
  * changes from GET_QUOTE_IN_FLIGHT or the request being timed out.
  */
-static int wait_for_quote_completion(struct tdx_quote_buf *quote_buf, u32 timeout)
+static int wait_for_quote_completion(struct tdx_quote_buf *buf, u32 timeout)
 {
 	int i = 0;
 
@@ -257,7 +256,7 @@ static int wait_for_quote_completion(struct tdx_quote_buf *quote_buf, u32 timeou
 	 * Quote requests usually take a few seconds to complete, so waking up
 	 * once per second to recheck the status is fine for this use case.
 	 */
-	while (quote_buf->status == GET_QUOTE_IN_FLIGHT && i++ < timeout) {
+	while (buf->status == GET_QUOTE_IN_FLIGHT && i++ < timeout) {
 		if (msleep_interruptible(MSEC_PER_SEC))
 			return -EINTR;
 	}
@@ -268,7 +267,6 @@ static int wait_for_quote_completion(struct tdx_quote_buf *quote_buf, u32 timeou
 static int tdx_report_new_locked(struct tsm_report *report)
 {
 	u8 *buf;
-	struct tdx_quote_buf *quote_buf = quote_data;
 	struct tsm_report_desc *desc = &report->desc;
 	u32 out_len;
 	int ret;
@@ -285,7 +283,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 	if (desc->inblob_len != TDX_REPORTDATA_LEN)
 		return -EINVAL;
 
-	memset(quote_data, 0, GET_QUOTE_BUF_SIZE);
+	memset(quote_buf, 0, GET_QUOTE_BUF_SIZE);
 
 	/* Update Quote buffer header */
 	quote_buf->version = GET_QUOTE_CMD_VER;
@@ -296,7 +294,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 	if (ret)
 		return ret;
 
-	err = tdx_hcall_get_quote(quote_data, GET_QUOTE_BUF_SIZE);
+	err = tdx_hcall_get_quote(quote_buf, GET_QUOTE_BUF_SIZE);
 	if (err) {
 		pr_err("GetQuote hypercall failed, status:%llx\n", err);
 		return -EIO;
@@ -417,8 +415,8 @@ static int __init tdx_guest_init(void)
 	if (ret)
 		goto deinit_mr;
 
-	quote_data = alloc_quote_buf();
-	if (!quote_data) {
+	quote_buf = alloc_quote_buf();
+	if (!quote_buf) {
 		pr_err("Failed to allocate Quote buffer\n");
 		ret = -ENOMEM;
 		goto free_misc;
@@ -431,7 +429,7 @@ static int __init tdx_guest_init(void)
 	return 0;
 
 free_quote:
-	free_quote_buf(quote_data);
+	free_quote_buf(quote_buf);
 free_misc:
 	misc_deregister(&tdx_misc_dev);
 deinit_mr:
@@ -444,7 +442,7 @@ module_init(tdx_guest_init);
 static void __exit tdx_guest_exit(void)
 {
 	tsm_report_unregister(&tdx_tsm_ops);
-	free_quote_buf(quote_data);
+	free_quote_buf(quote_buf);
 	misc_deregister(&tdx_misc_dev);
 	tdx_mr_deinit(tdx_attr_groups[0]);
 }
-- 
2.53.0


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

* [PATCH v6 3/6] virt: tdx-guest: Calculate the Quote buffer size safely
  2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
  2026-09-30 10:30 ` [PATCH v6 1/6] x86/tdx: Take the Quote buffer as a generic pointer Peter Fang
  2026-09-30 10:30 ` [PATCH v6 2/6] virt: tdx-guest: Give the Quote buffer an explicit type Peter Fang
@ 2026-09-30 10:30 ` Peter Fang
  2026-09-30 10:30 ` [PATCH v6 4/6] virt: tdx-guest: Add a helper for the Quote buffer size Peter Fang
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

struct tdx_quote_buf has a trailing flexible array member.
struct_size() calculates the size of this kind of struct safely. It
handles overflow, which helps since the Quote size comes from the host.

Use it to rewrite the bounds check logic, since

  "header_size + data_size > buf_size"

... is more readable than "data_size > buf_size - header_size".

This also prepares for a later change that needs the same
"header_size + data_size" calculation for the Quote buffer size.

AI was used under supervision to collect/apply feedback, review code and
workshop logs.

Signed-off-by: Peter Fang <peter.fang@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
---
v6:
 - Use struct_size() directly, without the macro. [Dave]
v5:
 - Pick "size" over "len" in the macro name. [Dave]
 - Add Kiryl's Reviewed-by.
v4:
 - No code changes.
 - Add Reviewed-by tags. [Sathya, Tony, Xiaoyao, Binbin]
v3:
 - Split out the use of struct_size_t() for buffer length from the v2
   "Allocate Quote buffer dynamically" patch to refactor first. [Dave]
 - Drop the Reviewed-by tags from v2 (Kiryl, Binbin) as the patch was
   reworked.
---
 drivers/virt/coco/tdx-guest/tdx-guest.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 83322cd7673a..77c63c3f820f 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -170,8 +170,6 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp)
 #define GET_QUOTE_SUCCESS		0
 #define GET_QUOTE_IN_FLIGHT		0xffffffffffffffff
 
-#define TDX_QUOTE_MAX_LEN		(GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_buf))
-
 /* struct tdx_quote_buf: Format of Quote request buffer.
  * @version: Quote format version, filled by TD.
  * @status: Status code of Quote request, filled by VMM.
@@ -313,7 +311,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 
 	out_len = READ_ONCE(quote_buf->out_len);
 
-	if (out_len > TDX_QUOTE_MAX_LEN)
+	if (struct_size(quote_buf, data, out_len) > GET_QUOTE_BUF_SIZE)
 		return -EFBIG;
 
 	buf = kvmemdup(quote_buf->data, out_len, GFP_KERNEL);
-- 
2.53.0


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

* [PATCH v6 4/6] virt: tdx-guest: Add a helper for the Quote buffer size
  2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
                   ` (2 preceding siblings ...)
  2026-09-30 10:30 ` [PATCH v6 3/6] virt: tdx-guest: Calculate the Quote buffer size safely Peter Fang
@ 2026-09-30 10:30 ` Peter Fang
  2026-09-30 10:30 ` [PATCH v6 5/6] x86/tdx: Add a helper to query maximum Quote size Peter Fang
  2026-09-30 10:30 ` [PATCH v6 6/6] virt: tdx-guest: Make the Quote buffer size dynamic Peter Fang
  5 siblings, 0 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

The Quote buffer size is a constant sprinkled across several places.
Read it from a helper instead. And rename the constant to avoid using a
verb.

This sets up the plumbing for a later change that makes the size
dynamic.

There are several "sizes" at play here: the raw Quote data, the Quote
buffer (the header metadata plus the raw data), and the allocation (the
page-padded Quote buffer). The helper returns the Quote buffer size and
leaves page alignment to callers that need it.

AI was used under supervision to collect/apply feedback, review code and
workshop logs.

Signed-off-by: Peter Fang <peter.fang@intel.com>
---
v6:
 - Don't cache the size in the helper. [Rick]
 - Let the callers page-align the buffer size. [Rick]
 - Add a comment for the helper. [Dave]
v5:
 - Reworked v4 3/4 to use a helper instead of a global. [Dave, Xiaoyao]
 - Use TDX_DEFAULT_QUOTE_SIZE instead of GET_QUOTE_DEFAULT_BUF_SIZE.
   [Dave]
 - Use "size" instead of "len" for buffer size variables. [Dave]
 - Drop the RB tags, as the code changed substantially.
---
 drivers/virt/coco/tdx-guest/tdx-guest.c | 31 +++++++++++++++++--------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 77c63c3f820f..0cf078f09a73 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -162,7 +162,7 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp)
  * DICE-based attestation uses layered evidence that requires
  * larger Quote size (~100K).
  */
-#define GET_QUOTE_BUF_SIZE		SZ_128K
+#define TDX_DEFAULT_QUOTE_SIZE		SZ_128K
 
 #define GET_QUOTE_CMD_VER		1
 
@@ -206,26 +206,36 @@ static long tdx_get_report0(struct tdx_report_req __user *req)
 			     USER_SOCKPTR(req->tdreport));
 }
 
+/* Size of the header metadata plus the largest possible raw Quote. */
+static size_t get_quote_buf_size(void)
+{
+	return TDX_DEFAULT_QUOTE_SIZE;
+}
+
 static void free_quote_buf(struct tdx_quote_buf *buf)
 {
-	size_t len = PAGE_ALIGN(GET_QUOTE_BUF_SIZE);
-	unsigned int count = len >> PAGE_SHIFT;
+	size_t alloc_size = PAGE_ALIGN(get_quote_buf_size());
+	unsigned int count;
+
+	count = alloc_size >> PAGE_SHIFT;
 
 	if (set_memory_encrypted((unsigned long)buf, count)) {
 		pr_err("Failed to restore encryption mask for Quote buffer, leak it\n");
 		return;
 	}
 
-	free_pages_exact(buf, len);
+	free_pages_exact(buf, alloc_size);
 }
 
 static struct tdx_quote_buf *alloc_quote_buf(void)
 {
-	size_t len = PAGE_ALIGN(GET_QUOTE_BUF_SIZE);
-	unsigned int count = len >> PAGE_SHIFT;
+	size_t alloc_size = PAGE_ALIGN(get_quote_buf_size());
 	struct tdx_quote_buf *buf;
+	unsigned int count;
 
-	buf = alloc_pages_exact(len, GFP_KERNEL | __GFP_ZERO);
+	count = alloc_size >> PAGE_SHIFT;
+
+	buf = alloc_pages_exact(alloc_size, GFP_KERNEL | __GFP_ZERO);
 	if (!buf)
 		return NULL;
 
@@ -266,6 +276,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 {
 	u8 *buf;
 	struct tsm_report_desc *desc = &report->desc;
+	size_t quote_buf_size = get_quote_buf_size();
 	u32 out_len;
 	int ret;
 	u64 err;
@@ -281,7 +292,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 	if (desc->inblob_len != TDX_REPORTDATA_LEN)
 		return -EINVAL;
 
-	memset(quote_buf, 0, GET_QUOTE_BUF_SIZE);
+	memset(quote_buf, 0, quote_buf_size);
 
 	/* Update Quote buffer header */
 	quote_buf->version = GET_QUOTE_CMD_VER;
@@ -292,7 +303,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 	if (ret)
 		return ret;
 
-	err = tdx_hcall_get_quote(quote_buf, GET_QUOTE_BUF_SIZE);
+	err = tdx_hcall_get_quote(quote_buf, PAGE_ALIGN(quote_buf_size));
 	if (err) {
 		pr_err("GetQuote hypercall failed, status:%llx\n", err);
 		return -EIO;
@@ -311,7 +322,7 @@ static int tdx_report_new_locked(struct tsm_report *report)
 
 	out_len = READ_ONCE(quote_buf->out_len);
 
-	if (struct_size(quote_buf, data, out_len) > GET_QUOTE_BUF_SIZE)
+	if (struct_size(quote_buf, data, out_len) > quote_buf_size)
 		return -EFBIG;
 
 	buf = kvmemdup(quote_buf->data, out_len, GFP_KERNEL);
-- 
2.53.0


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

* [PATCH v6 5/6] x86/tdx: Add a helper to query maximum Quote size
  2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
                   ` (3 preceding siblings ...)
  2026-09-30 10:30 ` [PATCH v6 4/6] virt: tdx-guest: Add a helper for the Quote buffer size Peter Fang
@ 2026-09-30 10:30 ` Peter Fang
  2026-09-30 10:30 ` [PATCH v6 6/6] virt: tdx-guest: Make the Quote buffer size dynamic Peter Fang
  5 siblings, 0 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

Newer crypto algorithms can make Quotes larger, so guests can no longer
rely on a fixed-size buffer.

The TDX module added a new ABI that reports the largest possible Quote
size via a metadata field [1]. Add a helper to query the size instead of
exposing tdg_vm_rd() directly, as it can read arbitrary metadata fields.

The reported size covers every Quote type the platform can produce,
including SGX-based Quotes.

AI was used under supervision to collect/apply feedback, review code and
workshop logs.

[1] Intel TDX Module ABI Definitions, August 2026, TD-scope metadata
    field "TD_QUOTE_MAX_SIZE"

Signed-off-by: Peter Fang <peter.fang@intel.com>
---
v6:
 - Drop the Xu Yilun credit line. [Dave]
 - Mention the host platform in the helper comment. [Rick]
v5:
 - Drop unused EXPORT_SYMBOL_GPL(). [Dave]
 - Use an error code to report failure. [Dave]
 - Drop the u32 cast. [Dave]
 - Replace the kernel-doc comment with a one-liner. [Dave]
 - Drop the RB tags, as the code changed substantially.
v4:
 - Update the TDCS_QUOTE_MAX_SIZE encoding to 0x9010000200000007. [1]
 - Provide documentation for the metadata field. [Rick, Kiryl]
 - Document that the reported size covers every Quote type. [Xiaoyao]
 - Document that a module update does not change the reported size.
   [Tony]
 - Add Tony's Reviewed-by.
v3:
 - No code changes. Add Binbin's Reviewed-by.
v2:
 - Keep the explicit (u32) cast to document the metadata field width.
   [Binbin]
 - Note that Xu Yilun's suggestion was made in an off-list discussion.
   [Sathya]
 - Drop the Assisted-by tags, as the code was not written by AI.
---
 arch/x86/coco/tdx/tdx.c           | 16 ++++++++++++++++
 arch/x86/include/asm/shared/tdx.h |  1 +
 arch/x86/include/asm/tdx.h        |  2 ++
 3 files changed, 19 insertions(+)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 92c243851171..02c2871b99d1 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -198,6 +198,22 @@ u64 tdx_hcall_get_quote(void *buf, size_t size)
 }
 EXPORT_SYMBOL_FOR_MODULES(tdx_hcall_get_quote, "tdx-guest");
 
+/*
+ * Ask the TDX module what the largest Quote on the host platform might be.
+ */
+int tdx_get_max_quote_size(u64 *max_quote_size)
+{
+	u64 err;
+
+	err = tdg_vm_rd(TDCS_QUOTE_MAX_SIZE, max_quote_size);
+
+	/* Old modules do not support this. Tell the caller. */
+	if (err)
+		return -EINVAL;
+
+	return 0;
+}
+
 static void __noreturn tdx_panic(const char *msg)
 {
 	struct tdx_module_args args = {
diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
index f2cfa71cf0ea..f1c543958028 100644
--- a/arch/x86/include/asm/shared/tdx.h
+++ b/arch/x86/include/asm/shared/tdx.h
@@ -50,6 +50,7 @@
 /* TDX TD-Scope Metadata. To be used by TDG.VM.WR and TDG.VM.RD */
 #define TDCS_CONFIG_FLAGS		0x1110000300000016
 #define TDCS_TD_CTLS			0x1110000300000017
+#define TDCS_QUOTE_MAX_SIZE		0x9010000200000007
 #define TDCS_NOTIFY_ENABLES		0x9100000000000010
 #define TDCS_TOPOLOGY_ENUM_CONFIGURED	0x9100000000000019
 
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 97bf6c8e0d89..1fcfaed515fe 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -84,6 +84,8 @@ int tdx_mcall_extend_rtmr(u8 index, u8 *data);
 
 u64 tdx_hcall_get_quote(void *buf, size_t size);
 
+int tdx_get_max_quote_size(u64 *max_quote_size);
+
 void __init tdx_dump_attributes(u64 td_attr);
 void __init tdx_dump_td_ctls(u64 td_ctls);
 
-- 
2.53.0


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

* [PATCH v6 6/6] virt: tdx-guest: Make the Quote buffer size dynamic
  2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
                   ` (4 preceding siblings ...)
  2026-09-30 10:30 ` [PATCH v6 5/6] x86/tdx: Add a helper to query maximum Quote size Peter Fang
@ 2026-09-30 10:30 ` Peter Fang
  5 siblings, 0 replies; 7+ messages in thread
From: Peter Fang @ 2026-09-30 10:30 UTC (permalink / raw)
  To: Dave Hansen, Kiryl Shutsemau, Rick Edgecombe, Kuppuswamy Sathyanarayanan
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, linux-kernel, linux-coco, kvm, Xiaoyao Li,
	Binbin Wu, Tony Lindgren, Sean Christopherson, Artem Bityutskiy,
	Peter Fang

Support a new TDX module ABI that reports the Quote size limit in a
metadata field. The fixed 128KB buffer in the driver may be too small
for Quotes that use new algorithms like post-quantum cryptography (PQC),
which can produce much larger certificates. With this ABI, the guest
sizes the buffer to the platform's needs and no longer has to rely on
some empirical number.

The shared buffer comes from the buddy allocator, as the host expects it
to be physically contiguous. The allocator's page order limit should be
sufficient for current attestation needs. Platforms that don't report
the limit fall back to the default 128KB buffer.

Assume the TDX module always reports the same size. It is a TDX module
bug if the size changes.

AI was used under supervision to collect/apply feedback, review code and
workshop logs.

Based on a patch originally by Kuppuswamy Sathyanarayanan.

Signed-off-by: Peter Fang <peter.fang@intel.com>
---
v6:
 - Use struct_size_t() directly, without the macro. [Dave]
 - Document that the reported size is fixed. [Dave, Rick]
v5:
 - Do the export here, and use EXPORT_SYMBOL_FOR_MODULES() instead.
   [Xiaoyao, Dave]
 - Drop the comment about the buddy allocator. [Dave]
 - Drop the RB tags, as the code changed substantially.
v4:
 - Move the PAGE_ALIGN() out of get_quote_buf_size(). [Xiaoyao]
 - Improve the get_quote_buf_size() pattern again.
 - Document that the reported size covers every Quote type. [Xiaoyao]
 - Document that a module update does not change the reported size.
   [Tony]
 - Add Tony's Reviewed-by.
v3:
 - Split out from the v2 "Allocate Quote buffer dynamically" patch. Add
   the dynamic buffer feature on top of the refactoring. [Dave]
 - Improve the get_quote_buf_size() pattern for better readability.
   [Dave]
 - Drop __GFP_NOWARN so an allocation failure warns. [Dave, Rick, Kiryl]
 - Drop the Reviewed-by tags from v2 (Kiryl, Binbin) as the patch was
   reworked.
---
 arch/x86/coco/tdx/tdx.c                 |  1 +
 drivers/virt/coco/tdx-guest/tdx-guest.c | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 02c2871b99d1..ad489f2abcf1 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -213,6 +213,7 @@ int tdx_get_max_quote_size(u64 *max_quote_size)
 
 	return 0;
 }
+EXPORT_SYMBOL_FOR_MODULES(tdx_get_max_quote_size, "tdx-guest");
 
 static void __noreturn tdx_panic(const char *msg)
 {
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 0cf078f09a73..11d741da3b35 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -209,7 +209,20 @@ static long tdx_get_report0(struct tdx_report_req __user *req)
 /* Size of the header metadata plus the largest possible raw Quote. */
 static size_t get_quote_buf_size(void)
 {
-	return TDX_DEFAULT_QUOTE_SIZE;
+	size_t buf_size;
+	u64 max_size;
+
+	/* Start with the default buffer size, which includes the header */
+	buf_size = TDX_DEFAULT_QUOTE_SIZE;
+
+	/*
+	 * Override the default when the TDX module reports a size. Add room
+	 * for the header metadata. The size is fixed during TD runtime.
+	 */
+	if (!tdx_get_max_quote_size(&max_size))
+		buf_size = struct_size_t(struct tdx_quote_buf, data, max_size);
+
+	return buf_size;
 }
 
 static void free_quote_buf(struct tdx_quote_buf *buf)
-- 
2.53.0


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

end of thread, other threads:[~2026-09-30 10:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-30 10:30 [PATCH v6 0/6] tdx-guest: Make Quote buffer size dynamic Peter Fang
2026-09-30 10:30 ` [PATCH v6 1/6] x86/tdx: Take the Quote buffer as a generic pointer Peter Fang
2026-09-30 10:30 ` [PATCH v6 2/6] virt: tdx-guest: Give the Quote buffer an explicit type Peter Fang
2026-09-30 10:30 ` [PATCH v6 3/6] virt: tdx-guest: Calculate the Quote buffer size safely Peter Fang
2026-09-30 10:30 ` [PATCH v6 4/6] virt: tdx-guest: Add a helper for the Quote buffer size Peter Fang
2026-09-30 10:30 ` [PATCH v6 5/6] x86/tdx: Add a helper to query maximum Quote size Peter Fang
2026-09-30 10:30 ` [PATCH v6 6/6] virt: tdx-guest: Make the Quote buffer size dynamic Peter Fang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®