Skip to content

Commit a89ef2a

Browse files
committed
Merge tag 'x86_tdx_for_6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 tdx updates from Dave Hansen: "This includes a single chunk of new functionality for TDX guests which allows them to talk to the trusted TDX module software and obtain an attestation report. This report can then be used to prove the trustworthiness of the guest to a third party and get access to things like storage encryption keys" * tag 'x86_tdx_for_6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: selftests/tdx: Test TDX attestation GetReport support virt: Add TDX guest driver x86/tdx: Add a wrapper to get TDREPORT0 from the TDX Module
2 parents 2da68a7 + 00e07cf commit a89ef2a

File tree

15 files changed

+469
-0
lines changed

15 files changed

+469
-0
lines changed

Documentation/virt/coco/tdx-guest.rst

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
===================================================================
4+
TDX Guest API Documentation
5+
===================================================================
6+
7+
1. General description
8+
======================
9+
10+
The TDX guest driver exposes IOCTL interfaces via the /dev/tdx-guest misc
11+
device to allow userspace to get certain TDX guest-specific details.
12+
13+
2. API description
14+
==================
15+
16+
In this section, for each supported IOCTL, the following information is
17+
provided along with a generic description.
18+
19+
:Input parameters: Parameters passed to the IOCTL and related details.
20+
:Output: Details about output data and return value (with details about
21+
the non common error values).
22+
23+
2.1 TDX_CMD_GET_REPORT0
24+
-----------------------
25+
26+
:Input parameters: struct tdx_report_req
27+
:Output: Upon successful execution, TDREPORT data is copied to
28+
tdx_report_req.tdreport and return 0. Return -EINVAL for invalid
29+
operands, -EIO on TDCALL failure or standard error number on other
30+
common failures.
31+
32+
The TDX_CMD_GET_REPORT0 IOCTL can be used by the attestation software to get
33+
the TDREPORT0 (a.k.a. TDREPORT subtype 0) from the TDX module using
34+
TDCALL[TDG.MR.REPORT].
35+
36+
A subtype index is added at the end of this IOCTL CMD to uniquely identify the
37+
subtype-specific TDREPORT request. Although the subtype option is mentioned in
38+
the TDX Module v1.0 specification, section titled "TDG.MR.REPORT", it is not
39+
currently used, and it expects this value to be 0. So to keep the IOCTL
40+
implementation simple, the subtype option was not included as part of the input
41+
ABI. However, in the future, if the TDX Module supports more than one subtype,
42+
a new IOCTL CMD will be created to handle it. To keep the IOCTL naming
43+
consistent, a subtype index is added as part of the IOCTL CMD.
44+
45+
Reference
46+
---------
47+
48+
TDX reference material is collected here:
49+
50+
https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html
51+
52+
The driver is based on TDX module specification v1.0 and TDX GHCI specification v1.0.

Documentation/virt/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Linux Virtualization Support
1414
ne_overview
1515
acrn/index
1616
coco/sev-guest
17+
coco/tdx-guest
1718
hyperv/index
1819

1920
.. only:: html and subproject

Documentation/x86/tdx.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,49 @@ converted to shared on boot.
210210
For coherent DMA allocation, the DMA buffer gets converted on the
211211
allocation. Check force_dma_unencrypted() for details.
212212

