From nobody Thu Sep 03 03:51:17 2026 X-Original-To: dev-commits-src-main@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 4hb5HT2lCdz6qVP4 for ; Thu, 03 Sep 2026 03:51:17 +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 4hb5HT1YnTz3mSR for ; Thu, 03 Sep 2026 03:51:17 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788407477; 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=c0PSamIFLguRDdMN2ErT1BS5KiEZ5BsZNcMYn8v6IURoa78UD/65Vvw7TjQA/cqKB/Dgz9 VJ3Uk9h05Qoltm4WBiSj2mjFtIYPR86GfJ++gBkVEG48JsJPBki92cTkf+yCqmahX6kYTr V42735yM4n+aoj5aO0pcSTMTHX8I4bgqmG2YA30ozRlRwfDxiWtL49MZxLFOQ83ihEUsPy 4bo1+6zXgsVIZTWpJujk0JrLMISvC34ARMGzq/ypO/wudIU+tCEdnuSHn7AIEMrBSqTBzS wDCoEBRnS1VM4iiQTyd/t+1gpCmlIgsa+RrXtPGkvnso0clVouHy5l+Jbr30ng== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788407477; a=rsa-sha256; cv=none; b=loeyaIvPuP+ak8Tjgx6DPgNAqt4jTxG9ozguhd2g6y4Ls9af/qUgGuGBDKEro6lo1bpwU1 zKbHlVTbQ4x+UgbIJfq0rEsCgV/4CEo36QVASKbNoww8fHoLBvFokQdiz4KSfOCYYV7i4E xGnFKVKFt7jA5+62fyGv0bsd1PwCjBI8vKRKQnEMEGaYj1d1OPVctYtSod9Z3PNsFopv/E YvU31fYu+2ZyEGSkrkxx4+ItsCjfF8DHhNOlMuwNuHdaz/jmhUUcMI7FECv0ynJbDrdRL9 5AA8UtJIPOJa9U2j131Ri3rzzlGjjNyzv7rzVgq8lB3fHSRTgYUE4dwvnBa5Cg== 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=1788407477; 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=wdlmPZTxgo0tnl+XOxGrlFAbF9DdTU2A5d/fy/dU/B/vESleMskM1ghocaXBGOpCF9j1W0 5uD3oj2OdwUa7pBv9xoCJObxzAqcDbmIt25ZWVfi2FEA7k5fL00iO8y/EBlotLHEJiGGP8 9rXz2Skqai9+l+cp7P3KgN0OHv8E2DxqmyKQqa4yn3iSLkGvlEedCUWSbbfvC+9/VUZMgN liIDeEbRj8jA6YYq36SAVxjntMBovqXq8sDteoQDd6BjXgHBqWHKclE7b/shkZQ8XvOPdF ouJrqnagXRjk7IR3sTY5Ha0FMI2DNcKTBlOdHbSm5A3oUboHgqLx7Ibhsl3Icg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hb5HT0Jgrz1BX0 for ; Thu, 03 Sep 2026 03:51:17 +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 the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@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