Subject: [PATCH v2 0/6] Add TDX Guest Support (Attestation support)

Hi All,

Intel's Trust Domain Extensions (TDX) protect guest VMs from malicious
hosts and some physical attacks. VM guest with TDX support is called
as TD Guest.

In TD Guest, the attestationĀ process is used to verify the
trustworthiness of TD guest to the 3rd party servers. Such attestation
process is required by 3rd party servers before sending sensitive
information to TD guests. One usage example is to get encryption keys
from the key server for mounting the encrypted rootfs or secondary drive.

Following patches adds the attestation support to TDX guest which
includes attestation user interface driver, user agent example, and
related hypercall support.

In this series, only following patches are in arch/x86 and are
intended for x86 maintainers review.

* x86/tdx: Add TDREPORT TDX Module call support
* x86/tdx: Add GetQuote TDX hypercall support
* x86/tdx: Add SetupEventNotifyInterrupt TDX hypercall support

Patch titled "platform/x86: intel_tdx_attest: Add TDX Guest attestation
interface driver" adds the attestation driver support. This is supposed
to be reviewed by platform-x86 maintainers.

Also, patch titled "tools/tdx: Add a sample attestation user app" adds
a testing app for attestation feature which needs review from
[email protected].

This series is the continuation of the following TDX patch series which
added basic TDX guest support.

[set 1] - https://lore.kernel.org/patchwork/project/lkml/list/?series=505232
[set 2] - https://lore.kernel.org/patchwork/project/lkml/list/?series=506230
[set 3] - https://lore.kernel.org/patchwork/project/lkml/list/?series=506231
[set 4] - https://lore.kernel.org/patchwork/project/lkml/list/?series=506232
[set 5] - https://lore.kernel.org/patchwork/project/lkml/list/?series=506233

Also please note that this series alone is not necessarily fully
functional.

You can find TDX related documents in the following link.

https://software.intel.com/content/www/br/pt/develop/articles/intel-trust-domain-extensions.html

Changes since v1:
* Included platform-x86 and test tool maintainers in recipient list.
* Fixed commit log and comments in attestation driver as per Han's comments.


Kuppuswamy Sathyanarayanan (6):
x86/tdx: Add TDREPORT TDX Module call support
x86/tdx: Add GetQuote TDX hypercall support
x86/tdx: Add SetupEventNotifyInterrupt TDX hypercall support
x86/tdx: Add TDX Guest event notify interrupt vector support
platform/x86: intel_tdx_attest: Add TDX Guest attestation interface
driver
tools/tdx: Add a sample attestation user app

arch/x86/include/asm/hardirq.h | 1 +
arch/x86/include/asm/idtentry.h | 4 +
arch/x86/include/asm/irq_vectors.h | 7 +-
arch/x86/include/asm/tdx.h | 6 +
arch/x86/kernel/irq.c | 7 +
arch/x86/kernel/tdx.c | 129 +++++++++++++
drivers/platform/x86/Kconfig | 9 +
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/intel_tdx_attest.c | 171 +++++++++++++++++
include/uapi/misc/tdx.h | 37 ++++
tools/Makefile | 13 +-
tools/tdx/Makefile | 19 ++
tools/tdx/attest/.gitignore | 2 +
tools/tdx/attest/Makefile | 24 +++
tools/tdx/attest/tdx-attest-test.c | 232 ++++++++++++++++++++++++
15 files changed, 655 insertions(+), 7 deletions(-)
create mode 100644 drivers/platform/x86/intel_tdx_attest.c
create mode 100644 include/uapi/misc/tdx.h
create mode 100644 tools/tdx/Makefile
create mode 100644 tools/tdx/attest/.gitignore
create mode 100644 tools/tdx/attest/Makefile
create mode 100644 tools/tdx/attest/tdx-attest-test.c

--
2.25.1


Subject: [PATCH v2 4/6] x86/tdx: Add TDX Guest event notify interrupt vector support

Allocate 0xec IRQ vector address for TDX guest to receive the event
completion notification from VMM. Since this vector address will be
sent to VMM via hypercall, allocate a fixed address and move
LOCAL_TIMER_VECTOR vector address by 1 byte. Also add related IDT
handler to process the notification event.

It will be mainly used by attestation driver to receive Quote event
completion notification from host.

Add support to track the notification event status via /proc/interrupts.