213+
Attestation
214+
===========
215+
216+
Attestation is used to verify the TDX guest trustworthiness to other
217+
entities before provisioning secrets to the guest. For example, a key
218+
server may want to use attestation to verify that the guest is the
219+
desired one before releasing the encryption keys to mount the encrypted
220+
rootfs or a secondary drive.
221+
222+
The TDX module records the state of the TDX guest in various stages of
223+
the guest boot process using the build time measurement register (MRTD)
224+
and runtime measurement registers (RTMR). Measurements related to the
225+
guest initial configuration and firmware image are recorded in the MRTD
226+
register. Measurements related to initial state, kernel image, firmware
227+
image, command line options, initrd, ACPI tables, etc are recorded in
228+
RTMR registers. For more details, as an example, please refer to TDX
229+
Virtual Firmware design specification, section titled "TD Measurement".
230+
At TDX guest runtime, the attestation process is used to attest to these
231+
measurements.
232+
233+
The attestation process consists of two steps: TDREPORT generation and
234+
Quote generation.
235+
236+
TDX guest uses TDCALL[TDG.MR.REPORT] to get the TDREPORT (TDREPORT_STRUCT)
237+
from the TDX module. TDREPORT is a fixed-size data structure generated by
238+
the TDX module which contains guest-specific information (such as build
239+
and boot measurements), platform security version, and the MAC to protect
240+
the integrity of the TDREPORT. A user-provided 64-Byte REPORTDATA is used
241+
as input and included in the TDREPORT. Typically it can be some nonce
242+
provided by attestation service so the TDREPORT can be verified uniquely.
243+
More details about the TDREPORT can be found in Intel TDX Module
244+
specification, section titled "TDG.MR.REPORT Leaf".
245+
246+
After getting the TDREPORT, the second step of the attestation process
247+
is to send it to the Quoting Enclave (QE) to generate the Quote. TDREPORT
248+
by design can only be verified on the local platform as the MAC key is
249+
bound to the platform. To support remote verification of the TDREPORT,
250+
TDX leverages Intel SGX Quoting Enclave to verify the TDREPORT locally
251+
and convert it to a remotely verifiable Quote. Method of sending TDREPORT
252+
to QE is implementation specific. Attestation software can choose
253+
whatever communication channel available (i.e. vsock or TCP/IP) to
254+
send the TDREPORT to QE and receive the Quote.
255+
213256
References
214257
==========
215258

arch/x86/coco/tdx/tdx.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#define pr_fmt(fmt) "tdx: " fmt
66

77
#include <linux/cpufeature.h>
8+
#include <linux/export.h>
9+
#include <linux/io.h>
810
#include <asm/coco.h>
911
#include <asm/tdx.h>
1012
#include <asm/vmx.h>
@@ -15,6 +17,7 @@
1517
/* TDX module Call Leaf IDs */
1618
#define TDX_GET_INFO 1
1719
#define TDX_GET_VEINFO 3
20+
#define TDX_GET_REPORT 4
1821
#define TDX_ACCEPT_PAGE 6
1922

2023
/* TDX hypercall Leaf IDs */
@@ -36,6 +39,12 @@
3639

3740
#define ATTR_SEPT_VE_DISABLE BIT(28)
3841

42+
/* TDX Module call error codes */
43+
#define TDCALL_RETURN_CODE(a) ((a) >> 32)
44+
#define TDCALL_INVALID_OPERAND 0xc0000100
45+
46+
#define TDREPORT_SUBTYPE_0 0
47+
3948
/*
4049
* Wrapper for standard use of __tdx_hypercall with no output aside from
4150
* return code.
@@ -100,6 +109,37 @@ static inline void tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9,
100109
panic("TDCALL %lld failed (Buggy TDX module!)\n", fn);
101110
}
102111

112+
/**
113+
* tdx_mcall_get_report0() - Wrapper to get TDREPORT0 (a.k.a. TDREPORT
114+
* subtype 0) using TDG.MR.REPORT TDCALL.
115+
* @reportdata: Address of the input buffer which contains user-defined
116+
* REPORTDATA to be included into TDREPORT.
117+
* @tdreport: Address of the output buffer to store TDREPORT.
118+
*
119+
* Refer to section titled "TDG.MR.REPORT leaf" in the TDX Module
120+
* v1.0 specification for more information on TDG.MR.REPORT TDCALL.
121+
* It is used in the TDX guest driver module to get the TDREPORT0.
122+
*
123+
* Return 0 on success, -EINVAL for invalid operands, or -EIO on
124+
* other TDCALL failures.
125+
*/
126+
int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport)
127+
{
128+
u64 ret;
129+
130+
ret = __tdx_module_call(TDX_GET_REPORT, virt_to_phys(tdreport),
131+
virt_to_phys(reportdata), TDREPORT_SUBTYPE_0,
132+
0, NULL);
133+
if (ret) {
134+
if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)
135+
return -EINVAL;
136+
return -EIO;
137+
}
138+
139+
return 0;
140+
}
141+
EXPORT_SYMBOL_GPL(tdx_mcall_get_report0);
142+
103143
static void tdx_parse_tdinfo(u64 *cc_mask)
104144
{
105145
struct tdx_module_output out;

arch/x86/include/asm/tdx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ void tdx_safe_halt(void);
6767

6868
bool tdx_early_handle_ve(struct pt_regs *regs);
6969

70+
int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport);
71+
7072
#else
7173

