DF-4929 / fix.diff
--- a/sys/dev/crypto/tpm/tpm20.c +++ b/sys/dev/crypto/tpm/tpm20.c @@ -77,6 +77,11 @@ callout_stop(&sc->discard_buffer_callout); lockmgr(&sc->dev_lock, LK_EXCLUSIVE); + if (sc->dying) { + lockmgr(&sc->dev_lock, LK_RELEASE); + return (ENXIO); + } + if (sc->owner_tid != uio->uio_td) { lockmgr(&sc->dev_lock, LK_RELEASE); return (EPERM); @@ -123,9 +128,14 @@ lockmgr(&sc->dev_lock, LK_EXCLUSIVE); - while (sc->pending_data_length != 0) + while (sc->pending_data_length != 0 && !sc->dying) cv_wait(&sc->buf_cv, &sc->dev_lock); + if (sc->dying) { + lockmgr(&sc->dev_lock, LK_RELEASE); + return (ENXIO); + } + result = uiomove(sc->buf, byte_count, uio); if (result != 0) { lockmgr(&sc->dev_lock, LK_RELEASE); @@ -155,6 +165,11 @@ lockmgr(&sc->dev_lock, LK_EXCLUSIVE); + if (sc->dying) { + lockmgr(&sc->dev_lock, LK_RELEASE); + return; + } + memset(sc->buf, 0, TPM_BUFSIZE); sc->pending_data_length = 0; @@ -211,18 +226,40 @@ void tpm20_release(struct tpm_sc *sc) { - + /* + * Best-effort early drain of the discard callout. The handler takes + * dev_lock itself, so this must happen outside the lock. + */ #ifdef TPM_HARVEST callout_drain(&sc->harvest_callout); #endif + callout_drain(&sc->discard_buffer_callout); - if (sc->buf != NULL) + /* Serialize against in-flight tpm20_read/tpm20_write/transmit. */ + lockmgr(&sc->dev_lock, LK_EXCLUSIVE); + sc->dying = true; + cv_broadcast(&sc->buf_cv); + + if (sc->sc_cdev != NULL) { + destroy_dev(sc->sc_cdev); + sc->sc_cdev = NULL; + } + if (sc->buf != NULL) { kfree(sc->buf, M_TPM20); + sc->buf = NULL; + } + sc->pending_data_length = 0; + lockmgr(&sc->dev_lock, LK_RELEASE); + + /* + * A writer can have armed the callout right before dropping the + * lock; the handler bails on sc->dying so it stays safe against + * the still-intact softc. + */ + callout_drain(&sc->discard_buffer_callout); - lockuninit(&sc->dev_lock); cv_destroy(&sc->buf_cv); - if (sc->sc_cdev != NULL) - destroy_dev(sc->sc_cdev); + lockuninit(&sc->dev_lock); } int --- a/sys/dev/crypto/tpm/tpm20.h +++ b/sys/dev/crypto/tpm/tpm20.h @@ -119,6 +119,7 @@ uint8_t *buf; size_t pending_data_length; struct thread *owner_tid; + bool dying; /* release/detach in progress */ struct callout discard_buffer_callout; #ifdef TPM_HARVEST |