From nobody Fri Oct 30 22:26:06 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 4jGbKc0F8gz6xgHq for ; Fri, 30 Oct 2026 22:26:12 +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) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jGbKb4jmgz4ddg for ; Fri, 30 Oct 2026 22:26:11 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793399171; 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=EABXa7IZvtsJzOeg5Dy0e8imx3TZLsVFGZkhibptZ7c=; b=vGIvreeSdKyiwgIdqxy0pWVsDfDfPIn9QdSGsHPsOAB/ayi77QoCSUawK1i4SZNIDcNjK7 EbOZPxhPpuAm0XAk4te1S0fs6RVZuvKpytD/xF28rK8ADOI/r+pZMYjt6v2WzxU9SiPfZy kMy0QtwlVc+KEanHhU/KkTUZQrOJzUiw7Rc8KWSZWe1YBejBYRQCUb14daHx53IPSZpirC PTpOOmfiHCG9pRu5W8bp2pcSZpay6XB6d65SB7S2keD0PzeI+QwSF/VGjue/XNZdInNj1s VhjeJpuNRD4XyNvWOzDxGp2lNuGcjX/BWjXvpqLc8cjoH0o0h8NDc4SX3An8Mw== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1793399171; b=gipM9XrrUx6FZuAE7Jey9KjKSDa1ROas/Zq36lqeT3M++dkZJP8qQRCsQYMB+ifILaeoe4 4JCbJDIh6TPCWdJLbKwY3BKl2v6GF1uNh+/3c88FqqS6Nu8b0jRpaSwK5Ykg0kCS2wuIrj 1FYeZVdPJcUgD+6+raNSrncN5EAYcJronhcl9ESGoKyY/nq3GahzzuVyQmk15UeD2RXIHe nW3wS3nkvaXk8m/A1vdMwqh9/McFbjJ0S0nUC0WVR0AOiv8mdbpeu0XrbOe0HldMu86l4l VI655BVrp+9+ZZ7tnmMx45A4ED5GzltuSH47QJsfxiCOBFtNZnaX+kNUgtkzaw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793399171; 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=EABXa7IZvtsJzOeg5Dy0e8imx3TZLsVFGZkhibptZ7c=; b=lDtVM5E545+25Ln6+PlsQwGQ6bjOCgRq+dcSbzaeVp+oK2pGVM7ZRa+lrKx5ieMpNbrSkg 8Yt8FJtr6oUZ34MRcFFCSH6AF0vFD5J6v6B1HHQOHPdvnxOpnASPWL7E5nfgwm2Nr5ps+A u8ADNQLAAFxEZi8o8MWf+8imYKivBFUcjJO8A1hTNng+PtCQg3e79V2+lFOlXC/QKVhgg6 NWsJVEp5fA8NE5gz5U+1Md4Jqw/1WKOJOXdRmEDnKsZTvxYtUKU5swUXEDQ98iZ89JZBYY QQJqN9crTLr3aU0vxzZNj1aIBgypg5LW0oGWD37gaiUAWbn+iWeO7zEi7nFTDA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jGbKb44nCznG0 for ; Fri, 30 Oct 2026 22:26:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 37258 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 30 Oct 2026 22:26:06 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 4bcd10f7c049 - main - tpm: Harvest entropy from TPM 1.2 devices List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: Commit messages for all branches of the src repository 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: 4bcd10f7c04988056c7b28c4cbe65804d7f26d93 Auto-Submitted: auto-generated Date: Fri, 30 Oct 2026 22:26:06 +0000 Message-Id: <6ae5197e.37258.2c3adb9b@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=4bcd10f7c04988056c7b28c4cbe65804d7f26d93 commit 4bcd10f7c04988056c7b28c4cbe65804d7f26d93 Author: Kevin Bowling AuthorDate: 2026-08-27 14:27:45 +0000 Commit: Kevin Bowling CommitDate: 2026-10-30 22:24:16 +0000 tpm: Harvest entropy from TPM 1.2 devices The TPM 2.0 driver periodically contributes TPM-generated random bytes to the kernel entropy pool, but the TPM 1.2 driver does not. Issue TPM_GetRandom every ten seconds and submit successful responses as RANDOM_PURE_TPM. Keep each exchange under the TPM transaction lock. Defer harvesting while the character device is open or a command is pending so the task cannot consume a user response. Drain the task for suspend and detach, rearming it after resume or a failed suspend. Document the expanded scope of RANDOM_ENABLE_TPM and update the kernel configuration comments that described it as TPM 2.0-only. Validated on a STMicroelectronics TPM 1.2 TIS device. DTrace observed periodic entropy submissions; a raw GetRandom response remained intact while the device was held open across a harvest interval; and module unload/reload deregistered and restored the entropy source cleanly. Tested by: zarychtam_plan-b.pwste.edu.pl MFC after: 2 weeks Sponsored by: BBOX.io Differential Revision: https://reviews.freebsd.org/D59239 --- share/man/man4/tpm.4 | 10 ++- sys/arm/conf/GENERIC | 2 +- sys/arm64/conf/std.arm64 | 2 +- sys/dev/tpm/tpm.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++- sys/dev/tpm/tpmvar.h | 6 ++ sys/riscv/conf/GENERIC | 2 +- 6 files changed, 216 insertions(+), 5 deletions(-) diff --git a/share/man/man4/tpm.4 b/share/man/man4/tpm.4 index 408b1f30022b..4a37fa2f8458 100644 --- a/share/man/man4/tpm.4 +++ b/share/man/man4/tpm.4 @@ -13,7 +13,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd October 31, 2018 +.Dd August 27, 2026 .Dt TPM 4 .Os .Sh NAME @@ -21,6 +21,7 @@ .Nd Trusted Platform Module .Sh SYNOPSIS .Cd device tpm +.Cd options RANDOM_ENABLE_TPM .Pp In .Xr device.hints 5 : @@ -43,6 +44,12 @@ store cryptographic keys. The driver can be configured to use an IRQ by providing a free ISA interrupt vector in .Pa /boot/device.hints . +.Pp +When the kernel is configured with +.Cd "options RANDOM_ENABLE_TPM" , +the driver periodically obtains random bytes from the TPM and supplies them +to +.Xr random 4 . .Sh HARDWARE The .Nm @@ -66,6 +73,7 @@ Winbond WEC WPCT200 .El .Sh SEE ALSO .Xr intro 4 , +.Xr random 4 , .Xr device.hints 5 , .Xr config 8 .Pp diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index b0a2eb92554b..c74c8d1f56a7 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -218,7 +218,7 @@ device smsc # SMSC LAN91C111 # random(4) device tpm # Trusted Platform Module -options RANDOM_ENABLE_TPM # enable entropy from TPM 2.0 +options RANDOM_ENABLE_TPM # enable entropy from TPM devices options RANDOM_ENABLE_KBD options RANDOM_ENABLE_MOUSE diff --git a/sys/arm64/conf/std.arm64 b/sys/arm64/conf/std.arm64 index 47d803a7c37e..28d62b1657f9 100644 --- a/sys/arm64/conf/std.arm64 +++ b/sys/arm64/conf/std.arm64 @@ -111,6 +111,6 @@ device smbios # random(4) device tpm # Trusted Platform Module -options RANDOM_ENABLE_TPM # enable entropy from TPM 2.0 +options RANDOM_ENABLE_TPM # enable entropy from TPM devices options RANDOM_ENABLE_KBD options RANDOM_ENABLE_MOUSE diff --git a/sys/dev/tpm/tpm.c b/sys/dev/tpm/tpm.c index 42c31ba75518..41f75aaa3047 100644 --- a/sys/dev/tpm/tpm.c +++ b/sys/dev/tpm/tpm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -43,8 +44,20 @@ #include "tpm_if.h" +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM +#include +#include +#endif + MALLOC_DEFINE(M_TPM, "tpm12_buffer", "buffer for TPM 1.2 responses"); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM +static const struct random_source random_tpm12 = { + .rs_ident = "TPM", + .rs_source = RANDOM_PURE_TPM, +}; +#endif + #define TPM_BUFSIZ 1024 #define TPM_HDRSIZE 10 @@ -54,11 +67,15 @@ MALLOC_DEFINE(M_TPM, "tpm12_buffer", "buffer for TPM 1.2 responses"); #define TPM_TAG_RQU_COMMAND 0x00c1 #define TPM_TAG_RSP_COMMAND 0x00c4 #define TPM_ORD_SAVESTATE 0x00000098 +#define TPM_ORD_GETRANDOM 0x00000046 #define TPM_WARN_RETRY 0x00000800 #define TPM_SAVESTATE_RETRIES 50 #define TPM_SAVESTATE_RETRY_MS 100 +#define TPM_HARVEST_SIZE 16 +#define TPM_HARVEST_INTERVAL 10 + #define TPM_ACCESS 0x0000 /* access register */ #define TPM_ACCESS_ESTABLISHMENT 0x01 /* establishment */ #define TPM_ACCESS_REQUEST_USE 0x02 /* request using locality */ @@ -196,6 +213,11 @@ int tpm_legacy_end(struct tpm_softc *, int, int); static int tpm_attach_finish(struct tpm_softc *); static void tpm_delayed_attach(void *); static int tpm_transmit_header(struct tpm_softc *, uint32_t, uint32_t *); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM +static int tpm_get_random(struct tpm_softc *, uint8_t *, size_t *); +static void tpm_harvest(void *, int); +static void tpm_harvest_enqueue(const uint8_t *, size_t); +#endif static void tpm_tis12_abort(struct tpm_softc *); static int tpm_tis12_devid_index(uint32_t); static int tpm_tis12_quiesce(struct tpm_softc *); @@ -254,6 +276,9 @@ tpm_attach(device_t dev) sc->sc_intr_received = false; sc->sc_irq_config.valid = false; TASK_INIT(&sc->sc_intr_task, 0, tpm_tis12_intr_task, sc); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + sc->sc_harvest_registered = false; +#endif sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, @@ -366,7 +391,19 @@ tpm_attach_finish(struct tpm_softc *sc) args.mda_gid = GID_WHEEL; args.mda_mode = 0600; args.mda_si_drv1 = sc; - return (make_dev_s(&args, &sc->sc_cdev, "tpm")); + error = make_dev_s(&args, &sc->sc_cdev, "tpm"); + if (error != 0) + return (error); + +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + TIMEOUT_TASK_INIT(taskqueue_thread, &sc->sc_harvest_task, 0, + tpm_harvest, sc); + random_source_register(&random_tpm12); + sc->sc_harvest_registered = true; + taskqueue_enqueue_timeout(taskqueue_thread, &sc->sc_harvest_task, 0); +#endif + + return (0); } static void @@ -401,6 +438,15 @@ tpm_detach(device_t dev) sx_xunlock(&sc->sc_lock); taskqueue_drain(taskqueue_thread, &sc->sc_intr_task); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + if (sc->sc_harvest_registered) { + taskqueue_drain_timeout(taskqueue_thread, + &sc->sc_harvest_task); + random_source_deregister(&random_tpm12); + sc->sc_harvest_registered = false; + } +#endif + /* * Prevent new methods from touching the transport. Do not hold the * lock while destroy_dev() drains methods and cdevpriv destructors @@ -1039,6 +1085,142 @@ tpm_transmit_header(struct tpm_softc *sc, uint32_t ordinal, uint32_t *tpm_rc) return (0); } +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM +/* + * Fetch random bytes as one command/response transaction. The caller owns + * sc_lock so a character-device request cannot be interposed between the + * write and read phases. + */ +static int +tpm_get_random(struct tpm_softc *sc, uint8_t *entropy, size_t *entropy_size) +{ + uint8_t command[TPM_HDRSIZE + sizeof(uint32_t)]; + uint8_t response[TPM_HDRSIZE + sizeof(uint32_t) + TPM_HARVEST_SIZE]; + size_t count, response_size; + uint32_t random_size, tpm_rc; + int end_error, error; + + sx_assert(&sc->sc_lock, SA_XLOCKED); + *entropy_size = 0; + random_size = 0; + + be16enc(command, TPM_TAG_RQU_COMMAND); + be32enc(command + 2, sizeof(command)); + be32enc(command + 6, TPM_ORD_GETRANDOM); + be32enc(command + TPM_HDRSIZE, TPM_HARVEST_SIZE); + + error = sc->sc_start(sc, UIO_WRITE); + if (error != 0) + return (error); + error = sc->sc_write(sc, command, sizeof(command)); + end_error = sc->sc_end(sc, UIO_WRITE, error); + if (error == 0) + error = end_error; + if (error != 0) + return (error); + + error = sc->sc_start(sc, UIO_READ); + if (error != 0) + return (error); + count = 0; + error = sc->sc_read(sc, response, TPM_HDRSIZE, &count, + TPM_PARAM_SIZE); + if (error != 0) + goto end; + if (count != TPM_HDRSIZE || + be16dec(response) != TPM_TAG_RSP_COMMAND) { + error = EPROTO; + goto end; + } + + response_size = be32dec(response + 2); + if (response_size < TPM_HDRSIZE || response_size > sizeof(response)) { + error = EPROTO; + goto end; + } + if (response_size > TPM_HDRSIZE) { + count = 0; + error = sc->sc_read(sc, response + TPM_HDRSIZE, + (int)(response_size - TPM_HDRSIZE), &count, + TPM_PARAM_SIZE); + if (error != 0) + goto end; + if (count != response_size - TPM_HDRSIZE) { + error = EIO; + goto end; + } + } + + tpm_rc = be32dec(response + 6); + if (tpm_rc != 0) { + error = EIO; + goto end; + } + if (response_size < TPM_HDRSIZE + sizeof(uint32_t)) { + error = EPROTO; + goto end; + } + random_size = be32dec(response + TPM_HDRSIZE); + if (random_size > response_size - TPM_HDRSIZE - sizeof(uint32_t)) { + error = EPROTO; + goto end; + } + random_size = MIN(random_size, TPM_HARVEST_SIZE); + +end: + end_error = sc->sc_end(sc, UIO_READ, error); + if (error == 0) + error = end_error; + if (error == 0) { + memcpy(entropy, response + TPM_HDRSIZE + sizeof(uint32_t), + random_size); + *entropy_size = random_size; + } + return (error); +} + +static void +tpm_harvest_enqueue(const uint8_t *entropy, size_t entropy_size) +{ + size_t chunk_size; + + /* Preserve all RNG bytes rather than squashing an oversized event. */ + chunk_size = sizeof(((struct harvest_event *)0)->he_entropy); + while (entropy_size != 0) { + size_t size; + + size = MIN(entropy_size, chunk_size); + random_harvest_queue(entropy, (u_int)size, RANDOM_PURE_TPM); + entropy += size; + entropy_size -= size; + } +} + +static void +tpm_harvest(void *arg, int pending) +{ + struct tpm_softc *sc; + uint8_t entropy[TPM_HARVEST_SIZE]; + size_t entropy_size; + + sc = arg; + entropy_size = 0; + sx_xlock(&sc->sc_lock); + if (sc->sc_dying || sc->sc_suspend != 0) + goto out; + + /* Do not interpose between a user's command and response. */ + if ((sc->sc_flags & TPM_OPEN) == 0 && !sc->sc_command_pending) + (void)tpm_get_random(sc, entropy, &entropy_size); + taskqueue_enqueue_timeout(taskqueue_thread, &sc->sc_harvest_task, + hz * TPM_HARVEST_INTERVAL); +out: + sx_xunlock(&sc->sc_lock); + if (entropy_size != 0) + tpm_harvest_enqueue(entropy, entropy_size); +} +#endif + /* Save TPM state on suspend. */ int tpm_suspend(device_t dev) @@ -1053,6 +1235,11 @@ tpm_suspend(device_t dev) * invalidate that saved state, so retry SaveState before entering S3. */ sc = device_get_softc(dev); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + if (sc->sc_harvest_registered) + taskqueue_drain_timeout(taskqueue_thread, + &sc->sc_harvest_task); +#endif sx_xlock(&sc->sc_lock); if (sc->sc_dying) { error = ENXIO; @@ -1088,6 +1275,11 @@ tpm_suspend(device_t dev) out: sx_xunlock(&sc->sc_lock); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + if (error != 0 && sc->sc_harvest_registered) + taskqueue_enqueue_timeout(taskqueue_thread, + &sc->sc_harvest_task, hz * TPM_HARVEST_INTERVAL); +#endif return (error); } @@ -1117,6 +1309,11 @@ tpm_resume(device_t dev) out: sx_xunlock(&sc->sc_lock); +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + if (error == 0 && sc->sc_harvest_registered) + taskqueue_enqueue_timeout(taskqueue_thread, + &sc->sc_harvest_task, hz * TPM_HARVEST_INTERVAL); +#endif return (error); } diff --git a/sys/dev/tpm/tpmvar.h b/sys/dev/tpm/tpmvar.h index 12cee8e92c90..24e928c25f8d 100644 --- a/sys/dev/tpm/tpmvar.h +++ b/sys/dev/tpm/tpmvar.h @@ -20,6 +20,8 @@ #define _TPMVAR_H #ifdef __FreeBSD__ +#include "opt_tpm.h" + #include #include #include @@ -77,6 +79,10 @@ struct tpm_softc { bool sc_dying; bool sc_locality; bool sc_command_pending; +#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM + struct timeout_task sc_harvest_task; + bool sc_harvest_registered; +#endif #endif #ifndef __FreeBSD__ diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 7b47bd1ac407..55449f779b69 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -218,7 +218,7 @@ device iicoc # OpenCores I2C controller support # random(4) device tpm # Trusted Platform Module -options RANDOM_ENABLE_TPM # enable entropy from TPM 2.0 +options RANDOM_ENABLE_TPM # enable entropy from TPM devices # Include SoC specific configuration include "std.allwinner"