| 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) |