7274
static inline void tdx_early_init(void) { };

drivers/virt/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,6 @@ source "drivers/virt/coco/efi_secret/Kconfig"
5252

5353
source "drivers/virt/coco/sev-guest/Kconfig"
5454

55+
source "drivers/virt/coco/tdx-guest/Kconfig"
56+
5557
endif

drivers/virt/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/
1111
obj-$(CONFIG_ACRN_HSM) += acrn/
1212
obj-$(CONFIG_EFI_SECRET) += coco/efi_secret/
1313
obj-$(CONFIG_SEV_GUEST) += coco/sev-guest/
14+
obj-$(CONFIG_INTEL_TDX_GUEST) += coco/tdx-guest/

drivers/virt/coco/tdx-guest/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
config TDX_GUEST_DRIVER
2+
tristate "TDX Guest driver"
3+
depends on INTEL_TDX_GUEST
4+
help
5+
The driver provides userspace interface to communicate with
6+
the TDX module to request the TDX guest details like attestation
7+
report.
8+
9+
To compile this driver as module, choose M here. The module will
10+
be called tdx-guest.

drivers/virt/coco/tdx-guest/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
obj-$(CONFIG_TDX_GUEST_DRIVER) += tdx-guest.o
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* TDX guest user interface driver
4+
*
5+
* Copyright (C) 2022 Intel Corporation
6+
*/
7+
8+
#include <linux/kernel.h>
9+
#include <linux/miscdevice.h>
10+
#include <linux/mm.h>
11+
#include <linux/module.h>
12+
#include <linux/mod_devicetable.h>
13+
#include <linux/string.h>
14+
#include <linux/uaccess.h>
15+
16+
#include <uapi/linux/tdx-guest.h>
17+
18+
#include <asm/cpu_device_id.h>
19+
#include <asm/tdx.h>
20+
21+
static long tdx_get_report0(struct tdx_report_req __user *req)
22+
{
23+
u8 *reportdata, *tdreport;
24+
long ret;
25+
26+
reportdata = kmalloc(TDX_REPORTDATA_LEN, GFP_KERNEL);
27+
if (!reportdata)
28+
return -ENOMEM;
29+
30+
tdreport = kzalloc(TDX_REPORT_LEN, GFP_KERNEL);
31+
if (!tdreport) {
32+
ret = -ENOMEM;
33+
goto out;
34+
}
35+
36+
if (copy_from_user(reportdata, req->reportdata, TDX_REPORTDATA_LEN)) {
37+
ret = -EFAULT;
38+
goto out;
39+
}
40+
41+
/* Generate TDREPORT0 using "TDG.MR.REPORT" TDCALL */
42+
ret = tdx_mcall_get_report0(reportdata, tdreport);
43+
if (ret)
44+
goto out;
45+
46+
if (copy_to_user(req->tdreport, tdreport, TDX_REPORT_LEN))
47+
ret = -EFAULT;
48+
49+
out:
50+
kfree(reportdata);
51+
kfree(tdreport);
52+
53+
return ret;
54+
}
55+
56+
static long tdx_guest_ioctl(struct file *file, unsigned int cmd,
57+
unsigned long arg)
58+
{
59+
switch (cmd) {
60+
case TDX_CMD_GET_REPORT0:
61+
return tdx_get_report0((struct tdx_report_req __user *)arg);
62+
default:
63+
return -ENOTTY;
64+
}
65+
}
66+
67+
static const struct file_operations tdx_guest_fops = {
68+
.owner = THIS_MODULE,
69+
.unlocked_ioctl = tdx_guest_ioctl,
70+
.llseek = no_llseek,
71+
};
72+
73+
static struct miscdevice tdx_misc_dev = {
74+
.name = KBUILD_MODNAME,
75+
.minor = MISC_DYNAMIC_MINOR,
76+
.fops = &tdx_guest_fops,
77+
};
78+
79+
static const struct x86_cpu_id tdx_guest_ids[] = {
80+
X86_MATCH_FEATURE(X86_FEATURE_TDX_GUEST, NULL),
81+
{}
82+
};
83+
MODULE_DEVICE_TABLE(x86cpu, tdx_guest_ids);
84+
85+
static int __init tdx_guest_init(void)
86+
{
87+
if (!x86_match_cpu(tdx_guest_ids))
88+
return -ENODEV;
89+
90+
return misc_register(&tdx_misc_dev);
91+
}
92+
module_init(tdx_guest_init);
93+
94+
static void __exit tdx_guest_exit(void)
95+
{
96+
misc_deregister(&tdx_misc_dev);
97+
}
98+
module_exit(tdx_guest_exit);
99+
100+
MODULE_AUTHOR("Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>");
101+
MODULE_DESCRIPTION("TDX Guest Driver");
102+
MODULE_LICENSE("GPL");

