From nobody Thu Sep 03 03:51:17 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hb5HZ2Xv3z6qVdD for ; Thu, 03 Sep 2026 03:51:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hb5HZ1XdKz3mdc for ; Thu, 03 Sep 2026 03:51:22 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788407482; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=rK6ylKuF3lUsqmFDSR0dae+wu0GFHz3tEBOwBN75RNA=; b=P5bECKQyWcjaz+34Bszf42zgPknxZh2TReFBzH1xl5qbdiCFNFdxTHpsrCBZIBDrdDmaUS Q4gtNCNFgULvHXL5hRWMk/seLT8THHi1mfO/n3DCkiWjxg10Gqj8FPEjOyLKL6hADluAba ifJ5OFNU5id3kDuX4oyYf8IEF6GjCcCzJoqpxUdnp4kLJkyBaKc3JT1QHuL/XZmUx1m2pf udblZc6+zCNKjsIejNCsQ9gQLQ69HEgvWRnKnqQUSYWkh/jLnWP/5Rgk/pH5ouQ6QtjZe2 lVZAVUk4U/1iP4nPyskI5G2qCv9/pO8AkoPDLmJgFVnKNiQ0djchiOMfr5l43w== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788407482; a=rsa-sha256; cv=none; b=cfWlKcs6YGmbEsvcVoUHYEA7Xsf+FXnoLtsq7fNiUM0e7RmGmLpMb8u/cK2DQb/oJU5Gtl M6MJXXD29+KJRTO+6RAatGYqm4BULI/JkdCyGHqWByJ2KFSvMXFb5M9hUJDmXhwzSpwacE OYR29dQTahGY926SqVrWfX0Bv7JHleuMWOYLw+QEHJ2/9DV93WPxyFLGc7g4LF+4TymE+v TKIDlvg4VKis3mfH9Hss8xp1y4c/JHKJKeT4sG06Xl81IJtsLDkcjXNahcOHIsVvNSBS4t /XqSyOPrkaiY1UMconFIA61SyUPmvAr4FOSdrDw2bRaraUKBephDB99Z4pZs+g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788407482; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=rK6ylKuF3lUsqmFDSR0dae+wu0GFHz3tEBOwBN75RNA=; b=eCnRWUrmSr5yK/bfIhhmyi02U7DZeyOxDHs1+f7rltXFemurhFAe3/4SDm1Aitvfmk6TN5 C4sDUZQTN59YQFbjTo0UL/g5Jg1a8RouXe8DJaDFQ7ZgEgycbv4Uq/OG43mKnp38RSvin/ bSAoKQdoZxHLdxfX5GX5s+tC9BO2Q6zPaHmOUIUf6IZt3VsKyVRsVYRp4cwo4YdCnIWdaD votQO+aYGhY4xCQ0uJPSgB7dEug2Pou/tRrZS5qO+oevBTlC1HEzQyiXhtRWCuBLTEPDu5 Z5styr4VjopkS8FLOT99TLQ7zw3wMPwbyTp4Jmg/84qgBltgwPTMG3l4fKyoNQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hb5HZ0LSsz1Bvb for ; Thu, 03 Sep 2026 03:51:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 38a88 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 03 Sep 2026 03:51:17 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 726f096f905c - main - tpm20: Validate suspend and resume commands List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kbowling X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 726f096f905c8e2ad2ac0035355fc2b4ed2718fe Auto-Submitted: auto-generated Date: Thu, 03 Sep 2026 03:51:17 +0000 Message-Id: <6a98eeb5.38a88.3a2c3981@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=726f096f905c8e2ad2ac0035355fc2b4ed2718fe commit 726f096f905c8e2ad2ac0035355fc2b4ed2718fe Author: Kevin Bowling AuthorDate: 2026-08-26 10:49:48 +0000 Commit: Kevin Bowling CommitDate: 2026-09-03 03:49:39 +0000 tpm20: Validate suspend and resume commands The internal TPM2_Shutdown and TPM2_Startup paths ignored both transport failures and the TPM response. Suspend could therefore enter S3 without saved TPM state, while resume could restart entropy harvesting after a failed state restoration. Build both commands through one helper, validate their response framing and TPM return codes, and propagate failures. Retry the standard RETRY and TESTING responses with bounded exponential backoff. Accept TPM_RC_INITIALIZE from Startup because firmware may already have started the TPM during resume. Do not enter S3 after an unsuccessful state save, and do not restart the entropy task when TPM state restoration failed. If Shutdown fails after the entropy task was drained, requeue it before returning so an aborted suspend does not permanently stop harvesting. Reviewed by: kevans MFC after: 2 weeks Sponsored by: BBOX.io Differential Revision: https://reviews.freebsd.org/D59195 --- sys/dev/tpm/tpm20.c | 146 +++++++++++++++++++++++++++++++++------------------- sys/dev/tpm/tpm20.h | 2 + 2 files changed, 95 insertions(+), 53 deletions(-) diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c index 48f33708917d..22189d112656 100644 --- a/sys/dev/tpm/tpm20.c +++ b/sys/dev/tpm/tpm20.c @@ -31,6 +31,18 @@ #include "tpm20.h" #define TPM_HARVEST_SIZE 16 + +#define TPM2_ST_NO_SESSIONS 0x8001 +#define TPM2_RC_SUCCESS 0x0000 +#define TPM2_RC_INITIALIZE 0x0100 +#define TPM2_RC_TESTING 0x090a +#define TPM2_RC_RETRY 0x0922 + +#define TPM2_SU_CLEAR 0x0000 +#define TPM2_SU_STATE 0x0001 + +#define TPM2_RETRY_INITIAL_MS 20 +#define TPM2_RETRY_MAX_MS (TPM_TIMEOUT_B / 1000) /* * Perform a harvest every 10 seconds. * Since discrete TPMs are painfully slow @@ -44,6 +56,8 @@ MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver"); #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM static void tpm20_harvest(void *arg, int unused); #endif +static int tpm20_command(device_t, uint32_t, uint16_t, uint32_t, + const char *); static int tpm20_restart(device_t dev, bool clear); static int tpm20_save_state(device_t dev, bool suspend); @@ -227,8 +241,11 @@ tpm20_release(struct tpm_sc *sc) int tpm20_resume(device_t dev) { + int error; - tpm20_restart(dev, false); + error = tpm20_restart(dev, false); + if (error != 0) + return (error); #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM struct tpm_sc *sc; @@ -243,13 +260,21 @@ tpm20_resume(device_t dev) int tpm20_suspend(device_t dev) { + int error; + #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM struct tpm_sc *sc; sc = device_get_softc(dev); taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task); #endif - return (tpm20_save_state(dev, true)); + error = tpm20_save_state(dev, true); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + if (error != 0) + taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, + hz * TPM_HARVEST_INTERVAL); +#endif + return (error); } int @@ -308,76 +333,91 @@ tpm20_harvest(void *arg, int unused) } #endif /* TPM_HARVEST */ +/* + * Send a TPM 2.0 command whose successful response contains only a header. + */ static int -tpm20_restart(device_t dev, bool clear) +tpm20_command(device_t dev, uint32_t command, uint16_t parameter, + uint32_t alternate_rc, const char *name) { - struct tpm_sc *sc; struct tpm_priv *priv; - uint8_t startup_cmd[] = { - 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ - 0x00, 0x00, 0x00, 0x0C, /* cmd length */ - 0x00, 0x00, 0x01, 0x44, /* cmd TPM_CC_Startup */ - 0x00, 0x01 /* TPM_SU_STATE */ - }; + struct tpm_sc *sc; + uint32_t response_rc, response_size; + uint8_t cmd[12]; + int delay_ms, error; sc = device_get_softc(dev); - - /* - * Inform the TPM whether we are resetting or resuming. - */ - if (clear) - startup_cmd[11] = 0; /* TPM_SU_CLEAR */ - if (sc == NULL) - return (0); + return (ENXIO); - sx_xlock(&sc->dev_lock); + be16enc(cmd, TPM2_ST_NO_SESSIONS); + be32enc(cmd + 2, sizeof(cmd)); + be32enc(cmd + 6, command); + be16enc(cmd + 10, parameter); + sx_xlock(&sc->dev_lock); priv = sc->internal_priv; - memcpy(priv->buf, startup_cmd, sizeof(startup_cmd)); - - /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */ - TPM_TRANSMIT(sc->dev, priv, sizeof(startup_cmd)); - + delay_ms = TPM2_RETRY_INITIAL_MS; + for (;;) { + memcpy(priv->buf, cmd, sizeof(cmd)); + error = TPM_TRANSMIT(sc->dev, priv, sizeof(cmd)); + if (error != 0) + break; + if (priv->len < TPM_HEADER_SIZE) { + error = EPROTO; + break; + } + + response_size = be32dec(priv->buf + 2); + response_rc = be32dec(priv->buf + 6); + if (be16dec(priv->buf) != TPM2_ST_NO_SESSIONS || + response_size != TPM_HEADER_SIZE || + priv->len != response_size) { + error = EPROTO; + break; + } + if (response_rc != TPM2_RC_RETRY && + response_rc != TPM2_RC_TESTING) + break; + if (delay_ms > TPM2_RETRY_MAX_MS) + break; + sx_xunlock(&sc->dev_lock); + pause("tpm2retry", MAX(hz * delay_ms / 1000, 1)); + sx_xlock(&sc->dev_lock); + delay_ms *= 2; + } sx_xunlock(&sc->dev_lock); + if (error != 0) { + device_printf(dev, "%s command failed: %d\n", name, error); + return (error); + } + if (response_rc != TPM2_RC_SUCCESS && response_rc != alternate_rc) { + device_printf(dev, "%s failed: TPM error 0x%x\n", name, + response_rc); + return (EIO); + } return (0); } static int -tpm20_save_state(device_t dev, bool suspend) +tpm20_restart(device_t dev, bool clear) { - struct tpm_sc *sc; - struct tpm_priv *priv; - uint8_t save_cmd[] = { - 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ - 0x00, 0x00, 0x00, 0x0C, /* cmd length */ - 0x00, 0x00, 0x01, 0x45, /* cmd TPM_CC_Shutdown */ - 0x00, 0x00 /* TPM_SU_STATE */ - }; - - sc = device_get_softc(dev); - - /* - * Inform the TPM whether we are going to suspend or reboot/shutdown. - */ - if (suspend) - save_cmd[11] = 1; /* TPM_SU_STATE */ + uint16_t startup_type; - if (sc == NULL) - return (0); - - sx_xlock(&sc->dev_lock); - - priv = sc->internal_priv; - memcpy(priv->buf, save_cmd, sizeof(save_cmd)); - - /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */ - TPM_TRANSMIT(sc->dev, priv, sizeof(save_cmd)); + startup_type = clear ? TPM2_SU_CLEAR : TPM2_SU_STATE; + return (tpm20_command(dev, TPM_CC_Startup, startup_type, + TPM2_RC_INITIALIZE, "Startup")); +} - sx_xunlock(&sc->dev_lock); +static int +tpm20_save_state(device_t dev, bool suspend) +{ + uint16_t shutdown_type; - return (0); + shutdown_type = suspend ? TPM2_SU_STATE : TPM2_SU_CLEAR; + return (tpm20_command(dev, TPM_CC_Shutdown, shutdown_type, + TPM2_RC_SUCCESS, "Shutdown")); } int32_t diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h index b63bb9a1436e..a004bdea9e06 100644 --- a/sys/dev/tpm/tpm20.h +++ b/sys/dev/tpm/tpm20.h @@ -74,6 +74,8 @@ */ #define TPM_TIMEOUT_LONG 40000000 +#define TPM_CC_Shutdown 0x00000145 + /* List of commands that require TPM_TIMEOUT_LONG time to complete */ #define TPM_CC_CreatePrimary 0x00000131 #define TPM_CC_Create 0x00000153