From b674e6cd2b6a68f891bf386df5c93e220b5b1a36 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Fri, 12 Jun 2026 02:32:06 +0000 Subject: [PATCH] x86/tdx: Add TDG.MR.KEY.GET ABI support Add support for the TDG.MR.KEY.GET TDCALL, which derives a persistent, hardware-bound sealing key for the TD customized to its measurements and policy. Add the tdx_mcall_key_get() wrapper, the TDX_CMD_KEY_GET ioctl with its tdx_key_get_req UAPI structure, and the tdx_guest driver handler that marshals the TDKEYREQUEST input and key output buffers with the alignment required by the TDX module ABI. [mishih: fix typos and a misplaced apostrophe from the original patch; use _IOWR since the ioctl both reads the request and writes back the key and error code; document that kmalloc()/kzalloc() satisfy the 128B and 32B buffer alignment for these power-of-two sizes; write err_code back on success so callers do not observe a stale value; and use kfree_sensitive() to clear keying material] Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Ming-Wei Shih --- arch/x86/coco/tdx/tdx.c | 20 ++++++++++ arch/x86/include/asm/shared/tdx.h | 1 + arch/x86/include/asm/tdx.h | 2 + drivers/virt/coco/tdx-guest/tdx-guest.c | 50 +++++++++++++++++++++++++ include/uapi/linux/tdx-guest.h | 27 +++++++++++++ 5 files changed, 100 insertions(+) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index a36081cbf5a37..79a34365292f3 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -178,6 +178,26 @@ int tdx_mcall_extend_rtmr(u8 index, u8 *data) } EXPORT_SYMBOL_GPL(tdx_mcall_extend_rtmr); +/** + * tdx_mcall_key_get() - Wrapper to derive a persistent key for the TD, + * customized to the TD's measurements and policy + * using TDG.MR.KEY.GET TDCALL. + * @indata: Address of the input buffer with TDKEYREQUEST data. + * @outdata: Address of the output buffer with the requested key data. + * + * Return 0 on success or error code on other TDCALL failures. + */ +u64 tdx_mcall_key_get(u8 *indata, u8 *outdata) +{ + struct tdx_module_args args = { + .rcx = virt_to_phys(indata), + .rdx = virt_to_phys(outdata), + }; + + return __tdcall(TDG_MR_KEY_GET, &args); +} +EXPORT_SYMBOL_GPL(tdx_mcall_key_get); + /** * tdx_hcall_get_quote() - Wrapper to request TD Quote using GetQuote * hypercall. diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h index 8bc074c8d7c6a..6d8c3212d752d 100644 --- a/arch/x86/include/asm/shared/tdx.h +++ b/arch/x86/include/asm/shared/tdx.h @@ -19,6 +19,7 @@ #define TDG_MEM_PAGE_ACCEPT 6 #define TDG_VM_RD 7 #define TDG_VM_WR 8 +#define TDG_MR_KEY_GET 29 /* TDX attributes */ #define TDX_ATTR_DEBUG_BIT 0 diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 0237accf6bd07..806d69de6007c 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -72,6 +72,8 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport); int tdx_mcall_extend_rtmr(u8 index, u8 *data); +u64 tdx_mcall_key_get(u8 *indata, u8 *outdata); + u64 tdx_hcall_get_quote(u8 *buf, size_t size); void __init tdx_dump_attributes(u64 td_attr); diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c index 4e239ec960c9b..f3fe3f1c7d5e4 100644 --- a/drivers/virt/coco/tdx-guest/tdx-guest.c +++ b/drivers/virt/coco/tdx-guest/tdx-guest.c @@ -206,6 +206,54 @@ static long tdx_get_report0(struct tdx_report_req __user *req) USER_SOCKPTR(req->tdreport)); } +static long tdx_key_get(struct tdx_key_get_req __user *req) +{ + u8 *indata = NULL, *outdata = NULL; + long ret = 0; + u64 err; + + /* + * TDG.MR.KEY.GET expects the TDKEYREQUEST input buffer to be 128B + * aligned and the key output buffer to be 32B aligned. kmalloc() + * guarantees alignment to the allocation size for power-of-two sizes, + * and TDX_TDKEYREQ_LEN (128) and TDX_KEY_LEN (32) are both powers of + * two, so the returned buffers meet the required alignment. + */ + indata = kmalloc(sizeof(req->tdkeyreq), GFP_KERNEL); + if (!indata) + return -ENOMEM; + + outdata = kzalloc(sizeof(req->outkey), GFP_KERNEL); + if (!outdata) { + ret = -ENOMEM; + goto out; + } + + if (copy_from_user(indata, req->tdkeyreq, sizeof(req->tdkeyreq))) { + ret = -EFAULT; + goto out; + } + + /* Get derived key using "TDG.MR.KEY.GET" TDCALL */ + err = tdx_mcall_key_get(indata, outdata); + if (err) { + ret = -EIO; + if (copy_to_user(&req->err_code, &err, sizeof(u64))) + ret = -EFAULT; + goto out; + } + + /* On success, write back the derived key and clear err_code (0) */ + if (copy_to_user(&req->err_code, &err, sizeof(u64)) || + copy_to_user(&req->outkey, outdata, sizeof(req->outkey))) + ret = -EFAULT; + +out: + kfree_sensitive(indata); + kfree_sensitive(outdata); + return ret; +} + static void free_quote_buf(void *buf) { size_t len = PAGE_ALIGN(GET_QUOTE_BUF_SIZE); @@ -353,6 +401,8 @@ static long tdx_guest_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case TDX_CMD_GET_REPORT0: return tdx_get_report0((struct tdx_report_req __user *)arg); + case TDX_CMD_KEY_GET: + return tdx_key_get((struct tdx_key_get_req __user *)arg); default: return -ENOTTY; } diff --git a/include/uapi/linux/tdx-guest.h b/include/uapi/linux/tdx-guest.h index a6a2098c08ff5..e31cc1a1f2d24 100644 --- a/include/uapi/linux/tdx-guest.h +++ b/include/uapi/linux/tdx-guest.h @@ -17,6 +17,12 @@ /* Length of TDREPORT used in TDG.MR.REPORT TDCALL */ #define TDX_REPORT_LEN 1024 +/* TDKEYREQ struct length */ +#define TDX_TDKEYREQ_LEN 128 + +/* Length of the derived key */ +#define TDX_KEY_LEN 32 + /** * struct tdx_report_req - Request struct for TDX_CMD_GET_REPORT0 IOCTL. * @@ -30,6 +36,19 @@ struct tdx_report_req { __u8 tdreport[TDX_REPORT_LEN]; }; +/** + * struct tdx_key_get_req - Request struct for TDX_CMD_KEY_GET IOCTL. + * + * @tdkeyreq: TDKEYREQ struct. + * @outkey: Derived key output + * @err_code: TDG.MR.KEY.GET TDCALL return error code. + */ +struct tdx_key_get_req { + __u8 tdkeyreq[TDX_TDKEYREQ_LEN]; + __u8 outkey[TDX_KEY_LEN]; + __u64 err_code; +}; + /* * TDX_CMD_GET_REPORT0 - Get TDREPORT0 (a.k.a. TDREPORT subtype 0) using * TDCALL[TDG.MR.REPORT] @@ -39,4 +58,12 @@ struct tdx_report_req { */ #define TDX_CMD_GET_REPORT0 _IOWR('T', 1, struct tdx_report_req) +/* + * TDX_CMD_KEY_GET - Request to derive a persistent key for the TD, + * customized to the TD's measurements and policy. + * + * Returns 0 on success, and standard errno on other failures. + */ +#define TDX_CMD_KEY_GET _IOWR('T', 5, struct tdx_key_get_req) + #endif /* _UAPI_LINUX_TDX_GUEST_H_ */