include/uapi/linux/tdx-guest.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
/*
3+
* Userspace interface for TDX guest driver
4+
*
5+
* Copyright (C) 2022 Intel Corporation
6+
*/
7+
8+
#ifndef _UAPI_LINUX_TDX_GUEST_H_
9+
#define _UAPI_LINUX_TDX_GUEST_H_
10+
11+
#include <linux/ioctl.h>
12+
#include <linux/types.h>
13+
14+
/* Length of the REPORTDATA used in TDG.MR.REPORT TDCALL */
15+
#define TDX_REPORTDATA_LEN 64
16+
17+
/* Length of TDREPORT used in TDG.MR.REPORT TDCALL */
18+
#define TDX_REPORT_LEN 1024
19+
20+
/**
21+
* struct tdx_report_req - Request struct for TDX_CMD_GET_REPORT0 IOCTL.
22+
*
23+
* @reportdata: User buffer with REPORTDATA to be included into TDREPORT.
24+
* Typically it can be some nonce provided by attestation
25+
* service, so the generated TDREPORT can be uniquely verified.
26+
* @tdreport: User buffer to store TDREPORT output from TDCALL[TDG.MR.REPORT].
27+
*/
28+
struct tdx_report_req {
29+
__u8 reportdata[TDX_REPORTDATA_LEN];
30+
__u8 tdreport[TDX_REPORT_LEN];
31+
};
32+
33+
/*
34+
* TDX_CMD_GET_REPORT0 - Get TDREPORT0 (a.k.a. TDREPORT subtype 0) using
35+
* TDCALL[TDG.MR.REPORT]
36+
*
37+
* Return 0 on success, -EIO on TDCALL execution failure, and
38+
* standard errno on other general error cases.
39+
*/
40+
#define TDX_CMD_GET_REPORT0 _IOWR('T', 1, struct tdx_report_req)
41+
42+
#endif /* _UAPI_LINUX_TDX_GUEST_H_ */

tools/testing/selftests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ TARGETS += sync
7474
TARGETS += syscall_user_dispatch
7575
TARGETS += sysctl
7676
TARGETS += tc-testing
77+
TARGETS += tdx
7778
TARGETS += timens
7879
ifneq (1, $(quicktest))
7980
TARGETS += timers

tools/testing/selftests/tdx/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
CFLAGS += -O3 -Wl,-no-as-needed -Wall -static
4+
5+
TEST_GEN_PROGS := tdx_guest_test
6+
7+
include ../lib.mk

tools/testing/selftests/tdx/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_TDX_GUEST_DRIVER=y

0 commit comments

Comments
 (0)