git: a0da653aaeae - main - tpm20: Initialize common state before testing TIS interrupts

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Thu, 03 Sep 2026 03:53:25 UTC
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=a0da653aaeae313479f2ab37d0faca483f530fa6

commit a0da653aaeae313479f2ab37d0faca483f530fa6
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-26 10:51:58 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-03 03:53:02 +0000

    tpm20: Initialize common state before testing TIS interrupts
    
    The TIS attach path tested its interrupt by transmitting GetRandom
    before tpm20_init() allocated the internal command buffer.  A TPM2 FIFO
    device with a usable IRQ could therefore dereference a null
    internal_priv.
    
    Initialize the common TPM2 state before running the interrupt test.
    Make common cleanup safe for partially initialized devices and leave
    cleanup to the attachment after tpm20_init() fails, avoiding duplicate
    release of the lock, command buffer, and random-source state.
    
    Clear the IRQ resource pointer after releasing it when interrupt handler
    setup fails so the later polling-mode detach does not release it twice.
    
    Free the internal command allocation through its object pointer rather
    than relying on its embedded buffer being the first structure member.
    
    Reviewed by:    kevans
    MFC after:      2 weeks
    Sponsored by:   BBOX.io
    Differential Revision:  https://reviews.freebsd.org/D59196
---
 sys/dev/tpm/tpm20.c        | 19 ++++++++++++++-----
 sys/dev/tpm/tpm20.h        |  1 +
 sys/dev/tpm/tpm_tis_core.c | 14 +++++++++-----
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c
index 22189d112656..20521b2ed361 100644
--- a/sys/dev/tpm/tpm20.c
+++ b/sys/dev/tpm/tpm20.c
@@ -157,7 +157,7 @@ tpm20_priv_dtor(void *data)
 {
 	struct tpm_priv *priv = data;
 
-	free(priv->buf, M_TPM20);
+	free(priv, M_TPM20);
 }
 
 int
@@ -209,7 +209,7 @@ tpm20_init(struct tpm_sc *sc)
 	args.mda_si_drv1 = sc;
 	result = make_dev_s(&args, &sc->sc_cdev, TPM_CDEV_NAME);
 	if (result != 0)
-		tpm20_release(sc);
+		return (result);
 
 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
 	random_source_register(&random_tpm);
@@ -217,6 +217,7 @@ tpm20_init(struct tpm_sc *sc)
 	    tpm20_harvest, sc);
 	taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 0);
 #endif
+	sc->common_initialized = true;
 
 	return (result);
 
@@ -226,16 +227,24 @@ void
 tpm20_release(struct tpm_sc *sc)
 {
 
+	if (!sc->common_initialized)
+		goto out;
 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
 	if (device_is_attached(sc->dev))
 		taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task);
 	random_source_deregister(&random_tpm);
 #endif
-
-	tpm20_priv_dtor(sc->internal_priv);
+	sc->common_initialized = false;
+out:
+	if (sc->internal_priv != NULL) {
+		tpm20_priv_dtor(sc->internal_priv);
+		sc->internal_priv = NULL;
+	}
 	sx_destroy(&sc->dev_lock);
-	if (sc->sc_cdev != NULL)
+	if (sc->sc_cdev != NULL) {
 		destroy_dev(sc->sc_cdev);
+		sc->sc_cdev = NULL;
+	}
 }
 
 int
diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h
index a004bdea9e06..7570812219b9 100644
--- a/sys/dev/tpm/tpm20.h
+++ b/sys/dev/tpm/tpm20.h
@@ -128,6 +128,7 @@ struct tpm_sc {
 	void 		*intr_cookie;
 	int 		intr_type;	/* Current event type */
 	bool 		interrupts;
+	bool		common_initialized;
 
 	struct tpm_priv *internal_priv;
 
diff --git a/sys/dev/tpm/tpm_tis_core.c b/sys/dev/tpm/tpm_tis_core.c
index 95e914fa570b..15370e648f1e 100644
--- a/sys/dev/tpm/tpm_tis_core.c
+++ b/sys/dev/tpm/tpm_tis_core.c
@@ -120,17 +120,21 @@ tpmtis_attach(device_t dev)
 	result = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
 		    NULL, tpmtis_intr_handler, sc, &sc->intr_cookie);
 	if (result != 0) {
-		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
+		if (bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
+		    sc->irq_res) == 0)
+			sc->irq_res = NULL;
 		goto skip_irq;
 	}
-	tpmtis_setup_intr(sc);
-
 skip_irq:
 	result = tpm20_init(sc);
-	if (result != 0)
+	if (result != 0) {
 		tpmtis_detach(dev);
+		return (result);
+	}
+	if (sc->intr_cookie != NULL)
+		tpmtis_setup_intr(sc);
 
-	return (result);
+	return (0);
 }
 
 static int