From nobody Wed Dec 17 05:27:05 2025 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CAE051A5B9A for ; Mon, 24 Feb 2025 03:22:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740367323; cv=none; b=KJUPmAb0jCRLzbfIYH3SYUS9qEhS5JtXXAY8S5pGCz2kD0KqKMlDmOijzSdWReUHXRJV44UO3QlAE7Acg+Y2qukspyg0hgtlZKM/xvDSozIu84DmLWwwzKOQAlzyEm6dn4VxeaHObqtPsuefVNkzz63QGytQXsmtTwLoiOFaFJM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740367323; c=relaxed/simple; bh=gtvQmFMZq96hBKeNoF2V0rliu4QKfGTnrxvFeoQp8Ss=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QI+xgzH6ksZtcgePTXv/FgRlZQ1zitl2Hpa/Us7AXLD+lsURdpBaKM1g5jEooiIfw/ZsavRtKyxyIfGUPikxl1FvSbQqKpn0IGYxuqnFj2Df6TBVexhi4NWF34W5poTLZmWxVoVdkHAGeJiYwHHkXOEgbIaHn3dZIP/rdoxSkBg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=ATD+jVa7; arc=none smtp.client-ip=192.198.163.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ATD+jVa7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740367322; x=1771903322; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=gtvQmFMZq96hBKeNoF2V0rliu4QKfGTnrxvFeoQp8Ss=; b=ATD+jVa784JgKNPocwP0DvSWeip4DRsKwNbdcgZibnkllG3GKR8lXOjC ZQ4sG7BysksbCamkvDxtFHxyKaNYrZX71IUokDkV+RWujy/2UAGsaQP6w sqJ6EUb44R/SwlZnLa0iry8Vx3BnOFGCEzMurrBXLkougZOqIXTDXQt4K eZHMXAWS/KZwE5SEbhUly8Gd9wfLhz7+yzVAkro4lOQUfUwz0EJqWa/av d4afg4ymr/9dYjnWitXCS4GgJGOwmFBLuFNndzUGy6OnIIF5U1W8Hiex+ j02sY7BbrczEcKxFtoFTlRmeJldqh7xW498W7ZKYI1xV6zL5JDGoROT2i A==; X-CSE-ConnectionGUID: mjqVxB5qToStJx0d01EFPg== X-CSE-MsgGUID: H/3XUxImQJ+kI3rnIxIS9Q== X-IronPort-AV: E=McAfee;i="6700,10204,11354"; a="28706895" X-IronPort-AV: E=Sophos;i="6.13,309,1732608000"; d="scan'208";a="28706895" Received: from fmviesa010.fm.intel.com ([10.60.135.150]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2025 19:21:56 -0800 X-CSE-ConnectionGUID: 98GZGlJlThOh0sx475/aTw== X-CSE-MsgGUID: /pY/rAzpTNOzD/pMmjuJvQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.13,309,1732608000"; d="scan'208";a="116441906" Received: from shanagud-mobl.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.117.251]) by fmviesa010-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2025 19:21:17 -0800 From: Cedric Xing Date: Sun, 23 Feb 2025 21:20:15 -0600 Subject: [PATCH v2 4/4] x86/tdx: Expose TDX MRs through TSM sysfs interface Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250223-tdx-rtmr-v2-4-f2d85b0a5f94@intel.com> References: <20250223-tdx-rtmr-v2-0-f2d85b0a5f94@intel.com> In-Reply-To: <20250223-tdx-rtmr-v2-0-f2d85b0a5f94@intel.com> To: Dan Williams , "Kirill A. Shutemov" , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , x86@kernel.org, "H. Peter Anvin" Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, Dionna Amalie Glaze , James Bottomley , Dan Middleton , Mikko Ylinen , Sathyanarayanan Kuppuswamy X-Mailer: b4 0.13.0 TDX MRs are made accessible to user mode as files (attributes) in sysfs. Below shows the directory structure of TDX MRs inside a TDVM. /sys/kernel/tsm =E2=94=94=E2=94=80=E2=94=80 tdx =E2=94=9C=E2=94=80=E2=94=80 mrconfigid =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 mrowner =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 mrownerconfig =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 mrtd =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 report0 =E2=94=9C=E2=94=80=E2=94=80 reportdata =E2=94=9C=E2=94=80=E2=94=80 rtmr0 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 rtmr1 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 rtmr2 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 rtmr3 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=94=E2=94=80=E2=94=80 servtd_hash =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=94=E2=94=80=E2=94=80 digest The digest attribute/file of each MR contains the MR's current value. Writing to the digest attribute/file of an RTMR extends the written value to that RTMR. The report0 and reportdata attributes offer a simple interface for user mode applications to request TDREPORTs. These 2 attributes can be enabled/disabled by setting TDX_GUEST_DRIVER_TSM_REPORT to Y/n. Signed-off-by: Cedric Xing --- drivers/virt/coco/tdx-guest/Kconfig | 24 +++++-- drivers/virt/coco/tdx-guest/tdx-guest.c | 115 ++++++++++++++++++++++++++++= ++++ 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/drivers/virt/coco/tdx-guest/Kconfig b/drivers/virt/coco/tdx-gu= est/Kconfig index 22dd59e19431..a1c5e8fdd511 100644 --- a/drivers/virt/coco/tdx-guest/Kconfig +++ b/drivers/virt/coco/tdx-guest/Kconfig @@ -3,9 +3,23 @@ config TDX_GUEST_DRIVER depends on INTEL_TDX_GUEST select TSM_REPORTS help - The driver provides userspace interface to communicate with - the TDX module to request the TDX guest details like attestation - report. + The driver provides userspace interface to communicate with the TDX + module to request the TDX guest details like attestation report. =20 - To compile this driver as module, choose M here. The module will - be called tdx-guest. + To compile this driver as module, choose M here. The module will be + called tdx-guest. + +if TDX_GUEST_DRIVER + +config TDX_GUEST_DRIVER_TSM_REPORT + bool "tdx-guest: Enable TSM raw TDREPORT interface" + default y + help + This option adds 2 files, namely report0 and reportdata, to the TSM + sysfs directory tree (/sys/kernel/tsm/tdx/). + + To request a TDREPORT, set REPORTDATA by writing to + /sys/kernel/tsm/tdx/reportdata, then read + /sys/kernel/tsm/tdx/report0. + +endif diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/td= x-guest/tdx-guest.c index 224e7dde9cde..a31fe2098901 100644 --- a/drivers/virt/coco/tdx-guest/tdx-guest.c +++ b/drivers/virt/coco/tdx-guest/tdx-guest.c @@ -5,6 +5,8 @@ * Copyright (C) 2022 Intel Corporation */ =20 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -18,6 +20,8 @@ #include #include =20 +#include + #include =20 #include @@ -304,6 +308,110 @@ static const struct tsm_ops tdx_tsm_ops =3D { .report_bin_attr_visible =3D tdx_report_bin_attr_visible, }; =20 +enum { + TDREPORT_MRSIZE =3D SHA384_DIGEST_SIZE, + + TDREPORT_reportdata =3D 128, + TDREPORT_tdinfo =3D 512, + TDREPORT_mrtd =3D TDREPORT_tdinfo + 16, + TDREPORT_mrconfigid =3D TDREPORT_mrtd + TDREPORT_MRSIZE, + TDREPORT_mrowner =3D TDREPORT_mrconfigid + TDREPORT_MRSIZE, + TDREPORT_mrownerconfig =3D TDREPORT_mrowner + TDREPORT_MRSIZE, + TDREPORT_rtmr0 =3D TDREPORT_mrownerconfig + TDREPORT_MRSIZE, + TDREPORT_rtmr1 =3D TDREPORT_rtmr0 + TDREPORT_MRSIZE, + TDREPORT_rtmr2 =3D TDREPORT_rtmr1 + TDREPORT_MRSIZE, + TDREPORT_rtmr3 =3D TDREPORT_rtmr2 + TDREPORT_MRSIZE, + TDREPORT_servtd_hash =3D TDREPORT_rtmr3 + TDREPORT_MRSIZE, +}; + +static u8 tdx_mr_report[TDX_REPORT_LEN] __aligned(TDX_REPORT_LEN); + +#define TDX_MR_(r) .mr_value =3D tdx_mr_report + TDREPORT_##r, TSM_MR_(r, = SHA384) +static const struct tsm_measurement_register tdx_mrs[] =3D { + { TDX_MR_(rtmr0) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(rtmr1) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(rtmr2) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(rtmr3) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(mrtd) }, + { TDX_MR_(mrconfigid) }, + { TDX_MR_(mrowner) }, + { TDX_MR_(mrownerconfig) }, + { TDX_MR_(servtd_hash) }, +#if IS_ENABLED(CONFIG_TDX_GUEST_DRIVER_TSM_REPORT) + { .mr_value =3D tdx_mr_report, .mr_size =3D sizeof(tdx_mr_report), + .mr_name =3D "report0", .mr_flags =3D TSM_MR_F_LIVE | TSM_MR_F_F }, + { .mr_value =3D tdx_mr_report + TDREPORT_reportdata, + TSM_MR_(reportdata, SHA512) | TSM_MR_F_W | TSM_MR_F_F }, +#endif + {} +}; +#undef TDX_MR_ + +static int tdx_mr_refresh(struct tsm_measurement *tmr, + const struct tsm_measurement_register *mr) +{ + u8 *reportdata, *tdreport; + int ret; + + reportdata =3D tdx_mr_report + TDREPORT_reportdata; + + /* + * TDCALL requires a GPA as input. Depending on whether this module is + * built as a built-in (Y) or a module (M), tdx_mr_report may or may + * not be converted to a GPA using virt_to_phys. If not, a directly + * mapped buffer must be allocated using kmalloc and used as an + * intermediary. + */ +#if IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER) + tdreport =3D tdx_mr_report; +#else + tdreport =3D kmalloc(sizeof(tdx_mr_report), GFP_KERNEL); + if (!tdreport) + return -ENOMEM; + + reportdata =3D memcpy(tdreport + TDREPORT_reportdata, reportdata, + TDX_REPORTDATA_LEN); +#endif + + ret =3D tdx_mcall_get_report0(reportdata, tdreport); + if (ret) + pr_err("GetReport call failed\n"); + +#if !IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER) + memcpy(tdx_mr_report, tdreport, sizeof(tdx_mr_report)); + kfree(tdreport); +#endif + + return ret; +} + +static int tdx_mr_extend(struct tsm_measurement *tmr, + const struct tsm_measurement_register *mr, const u8 *data) +{ + u8 *buf; + int ret; + + buf =3D kmalloc(64, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, data, TDREPORT_MRSIZE); + + ret =3D tdx_mcall_extend_rtmr((u8)(mr - tmr->mrs), buf); + if (ret) + pr_err("Extending RTMR%ld failed\n", mr - tmr->mrs); + + kfree(buf); + return ret; +} + +static struct tsm_measurement tdx_measurement =3D { + .name =3D "tdx", + .mrs =3D tdx_mrs, + .refresh =3D tdx_mr_refresh, + .extend =3D tdx_mr_extend, +}; + static int __init tdx_guest_init(void) { int ret; @@ -326,8 +434,14 @@ static int __init tdx_guest_init(void) if (ret) goto free_quote; =20 + ret =3D tsm_register_measurement(&tdx_measurement); + if (ret) + goto unregister_tsm; + return 0; =20 +unregister_tsm: + tsm_unregister(&tdx_tsm_ops); free_quote: free_quote_buf(quote_data); free_misc: @@ -339,6 +453,7 @@ module_init(tdx_guest_init); =20 static void __exit tdx_guest_exit(void) { + tsm_unregister_measurement(&tdx_measurement); tsm_unregister(&tdx_tsm_ops); free_quote_buf(quote_data); misc_deregister(&tdx_misc_dev); --=20 2.43.0