Reviewed-by: Tony Luck <[email protected]>
Reviewed-by: Andi Kleen <[email protected]>
Signed-off-by: Kuppuswamy Sathyanarayanan <[email protected]>
---
arch/x86/include/asm/hardirq.h | 1 +
arch/x86/include/asm/idtentry.h | 4 +++
arch/x86/include/asm/irq_vectors.h | 7 ++++-
arch/x86/include/asm/tdx.h | 2 ++
arch/x86/kernel/irq.c | 7 +++++
arch/x86/kernel/tdx.c | 41 ++++++++++++++++++++++++++++++
6 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 07d79fa9c5c6..40d0534e7d82 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -46,6 +46,7 @@ typedef struct {
#endif
#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
unsigned int tdg_ve_count;
+ unsigned int irq_tdg_event_notify_count;
#endif
} ____cacheline_aligned irq_cpustat_t;

diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
index d3c779abbc78..fad1b0110c88 100644
--- a/arch/x86/include/asm/idtentry.h
+++ b/arch/x86/include/asm/idtentry.h
@@ -702,6 +702,10 @@ DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_xen_hvm_callback);
DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_kvm_asyncpf_interrupt);
#endif

+#ifdef CONFIG_INTEL_TDX_GUEST
+DECLARE_IDTENTRY_SYSVEC(TDX_GUEST_EVENT_NOTIFY_VECTOR, sysvec_tdg_event_notify);
+#endif
+
#undef X86_TRAP_OTHER

#endif
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 889f8b1b5b7f..a1550f237ef6 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -104,7 +104,12 @@
#define HYPERV_STIMER0_VECTOR 0xed
#endif

-#define LOCAL_TIMER_VECTOR 0xec
+#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
+/* Vector on which TDX Guest event notification is delivered */
+#define TDX_GUEST_EVENT_NOTIFY_VECTOR 0xec
+#endif
+
+#define LOCAL_TIMER_VECTOR 0xeb

#define NR_VECTORS 256

diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 1599aa4850e5..a7ebc6e448d7 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -100,6 +100,8 @@ int tdx_mcall_tdreport(u64 data, u64 reportdata);

int tdx_hcall_get_quote(u64 data);

