blob: d9a25cfc4ec09823b5f1c09d1c5e407839f36a7a [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Date: Tue, 23 Jan 2024 00:16:47 +0000
Subject: [PATCH] virt: tdx-guest: Add runtime measurement update (RTMR)
support
VM measurement data is used during the attestation process to validate
the state and trustworthiness of the VM. After boot, an OS application
may want to extend the measurements data to record the new state.
Generally VMs use TPM interface for such operations (tpm2_pcrextend),
which can extend the VM measurements via PCR registers. But not all
platforms emulate the TPM device or enable full stack TPM support. To
allow users to extend VM measurements in the non TPM environment, TSM
exposes ConfigFS ABI to extend and read VM measurements.
In TDX guest, the runtime measurement data is stored in four RTMR
registers and TDCALLs can be used to securely update/read the RTMR
registers.
Extend the RTMR TSM ConfigFS ABI and TDX guest support.
A typical usage looks like below:
rtmr=/sys/kernel/config/tsm/rtmrs/rtmr2
mkdir $rtmr
echo 2 > $rtmr/index
dd if=/dev/urandom bs=48 count=1 > $rtmr/digest
hexdump -C $rtmr/digest
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
drivers/virt/coco/tdx-guest/tdx-guest.c | 103 ++++++++++++++++++++++++
1 file changed, 103 insertions(+)
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 1253bf76b5703..e01581fe21a60 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/tsm.h>
#include <linux/sizes.h>
+#include <linux/bits.h>
#include <uapi/linux/tdx-guest.h>
@@ -35,6 +36,12 @@
#define GET_QUOTE_SUCCESS 0
#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff
+/* TDX RTMR macros */
+#define RTMR_INDEX_USER_APPLICATION 2
+#define RTMR_INDEX_SPECIAL 3
+#define RTMR_BUF_LEN 64
+#define TDREPORT_RTMR_OFFSET 720
+
/* 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.
@@ -249,6 +256,75 @@ static int tdx_report_new(struct tsm_report *report, void *data)
return ret;
}
+static int tdx_rtmr_extend(u32 index, const u8 *digest, size_t digest_size)
+{
+ /*
+ * Per Intel TDX Virtual Firmware Design Guide, section titled
+ * "Measurement Register Usage in TD", only RTMR index 2 or 3 can
+ * be used for userspace measurement extension.
+ */
+ if (index != RTMR_INDEX_USER_APPLICATION && index != RTMR_INDEX_SPECIAL) {
+ pr_err("RTMR extend failed, index %d is not allowed for user udpates\n",
+ index);
+ return -EINVAL;
+ }
+
+ /*
+ * Per TDX Module specification r1.0, section titled "RTMR: Run-Time
+ * Measurement Registers", RTMR extend only uses SHA384. Ensure
+ * digest size matches it.
+ */
+ if (digest_size != SHA384_DIGEST_SIZE) {
+ pr_err("RTMR extend failed, invalid digest size:%ld\n", digest_size);
+ return -EINVAL;
+ }
+
+ void *buf __free(kfree) = kzalloc(RTMR_BUF_LEN, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, digest, digest_size);
+
+ /* Extend RTMR registers using "TDG.MR.RTMR.EXTEND" TDCALL */
+ return tdx_mcall_rtmr_extend(index, buf);
+}
+
+static ssize_t tdx_rtmr_read(u32 index, u8 *digest, size_t digest_size)
+{
+ u8 *rtmr;
+ int ret;
+
+ /*
+ * Per TDX Module specification r1.0, section titled "RTMR: Run-Time
+ * Measurement Registers", RTMR extend only uses SHA384. Ensure
+ * digest size matches it.
+ */
+ if (digest_size != SHA384_DIGEST_SIZE) {
+ pr_err("RTMR read failed, invalid digest size:%ld\n", digest_size);
+ return -EINVAL;
+ }
+
+ u8 *reportdata __free(kfree) = kmalloc(TDX_REPORTDATA_LEN, GFP_KERNEL);
+ if (!reportdata)
+ return -ENOMEM;
+
+ u8 *tdreport __free(kfree) = kzalloc(TDX_REPORT_LEN, GFP_KERNEL);
+ if (!tdreport)
+ return -ENOMEM;
+
+ ret = tdx_mcall_get_report0(reportdata, tdreport);
+ if (ret) {
+ pr_err("GetReport call failed\n");
+ return ret;
+ }
+
+ rtmr = tdreport + TDREPORT_RTMR_OFFSET + (digest_size * index);
+
+ memcpy(digest, rtmr, digest_size);
+
+ return digest_size;
+}
+
static long tdx_guest_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -278,9 +354,36 @@ static const struct x86_cpu_id tdx_guest_ids[] = {
};
MODULE_DEVICE_TABLE(x86cpu, tdx_guest_ids);
+const struct tsm_rtmr_desc rtmrs[] = {
+ {
+ .hash_alg = HASH_ALGO_SHA384,
+ /* RTMR 0 => PCR 1 & 7 */
+ .tcg_pcr_mask = BIT(1) | BIT(7),
+ },
+ {
+ .hash_alg = HASH_ALGO_SHA384,
+ /* RTMR 1 => PCR 2~6 */
+ .tcg_pcr_mask = GENMASK(6, 2),
+ },
+ {
+ .hash_alg = HASH_ALGO_SHA384,
+ /* RTMR 2 => PCR 8~15 */
+ .tcg_pcr_mask = GENMASK(15, 8),
+ },
+ {
+ .hash_alg = HASH_ALGO_SHA384,
+ /* No PCR mapping */
+ .tcg_pcr_mask = 0,
+ },
+};
+
static const struct tsm_ops tdx_tsm_ops = {
.name = KBUILD_MODNAME,
+ .capabilities.num_rtmrs = ARRAY_SIZE(rtmrs),
+ .capabilities.rtmrs = rtmrs,
.report_new = tdx_report_new,
+ .rtmr_extend = tdx_rtmr_extend,
+ .rtmr_read = tdx_rtmr_read
};
static int __init tdx_guest_init(void)