Skip to content

Commit 4f557d9

Browse files
author
Herton R. Krzesinski
committed
Merge: tdx: add the attestation driver
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/1678 Depends: !875 Bugzilla: https://bugzilla.redhat.com/2076749 Signed-off-by: Wander Lairson Costa <wander@redhat.com> 9a8d981638e4 (Wander Lairson Costa) selftests/tdx: Test TDX attestation GetReport support a2db4e40c4bf (Wander Lairson Costa) virt: Add TDX guest driver bd82437ab18d (Wander Lairson Costa) x86/tdx: Add a wrapper to get TDREPORT0 from the TDX Module Approved-by: Vitaly Kuznetsov <vkuznets@redhat.com> Approved-by: David Arcari <darcari@redhat.com> Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
2 parents 7d36d7c + 06275de commit 4f557d9

File tree

16 files changed

+470
-0
lines changed

16 files changed

+470
-0
lines changed
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

1819
.. only:: html and subproject
1920

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
@@ -41,4 +41,6 @@ source "drivers/virt/coco/efi_secret/Kconfig"
4141

4242
source "drivers/virt/coco/sev-guest/Kconfig"
4343

44+
source "drivers/virt/coco/tdx-guest/Kconfig"
45+
4446
endif

drivers/virt/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/
1010
obj-$(CONFIG_ACRN_HSM) += acrn/
1111
obj-$(CONFIG_EFI_SECRET) += coco/efi_secret/
1212
obj-$(CONFIG_SEV_GUEST) += coco/sev-guest/
13+
obj-$(CONFIG_INTEL_TDX_GUEST) += coco/tdx-guest/
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.
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");

0 commit comments

Comments
 (0)