+extern void (*tdg_event_notify_handler)(void);
+
/*
* To support I/O port access in decompressor or early kernel init
* code, since #VE exception handler cannot be used, use paravirt
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 669869bd46ec..a4fe53c8c18f 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -182,11 +182,18 @@ int arch_show_interrupts(struct seq_file *p, int prec)
irq_stats(j)->kvm_posted_intr_wakeup_ipis);
seq_puts(p, " Posted-interrupt wakeup event\n");
#endif
+
#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
seq_printf(p, "%*s: ", prec, "TGV");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->tdg_ve_count);
seq_puts(p, " TDX Guest VE event\n");
+
+ seq_printf(p, "%*s: ", prec, "TGN");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ irq_stats(j)->irq_tdg_event_notify_count);
+ seq_puts(p, " TDX Guest event notification\n");
#endif
return 0;
}
diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c
index fcb0ed70ea19..f08fd6ae44b3 100644
--- a/arch/x86/kernel/tdx.c
+++ b/arch/x86/kernel/tdx.c
@@ -11,6 +11,11 @@
#include <asm/tdx.h>
#include <asm/cmdline.h>
#include <asm/i8259.h>
+#include <asm/apic.h>
+#include <asm/idtentry.h>
+#include <asm/irq_regs.h>
+#include <asm/desc.h>
+#include <asm/idtentry.h>
#include <asm/vmx.h>
#include <asm/insn.h>
#include <asm/insn-eval.h>
@@ -52,6 +57,14 @@ static struct {
unsigned long attributes;
} td_info __ro_after_init;

+/*
+ * Currently it will be used only by the attestation
+ * driver. So, race condition with read/write operation
+ * is not considered.
+ */
+void (*tdg_event_notify_handler)(void);
+EXPORT_SYMBOL_GPL(tdg_event_notify_handler);
+
/*
* Wrapper for standard use of __tdx_hypercall with BUG_ON() check
* for TDCALL error.
@@ -150,6 +163,28 @@ static bool tdg_perfmon_enabled(void)
return td_info.attributes & BIT(63);
}

+/* TDX guest event notification handler */
+DEFINE_IDTENTRY_SYSVEC(sysvec_tdg_event_notify)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ inc_irq_stat(irq_tdg_event_notify_count);
+
+ if (tdg_event_notify_handler)
+ tdg_event_notify_handler();
+
+ /*
+ * The hypervisor requires that the APIC EOI should be acked.
+ * If the APIC EOI is not acked, the APIC ISR bit for the
+ * TDX_GUEST_EVENT_NOTIFY_VECTOR will not be cleared and then it
+ * will block the interrupt whose vector is lower than
+ * TDX_GUEST_EVENT_NOTIFY_VECTOR.
+ */
+ ack_APIC_irq();
+
+ set_irq_regs(old_regs);
+}
+
/*
* tdx_mcall_tdreport() - Generate TDREPORT_STRUCT using TDCALL.
*
@@ -712,5 +747,11 @@ void __init tdx_early_init(void)
lock_kernel_down("TDX guest init", lockdown_reason);
}

+ alloc_intr_gate(TDX_GUEST_EVENT_NOTIFY_VECTOR,
+ asm_sysvec_tdg_event_notify);
+
+ if (tdx_hcall_set_notify_intr(TDX_GUEST_EVENT_NOTIFY_VECTOR))
+ pr_warn("Setting event notification interrupt failed\n");
+
pr_info("Guest initialized\n");
}
--
2.25.1

Subject: [PATCH v2 6/6] tools/tdx: Add a sample attestation user app

This application uses the misc device /dev/tdx-attest to get TDREPORT
from the TDX Module or request quote from the VMM.

It tests following attestation features:

- Get report using TDX_CMD_GET_TDREPORT IOCTL.
- Using report data request quote from VMM using TDX_CMD_GEN_QUOTE IOCTL.
- Get the quote size using TDX_CMD_GET_QUOTE_SIZE IOCTL.

Reviewed-by: Tony Luck <[email protected]>
Reviewed-by: Andi Kleen <[email protected]>
Signed-off-by: Kuppuswamy Sathyanarayanan <[email protected]>
---
tools/Makefile | 13 +-
tools/tdx/Makefile | 19 +++
tools/tdx/attest/.gitignore | 2 +
tools/tdx/attest/Makefile | 24 +++
tools/tdx/attest/tdx-attest-test.c | 232 +++++++++++++++++++++++++++++
5 files changed, 284 insertions(+), 6 deletions(-)
create mode 100644 tools/tdx/Makefile
create mode 100644 tools/tdx/attest/.gitignore
create mode 100644 tools/tdx/attest/Makefile
create mode 100644 tools/tdx/attest/tdx-attest-test.c

diff --git a/tools/Makefile b/tools/Makefile
index 7e9d34ddd74c..5d68084511cb 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -30,6 +30,7 @@ help:
@echo ' selftests - various kernel selftests'
@echo ' bootconfig - boot config tool'
@echo ' spi - spi tools'
+ @echo ' tdx - TDX related test tools'
@echo ' tmon - thermal monitoring and tuning tool'
@echo ' tracing - misc tracing tools'
@echo ' turbostat - Intel CPU idle stats and freq reporting tool'
@@ -65,7 +66,7 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)

-cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing: FORCE
+cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing tdx: FORCE
$(call descend,$@)

bpf/%: FORCE
@@ -104,7 +105,7 @@ all: acpi cgroup cpupower gpio hv firewire liblockdep \
perf selftests bootconfig spi turbostat usb \
virtio vm bpf x86_energy_perf_policy \
tmon freefall iio objtool kvm_stat wmi \
- pci debugging tracing
+ pci debugging tracing tdx

acpi_install:
$(call descend,power/$(@:_install=),install)
@@ -112,7 +113,7 @@ acpi_install:
cpupower_install:
$(call descend,power/$(@:_install=),install)

-cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install:
+cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install tdx_install:
$(call descend,$(@:_install=),install)

liblockdep_install:
@@ -139,7 +140,7 @@ install: acpi_install cgroup_install cpupower_install gpio_install \
virtio_install vm_install bpf_install x86_energy_perf_policy_install \
tmon_install freefall_install objtool_install kvm_stat_install \
wmi_install pci_install debugging_install intel-speed-select_install \
- tracing_install
+ tracing_install tdx_install

acpi_clean:
$(call descend,power/acpi,clean)
@@ -147,7 +148,7 @@ acpi_clean:
cpupower_clean:
$(call descend,power/cpupower,clean)

-cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean:
+cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean tdx_clean:
$(call descend,$(@:_clean=),clean)

liblockdep_clean:
@@ -186,6 +187,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
gpio_clean objtool_clean leds_clean wmi_clean pci_clean firmware_clean debugging_clean \
- intel-speed-select_clean tracing_clean
+ intel-speed-select_clean tracing_clean tdx_clean

.PHONY: FORCE
diff --git a/tools/tdx/Makefile b/tools/tdx/Makefile
new file mode 100644
index 000000000000..e2564557d463
--- /dev/null
+++ b/tools/tdx/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+include ../scripts/Makefile.include
+
+all: attest
+
+clean: attest_clean
+
+install: attest_install
+
+attest:
+ $(call descend,attest)
+
+attest_install:
+ $(call descend,attest,install)
+
+attest_clean:
+ $(call descend,attest,clean)
+
+.PHONY: all install clean attest latency_install latency_clean
diff --git a/tools/tdx/attest/.gitignore b/tools/tdx/attest/.gitignore
new file mode 100644
index 000000000000..5f819a8a6c49
--- /dev/null
+++ b/tools/tdx/attest/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+tdx-attest-test
diff --git a/tools/tdx/attest/Makefile b/tools/tdx/attest/Makefile
new file mode 100644
index 000000000000..bf47ba718386
--- /dev/null
+++ b/tools/tdx/attest/Makefile
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for vm tools
+#
+VAR_CFLAGS := $(shell pkg-config --cflags libtracefs 2>/dev/null)
+VAR_LDLIBS := $(shell pkg-config --libs libtracefs 2>/dev/null)
+
+TARGETS = tdx-attest-test
+CFLAGS = -static -Wall -Wextra -g -O2 $(VAR_CFLAGS)
+LDFLAGS = -lpthread $(VAR_LDLIBS)
+
+all: $(TARGETS)
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
+clean:
+ $(RM) tdx-attest-test
+
+prefix ?= /usr/local
+sbindir ?= ${prefix}/sbin
+
+install: all
+ install -d $(DESTDIR)$(sbindir)
+ install -m 755 -p $(TARGETS) $(DESTDIR)$(sbindir)
diff --git a/tools/tdx/attest/tdx-attest-test.c b/tools/tdx/attest/tdx-attest-test.c
new file mode 100644
index 000000000000..7634ec6a084c
--- /dev/null
+++ b/tools/tdx/attest/tdx-attest-test.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * tdx-attest-test.c - utility to test TDX attestation feature.
+ *
+ * Copyright (C) 2020 - 2021 Intel Corporation. All rights reserved.
+ *
+ * Author: Kuppuswamy Sathyanarayanan <[email protected]>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include <stdint.h> /* uintmax_t */
+#include <sys/mman.h>
+#include <unistd.h> /* sysconf */
+#include <time.h>
+
+#include "../../../include/uapi/misc/tdx.h"
+
+#define devname "/dev/tdx-attest"
+
+#define HEX_DUMP_SIZE 16
+#define MAX_ROW_SIZE 70
+
+#define ATTESTATION_TEST_BIN_VERSION "0.1"
+
+struct tdx_attest_args {
+ bool is_dump_data;
+ bool is_get_tdreport;
+ bool is_get_quote_size;
+ bool is_gen_quote;
+ bool debug_mode;
+ char *out_file;
+};
+
+static void print_hex_dump(const char *title, const char *prefix_str,
+ const void *buf, int len)
+{
+ const __u8 *ptr = buf;
+ int i, rowsize = HEX_DUMP_SIZE;
+
+ if (!len || !buf)
+ return;
+
+ printf("\t\t%s", title);
+
+ for (i = 0; i < len; i++) {
+ if (!(i % rowsize))
+ printf("\n%s%.8x:", prefix_str, i);
+ printf(" %.2x", ptr[i])
+ }
+
+ printf("\n");
+}
+
+static void gen_report_data(__u8 *report_data, bool dump_data)
+{
+ int i;
+
+ srand(time(NULL));
+
+ for (i = 0; i < TDX_REPORT_DATA_LEN; i++)
+ report_data[i] = rand();
+
+ if (dump_data)
+ print_hex_dump("\n\t\tTDX report data\n", " ",
+ report_data, TDX_REPORT_DATA_LEN);
+}
+
+static int get_tdreport(int devfd, bool dump_data, __u8 *report_data)
+{
+ __u8 tdrdata[TDX_TDREPORT_LEN] = {0};
+ int ret;
+
+ if (!report_data)
+ report_data = tdrdata;
+
+ gen_report_data(report_data, dump_data);
+
+ ret = ioctl(devfd, TDX_CMD_GET_TDREPORT, report_data);
+ if (ret) {
+ printf("TDX_CMD_GET_TDREPORT ioctl() %d failed\n", ret);
+ return -EIO;
+ }
+
+ if (dump_data)
+ print_hex_dump("\n\t\tTDX tdreport data\n", " ", report_data,
+ TDX_TDREPORT_LEN);
+
+ return 0;
+}
+
+static __u64 get_quote_size(int devfd)
+{
+ int ret;
+ __u64 quote_size;
+
+ ret = ioctl(devfd, TDX_CMD_GET_QUOTE_SIZE, &quote_size);
+ if (ret) {
+ printf("TDX_CMD_GET_QUOTE_SIZE ioctl() %d failed\n", ret);
+ return -EIO;
+ }
+
+ printf("Quote size: %lld\n", quote_size);
+
+ return quote_size;
+}
+
+static int gen_quote(int devfd, bool dump_data)
+{
+ __u8 *quote_data;
+ __u64 quote_size;
+ int ret;
+
+ quote_size = get_quote_size(devfd);
+
+ quote_data = malloc(sizeof(char) * quote_size);
+ if (!quote_data) {
+ printf("%s queue data alloc failed\n", devname);
+ return -ENOMEM;
+ }
+
+ ret = get_tdreport(devfd, dump_data, quote_data);
+ if (ret) {
+ printf("TDX_CMD_GET_TDREPORT ioctl() %d failed\n", ret);
+ goto done;
+ }
+
+ ret = ioctl(devfd, TDX_CMD_GEN_QUOTE, quote_data);
+ if (ret) {
+ printf("TDX_CMD_GEN_QUOTE ioctl() %d failed\n", ret);
+ goto done;
+ }
+
+ print_hex_dump("\n\t\tTDX Quote MMIO data\n", " ", quote_data,
+ quote_size);
+
+done:
+ free(quote_data);
+
+ return ret;
+}
+
+static void usage(void)
+{
+ puts("\nUsage:\n");
+ puts("tdx_attest [options] \n");
+
+ puts("Attestation device test utility.");
+
+ puts("\nOptions:\n");
+ puts(" -d, --dump Dump tdreport/tdquote data");
+ puts(" -r, --get-tdreport Get TDREPORT data");
+ puts(" -g, --gen-quote Generate TDQUOTE");
+ puts(" -s, --get-quote-size Get TDQUOTE size");
+}
+
+int main(int argc, char **argv)
+{
+ int ret, devfd;
+ struct tdx_attest_args args = {0};
+
+ static const struct option longopts[] = {
+ { "dump", no_argument, NULL, 'd' },
+ { "get-tdreport", required_argument, NULL, 'r' },
+ { "gen-quote", required_argument, NULL, 'g' },
+ { "gen-quote-size", required_argument, NULL, 's' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((ret = getopt_long(argc, argv, "hdrgsV", longopts,
+ NULL)) != -1) {
+ switch (ret) {
+ case 'd':
+ args.is_dump_data = true;
+ break;
+ case 'r':
+ args.is_get_tdreport = true;
+ break;
+ case 'g':
+ args.is_gen_quote = true;
+ break;
+ case 's':
+ args.is_get_quote_size = true;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'V':
+ printf("Version: %s\n", ATTESTATION_TEST_BIN_VERSION);
+ return 0;
+ default:
+ printf("Invalid options\n");
+ usage();
+ return -EINVAL;
+ }
+ }
+
+ devfd = open(devname, O_RDWR | O_SYNC);
+ if (devfd < 0) {
+ printf("%s open() failed\n", devname);
+ return -ENODEV;
+ }
+
+ if (args.is_get_quote_size)
+ get_quote_size(devfd);
+
+ if (args.is_get_tdreport)
+ get_tdreport(devfd, args.is_dump_data, NULL);
+
+ if (args.is_gen_quote)
+ gen_quote(devfd, args.is_dump_data);
+
+ close(devfd);
+
+ return 0;
+}
--
2.25.1

2021-07-15 10:48:27

by Yousaf Kaukab

[permalink] [raw]
Subject: Re: [PATCH v2 6/6] tools/tdx: Add a sample attestation user app

On Wed, Jul 07, 2021 at 01:42:49PM -0700, Kuppuswamy Sathyanarayanan wrote:
> This application uses the misc device /dev/tdx-attest to get TDREPORT
> from the TDX Module or request quote from the VMM.
>
> It tests following attestation features:
>
> - Get report using TDX_CMD_GET_TDREPORT IOCTL.
> - Using report data request quote from VMM using TDX_CMD_GEN_QUOTE IOCTL.
> - Get the quote size using TDX_CMD_GET_QUOTE_SIZE IOCTL.
>
> Reviewed-by: Tony Luck <[email protected]>
> Reviewed-by: Andi Kleen <[email protected]>
> Signed-off-by: Kuppuswamy Sathyanarayanan <[email protected]>
> ---
> tools/Makefile | 13 +-
> tools/tdx/Makefile | 19 +++
> tools/tdx/attest/.gitignore | 2 +
> tools/tdx/attest/Makefile | 24 +++
> tools/tdx/attest/tdx-attest-test.c | 232 +++++++++++++++++++++++++++++
> 5 files changed, 284 insertions(+), 6 deletions(-)
> create mode 100644 tools/tdx/Makefile
> create mode 100644 tools/tdx/attest/.gitignore
> create mode 100644 tools/tdx/attest/Makefile
> create mode 100644 tools/tdx/attest/tdx-attest-test.c
>
> diff --git a/tools/Makefile b/tools/Makefile
> index 7e9d34ddd74c..5d68084511cb 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -30,6 +30,7 @@ help:
> @echo ' selftests - various kernel selftests'
> @echo ' bootconfig - boot config tool'
> @echo ' spi - spi tools'
> + @echo ' tdx - TDX related test tools'
> @echo ' tmon - thermal monitoring and tuning tool'
> @echo ' tracing - misc tracing tools'
> @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
> @@ -65,7 +66,7 @@ acpi: FORCE
> cpupower: FORCE
> $(call descend,power/$@)
>
> -cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing: FORCE
> +cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing tdx: FORCE
> $(call descend,$@)
>
> bpf/%: FORCE
> @@ -104,7 +105,7 @@ all: acpi cgroup cpupower gpio hv firewire liblockdep \
> perf selftests bootconfig spi turbostat usb \
> virtio vm bpf x86_energy_perf_policy \
> tmon freefall iio objtool kvm_stat wmi \
> - pci debugging tracing
> + pci debugging tracing tdx
>
> acpi_install:
> $(call descend,power/$(@:_install=),install)
> @@ -112,7 +113,7 @@ acpi_install:
> cpupower_install:
> $(call descend,power/$(@:_install=),install)
>
> -cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install:
> +cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install tdx_install:
> $(call descend,$(@:_install=),install)
>
> liblockdep_install:
> @@ -139,7 +140,7 @@ install: acpi_install cgroup_install cpupower_install gpio_install \
> virtio_install vm_install bpf_install x86_energy_perf_policy_install \
> tmon_install freefall_install objtool_install kvm_stat_install \
> wmi_install pci_install debugging_install intel-speed-select_install \
> - tracing_install
> + tracing_install tdx_install
>
> acpi_clean:
> $(call descend,power/acpi,clean)
> @@ -147,7 +148,7 @@ acpi_clean:
> cpupower_clean:
> $(call descend,power/cpupower,clean)
>
> -cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean:
> +cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean tdx_clean:
> $(call descend,$(@:_clean=),clean)
>
> liblockdep_clean:
> @@ -186,6 +187,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
> vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
> freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
> gpio_clean objtool_clean leds_clean wmi_clean pci_clean firmware_clean debugging_clean \
> - intel-speed-select_clean tracing_clean
> + intel-speed-select_clean tracing_clean tdx_clean
>
> .PHONY: FORCE
> diff --git a/tools/tdx/Makefile b/tools/tdx/Makefile
> new file mode 100644
> index 000000000000..e2564557d463
> --- /dev/null
> +++ b/tools/tdx/Makefile
> @@ -0,0 +1,19 @@
> +# SPDX-License-Identifier: GPL-2.0
> +include ../scripts/Makefile.include
> +
> +all: attest
> +
> +clean: attest_clean
> +
> +install: attest_install
> +
> +attest:
> + $(call descend,attest)
> +
> +attest_install:
> + $(call descend,attest,install)
> +
> +attest_clean:
> + $(call descend,attest,clean)
> +
> +.PHONY: all install clean attest latency_install latency_clean
> diff --git a/tools/tdx/attest/.gitignore b/tools/tdx/attest/.gitignore
> new file mode 100644
> index 000000000000..5f819a8a6c49
> --- /dev/null
> +++ b/tools/tdx/attest/.gitignore
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +tdx-attest-test
> diff --git a/tools/tdx/attest/Makefile b/tools/tdx/attest/Makefile
> new file mode 100644
> index 000000000000..bf47ba718386
> --- /dev/null
> +++ b/tools/tdx/attest/Makefile
> @@ -0,0 +1,24 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Makefile for vm tools
> +#
> +VAR_CFLAGS := $(shell pkg-config --cflags libtracefs 2>/dev/null)
> +VAR_LDLIBS := $(shell pkg-config --libs libtracefs 2>/dev/null)
> +
> +TARGETS = tdx-attest-test
> +CFLAGS = -static -Wall -Wextra -g -O2 $(VAR_CFLAGS)
> +LDFLAGS = -lpthread $(VAR_LDLIBS)
> +
> +all: $(TARGETS)
> +
> +%: %.c
> + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
> +
> +clean:
> + $(RM) tdx-attest-test
> +
> +prefix ?= /usr/local
> +sbindir ?= ${prefix}/sbin
> +
> +install: all
> + install -d $(DESTDIR)$(sbindir)
> + install -m 755 -p $(TARGETS) $(DESTDIR)$(sbindir)
> diff --git a/tools/tdx/attest/tdx-attest-test.c b/tools/tdx/attest/tdx-attest-test.c
> new file mode 100644
> index 000000000000..7634ec6a084c
> --- /dev/null
> +++ b/tools/tdx/attest/tdx-attest-test.c
> @@ -0,0 +1,232 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * tdx-attest-test.c - utility to test TDX attestation feature.
> + *
> + * Copyright (C) 2020 - 2021 Intel Corporation. All rights reserved.
> + *
> + * Author: Kuppuswamy Sathyanarayanan <[email protected]>
> + *
> + */
> +
> +#include <linux/types.h>
> +#include <linux/ioctl.h>
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <stdio.h>
> +#include <ctype.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <stdbool.h>
> +#include <getopt.h>
> +#include <stdint.h> /* uintmax_t */
> +#include <sys/mman.h>
> +#include <unistd.h> /* sysconf */
> +#include <time.h>
> +
> +#include "../../../include/uapi/misc/tdx.h"
> +
> +#define devname "/dev/tdx-attest"
> +
> +#define HEX_DUMP_SIZE 16
> +#define MAX_ROW_SIZE 70
> +
> +#define ATTESTATION_TEST_BIN_VERSION "0.1"
> +
> +struct tdx_attest_args {
> + bool is_dump_data;
> + bool is_get_tdreport;
> + bool is_get_quote_size;
> + bool is_gen_quote;
> + bool debug_mode;
> + char *out_file;
> +};
> +
> +static void print_hex_dump(const char *title, const char *prefix_str,
> + const void *buf, int len)
> +{
> + const __u8 *ptr = buf;
> + int i, rowsize = HEX_DUMP_SIZE;
> +
> + if (!len || !buf)
> + return;
> +
> + printf("\t\t%s", title);
> +
> + for (i = 0; i < len; i++) {
> + if (!(i % rowsize))
> + printf("\n%s%.8x:", prefix_str, i);
> + printf(" %.2x", ptr[i])
> + }
> +
> + printf("\n");
> +}
> +
> +static void gen_report_data(__u8 *report_data, bool dump_data)
> +{
> + int i;
> +
> + srand(time(NULL));
> +
> + for (i = 0; i < TDX_REPORT_DATA_LEN; i++)
> + report_data[i] = rand();
> +
> + if (dump_data)
> + print_hex_dump("\n\t\tTDX report data\n", " ",
> + report_data, TDX_REPORT_DATA_LEN);
> +}
> +
> +static int get_tdreport(int devfd, bool dump_data, __u8 *report_data)
> +{
> + __u8 tdrdata[TDX_TDREPORT_LEN] = {0};
> + int ret;
> +
> + if (!report_data)
> + report_data = tdrdata;
> +
> + gen_report_data(report_data, dump_data);
> +
> + ret = ioctl(devfd, TDX_CMD_GET_TDREPORT, report_data);
> + if (ret) {
> + printf("TDX_CMD_GET_TDREPORT ioctl() %d failed\n", ret);
> + return -EIO;
> + }
> +
> + if (dump_data)
> + print_hex_dump("\n\t\tTDX tdreport data\n", " ", report_data,
> + TDX_TDREPORT_LEN);
> +
> + return 0;
> +}
> +
> +static __u64 get_quote_size(int devfd)
> +{
> + int ret;
> + __u64 quote_size;
> +
> + ret = ioctl(devfd, TDX_CMD_GET_QUOTE_SIZE, &quote_size);
> + if (ret) {
> + printf("TDX_CMD_GET_QUOTE_SIZE ioctl() %d failed\n", ret);
> + return -EIO;
> + }
> +
> + printf("Quote size: %lld\n", quote_size);
> +
> + return quote_size;
> +}
> +
> +static int gen_quote(int devfd, bool dump_data)
> +{
> + __u8 *quote_data;
> + __u64 quote_size;
> + int ret;
> +
> + quote_size = get_quote_size(devfd);
> +
> + quote_data = malloc(sizeof(char) * quote_size);
> + if (!quote_data) {
> + printf("%s queue data alloc failed\n", devname);
> + return -ENOMEM;
> + }
> +
> + ret = get_tdreport(devfd, dump_data, quote_data);
In tdg_attest_ioctl() TDX_CMD_GEN_QUOTE case is calling
tdx_mcall_tdreport() same as TDX_CMD_GET_TDREPORT case. Then what is
the point of calling get_tdreport() here? Do you mean to call
gen_report_data()?
> + if (ret) {
> + printf("TDX_CMD_GET_TDREPORT ioctl() %d failed\n", ret);
> + goto done;
> + }
> +
> + ret = ioctl(devfd, TDX_CMD_GEN_QUOTE, quote_data);
> + if (ret) {
> + printf("TDX_CMD_GEN_QUOTE ioctl() %d failed\n", ret);
> + goto done;
> + }
> +
> + print_hex_dump("\n\t\tTDX Quote MMIO data\n", " ", quote_data,
> + quote_size);
> +
> +done:
> + free(quote_data);
> +
> + return ret;
> +}
> +
> +static void usage(void)
> +{
> + puts("\nUsage:\n");
> + puts("tdx_attest [options] \n");
> +
> + puts("Attestation device test utility.");
> +
> + puts("\nOptions:\n");
> + puts(" -d, --dump Dump tdreport/tdquote data");
> + puts(" -r, --get-tdreport Get TDREPORT data");
> + puts(" -g, --gen-quote Generate TDQUOTE");
> + puts(" -s, --get-quote-size Get TDQUOTE size");
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int ret, devfd;
> + struct tdx_attest_args args = {0};
> +
> + static const struct option longopts[] = {
> + { "dump", no_argument, NULL, 'd' },
> + { "get-tdreport", required_argument, NULL, 'r' },
> + { "gen-quote", required_argument, NULL, 'g' },
> + { "gen-quote-size", required_argument, NULL, 's' },
> + { "version", no_argument, NULL, 'V' },
> + { NULL, 0, NULL, 0 }
> + };
> +
> + while ((ret = getopt_long(argc, argv, "hdrgsV", longopts,
> + NULL)) != -1) {
> + switch (ret) {
> + case 'd':
> + args.is_dump_data = true;
> + break;
> + case 'r':
> + args.is_get_tdreport = true;
> + break;
> + case 'g':
> + args.is_gen_quote = true;
> + break;
> + case 's':
> + args.is_get_quote_size = true;
> + break;
> + case 'h':
> + usage();
> + return 0;
> + case 'V':
> + printf("Version: %s\n", ATTESTATION_TEST_BIN_VERSION);
> + return 0;
> + default:
> + printf("Invalid options\n");
> + usage();
> + return -EINVAL;
> + }
> + }
> +
> + devfd = open(devname, O_RDWR | O_SYNC);
> + if (devfd < 0) {
> + printf("%s open() failed\n", devname);
> + return -ENODEV;
> + }
> +
> + if (args.is_get_quote_size)
> + get_quote_size(devfd);
> +
> + if (args.is_get_tdreport)
> + get_tdreport(devfd, args.is_dump_data, NULL);
> +
> + if (args.is_gen_quote)
> + gen_quote(devfd, args.is_dump_data);
> +
> + close(devfd);
> +
> + return 0;
> +}
> --
> 2.25.1

BR,
Yousaf

Subject: Re: [PATCH v2 6/6] tools/tdx: Add a sample attestation user app



On 7/15/21 1:36 AM, Mian Yousaf Kaukab wrote:
> In tdg_attest_ioctl() TDX_CMD_GEN_QUOTE case is calling
> tdx_mcall_tdreport() same as TDX_CMD_GET_TDREPORT case. Then what is
> the point of calling get_tdreport() here? Do you mean to call
> gen_report_data()?

Yes, I also noticed this issue and fixed the attestation driver to
to get TDREPORT data as input to get TDQUOTE.

I will be posting the fixed version of attestation driver today.


--
Sathyanarayanan Kuppuswamy
Linux Kernel Developer