Skip to content

Commit 46d2d33

Browse files
authored
Merge pull request #563 from aidangarske/fenrir-fixes-7606-7610
Reuse transport connections and reduce NV write and hash cache overhead
2 parents c7433c1 + 8030099 commit 46d2d33

10 files changed

Lines changed: 333 additions & 81 deletions

File tree

docs/SWTPM.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Build Options:
5151
* `TPM2_SWTPM_HOST`: The serial device path (default is `/dev/ttyACM0` on Linux, `/dev/cu.usbmodem` on macOS). Can be overridden at runtime via the `TPM2_SWTPM_HOST` environment variable.
5252
* `TPM2_SWTPM_PORT`: The baud rate (default is 115200)
5353

54-
The UART transport uses the same mssim protocol as the socket transport. The serial port is configured as 8N1 raw mode with no flow control. Unlike the socket transport, the serial port file descriptor is kept open across commands (no reconnect per command).
54+
The UART transport uses the same mssim protocol as the socket transport. The serial port is configured as 8N1 raw mode with no flow control. Like the socket transport, the serial port file descriptor is kept open across commands (no reconnect per command). Both transports close the connection during `wolfTPM2_Cleanup`. On the socket transport any transmit/receive failure also closes the connection so the next command reconnects; the UART transport closes only when the per-command `TPM_SESSION_END` write fails.
5555

5656
#### Security note: environment variable override
5757

examples/tpm_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#define TPM2_DEMO_NV_TEST_INDEX 0x01800200
4646
#define TPM2_DEMO_NV_TEST_AUTH_INDEX 0x01800201
4747
#define TPM2_DEMO_NVRAM_STORE_INDEX 0x01800202
48+
#define TPM2_DEMO_NV_TEST_CHUNKED_INDEX 0x01800205
4849
#define TPM2_DEMO_NVRAM_EXTEND_INDEX 0x01000200
4950
#define TPM2_DEMO_NV_TEST_SIZE MAX_DIGEST_BUFFER /* max size on Infineon SLB9670 is 1664 */
5051
#define TPM2_DEMO_NV_COUNTER_INDEX 0x01800300

hal/tpm_io_linux.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#define TPM2_I2C_DEV "/dev/i2c-1"
7777
#define TPM2_I2C_HZ 400000 /* 400kHz */
7878
static int i2cOpenFailed = 0;
79+
static int i2cDevFd = -1;
7980
#else
8081
/* SPI */
8182
#ifndef TPM2_SPI_DEV_CS
@@ -112,6 +113,7 @@
112113
#define TPM2_SPI_DEV TPM2_SPI_DEV_PATH TPM2_SPI_DEV_CS
113114
static int spiOpenFailed = 0;
114115
#endif
116+
static int spiDevFd = -1;
115117
#endif
116118
#endif
117119

@@ -195,14 +197,19 @@
195197
word16 size, void* userCtx)
196198
{
197199
int ret = TPM_RC_FAILURE;
198-
int i2cDev = open(TPM2_I2C_DEV, O_RDWR);
199-
if (i2cDev >= 0) {
200+
if (i2cDevFd < 0) {
201+
i2cDevFd = open(TPM2_I2C_DEV, O_RDWR | O_CLOEXEC);
202+
}
203+
if (i2cDevFd >= 0) {
200204
if (isRead)
201-
ret = i2c_read(i2cDev, addr, buf, size);
205+
ret = i2c_read(i2cDevFd, addr, buf, size);
202206
else
203-
ret = i2c_write(i2cDev, addr, buf, size);
207+
ret = i2c_write(i2cDevFd, addr, buf, size);
204208

205-
close(i2cDev);
209+
if (ret != TPM_RC_SUCCESS) {
210+
close(i2cDevFd);
211+
i2cDevFd = -1;
212+
}
206213
}
207214
else if (!i2cOpenFailed) {
208215
i2cOpenFailed = 1;
@@ -264,7 +271,6 @@
264271
word16 xferSz, void* userCtx)
265272
{
266273
int ret;
267-
int spiDev;
268274
#ifdef WOLFTPM_CHECK_WAIT_STATE
269275
int timeout;
270276
#endif
@@ -274,7 +280,6 @@
274280

275281
/* Note: PI has issue with 5-10Mhz on packets sized over 130 bytes */
276282
unsigned int maxSpeed = TPM2_SPI_HZ;
277-
int mode = 0; /* Mode 0 (CPOL=0, CPHA=0) */
278283
int bits_per_word = 8; /* 8-bits */
279284

280285
#ifdef WOLFTPM_AUTODETECT
@@ -290,16 +295,20 @@
290295
#ifdef WOLFTPM_CHECK_WAIT_STATE
291296
timeout = TPM_SPI_WAIT_RETRY;
292297
#endif
293-
spiDev = open(TPM2_SPI_DEV, O_RDWR);
294-
if (spiDev >= 0) {
298+
if (spiDevFd < 0) {
299+
spiDevFd = open(TPM2_SPI_DEV, O_RDWR | O_CLOEXEC);
300+
if (spiDevFd >= 0) {
301+
int mode = 0; /* Mode 0 (CPOL=0, CPHA=0) */
302+
ioctl(spiDevFd, SPI_IOC_WR_MODE, &mode);
303+
}
304+
}
305+
if (spiDevFd >= 0) {
295306
struct spi_ioc_transfer spi;
296307
size_t size;
297308

298-
ioctl(spiDev, SPI_IOC_WR_MODE, &mode);
299-
ioctl(spiDev, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);
300-
ioctl(spiDev, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word);
301-
302309
XMEMSET(&spi, 0, sizeof(spi));
310+
spi.speed_hz = maxSpeed;
311+
spi.bits_per_word = bits_per_word;
303312

304313
#ifdef WOLFTPM_CHECK_WAIT_STATE
305314
/* Keep CS asserted for header and flow control transfers */
@@ -309,7 +318,7 @@
309318
spi.tx_buf = (unsigned long)txBuf;
310319
spi.rx_buf = (unsigned long)rxBuf;
311320
spi.len = TPM_TIS_HEADER_SZ;
312-
size = ioctl(spiDev, SPI_IOC_MESSAGE(1), &spi);
321+
size = ioctl(spiDevFd, SPI_IOC_MESSAGE(1), &spi);
313322
if (size != TPM_TIS_HEADER_SZ) {
314323
ret = TPM_RC_FAILURE;
315324
}
@@ -322,7 +331,7 @@
322331
spi.len = 1;
323332
do {
324333
/* Check for SPI ready */
325-
size = ioctl(spiDev, SPI_IOC_MESSAGE(1), &spi);
334+
size = ioctl(spiDevFd, SPI_IOC_MESSAGE(1), &spi);
326335
} while (
327336
(size == 1) &&
328337
((rxBuf[TPM_TIS_HEADER_SZ-1] & TPM_TIS_READY_MASK) == 0) &&
@@ -342,7 +351,7 @@
342351
spi.tx_buf = (unsigned long)&txBuf[TPM_TIS_HEADER_SZ];
343352
spi.rx_buf = (unsigned long)&rxBuf[TPM_TIS_HEADER_SZ];
344353
spi.len = xferSz - TPM_TIS_HEADER_SZ;
345-
size = ioctl(spiDev, SPI_IOC_MESSAGE(1), &spi);
354+
size = ioctl(spiDevFd, SPI_IOC_MESSAGE(1), &spi);
346355
if (size != (size_t)xferSz - TPM_TIS_HEADER_SZ)
347356
ret = TPM_RC_FAILURE;
348357
}
@@ -351,20 +360,23 @@
351360
if (spi.cs_change == 1) {
352361
spi.cs_change = 0;
353362
spi.len = 1;
354-
size = ioctl(spiDev, SPI_IOC_MESSAGE(1), &spi);
363+
size = ioctl(spiDevFd, SPI_IOC_MESSAGE(1), &spi);
355364
(void)size; /* Ignore result */
356365
}
357366
#else
358367
/* Send Entire Message - no wait states */
359368
spi.tx_buf = (unsigned long)txBuf;
360369
spi.rx_buf = (unsigned long)rxBuf;
361370
spi.len = xferSz;
362-
size = ioctl(spiDev, SPI_IOC_MESSAGE(1), &spi);
371+
size = ioctl(spiDevFd, SPI_IOC_MESSAGE(1), &spi);
363372
if (size != (size_t)xferSz)
364373
ret = TPM_RC_FAILURE;
365374
#endif /* WOLFTPM_CHECK_WAIT_STATE */
366375

367-
close(spiDev);
376+
if (ret != TPM_RC_SUCCESS) {
377+
close(spiDevFd);
378+
spiDevFd = -1;
379+
}
368380
}
369381
else {
370382
/* Failed to open device */
@@ -398,6 +410,10 @@
398410
foundSpiDev = 1;
399411
}
400412
else {
413+
if (spiDevFd >= 0) {
414+
close(spiDevFd);
415+
spiDevFd = -1;
416+
}
401417
devLen = (int)XSTRLEN(TPM2_SPI_DEV);
402418
/* tries spidev0.[0-4] */
403419
if (TPM2_SPI_DEV[devLen-1] < MAX_SPI_DEV_CS) {

src/fwtpm/fwtpm_io.c

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ int FWTPM_IO_IsStopRequested(void)
8484
#ifndef WOLFTPM_FWTPM_TIS
8585
/* --- Low-level socket helpers --- */
8686

87+
#define FWTPM_MAX_COMMAND_CLIENTS 8
88+
8789
static int SocketSend(SOCKET_T fd, const void* buf, int sz)
8890
{
8991
const char* ptr = (const char*)buf;
@@ -650,10 +652,11 @@ int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)
650652
int rc = TPM_RC_SUCCESS;
651653
fd_set readFds;
652654
int maxFd;
653-
SOCKET_T cmdFd = FWTPM_INVALID_FD; /* active command client fd */
655+
SOCKET_T cmdFds[FWTPM_MAX_COMMAND_CLIENTS];
654656
SOCKET_T platFd = FWTPM_INVALID_FD; /* active platform client fd */
655657
struct timeval tv;
656658
int selRc;
659+
int i;
657660
#ifndef _WIN32
658661
struct sigaction sa;
659662
#endif
@@ -667,6 +670,9 @@ int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)
667670
return FWTPM_TIS_ServerLoop(ctx);
668671
#else
669672
ctx->running = 1;
673+
for (i = 0; i < FWTPM_MAX_COMMAND_CLIENTS; i++) {
674+
cmdFds[i] = FWTPM_INVALID_FD;
675+
}
670676

671677
#ifndef _WIN32
672678
/* Ignore SIGPIPE so write to closed socket returns error instead
@@ -697,9 +703,13 @@ int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)
697703
maxFd = ctx->io.platListenFd;
698704

699705
/* Watch active client connections for incoming data */
700-
if (cmdFd != FWTPM_INVALID_FD) {
701-
FD_SET(cmdFd, &readFds);
702-
if (cmdFd > maxFd) maxFd = cmdFd;
706+
for (i = 0; i < FWTPM_MAX_COMMAND_CLIENTS; i++) {
707+
if (cmdFds[i] != FWTPM_INVALID_FD) {
708+
FD_SET(cmdFds[i], &readFds);
709+
if (cmdFds[i] > maxFd) {
710+
maxFd = cmdFds[i];
711+
}
712+
}
703713
}
704714
if (platFd != FWTPM_INVALID_FD) {
705715
FD_SET(platFd, &readFds);
@@ -739,48 +749,54 @@ int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)
739749
}
740750
}
741751

752+
/* Handle one message from active platform client */
753+
if (platFd != FWTPM_INVALID_FD && FD_ISSET(platFd, &readFds)) {
754+
if (HandlePlatformCommand(ctx, platFd) != TPM_RC_SUCCESS) {
755+
CloseSocket(platFd);
756+
platFd = FWTPM_INVALID_FD;
757+
}
758+
}
759+
760+
/* Handle one message from each ready command client */
761+
for (i = 0; i < FWTPM_MAX_COMMAND_CLIENTS; i++) {
762+
if (cmdFds[i] != FWTPM_INVALID_FD &&
763+
FD_ISSET(cmdFds[i], &readFds)) {
764+
if (HandleCommandConnection(ctx, cmdFds[i]) !=
765+
TPM_RC_SUCCESS) {
766+
CloseSocket(cmdFds[i]);
767+
cmdFds[i] = FWTPM_INVALID_FD;
768+
}
769+
}
770+
}
771+
742772
/* Accept new command connection */
743773
if (FD_ISSET(ctx->io.listenFd, &readFds)) {
744774
SOCKET_T newFd = accept(ctx->io.listenFd, NULL, NULL);
745775
if (newFd != FWTPM_INVALID_FD) {
746-
if (cmdFd != FWTPM_INVALID_FD) {
747-
/* Consume any select-confirmed in-flight command on the
748-
* old connection before dropping it, so a pending
749-
* request is not silently lost. */
750-
if (FD_ISSET(cmdFd, &readFds)) {
751-
HandleCommandConnection(ctx, cmdFd);
776+
for (i = 0; i < FWTPM_MAX_COMMAND_CLIENTS; i++) {
777+
if (cmdFds[i] == FWTPM_INVALID_FD) {
778+
cmdFds[i] = newFd;
779+
break;
752780
}
781+
}
782+
if (i == FWTPM_MAX_COMMAND_CLIENTS) {
753783
#ifdef DEBUG_WOLFTPM
754-
printf("fwTPM: command connection replaced\n");
784+
printf("fwTPM: too many command connections\n");
755785
#endif
756-
CloseSocket(cmdFd);
786+
CloseSocket(newFd);
757787
}
758-
cmdFd = newFd;
759-
}
760-
}
761-
762-
/* Handle one message from active platform client */
763-
if (platFd != FWTPM_INVALID_FD && FD_ISSET(platFd, &readFds)) {
764-
if (HandlePlatformCommand(ctx, platFd) != TPM_RC_SUCCESS) {
765-
CloseSocket(platFd);
766-
platFd = FWTPM_INVALID_FD;
767788
}
768789
}
790+
}
769791

770-
/* Handle one message from active command client */
771-
if (cmdFd != FWTPM_INVALID_FD && FD_ISSET(cmdFd, &readFds)) {
772-
if (HandleCommandConnection(ctx, cmdFd) != TPM_RC_SUCCESS) {
773-
CloseSocket(cmdFd);
774-
cmdFd = FWTPM_INVALID_FD;
775-
/* Transient state persists across command connections: the
776-
* mssim transport reconnects per command for one logical TPM,
777-
* so a clean disconnect must not flush handles. */
778-
}
792+
for (i = 0; i < FWTPM_MAX_COMMAND_CLIENTS; i++) {
793+
if (cmdFds[i] != FWTPM_INVALID_FD) {
794+
CloseSocket(cmdFds[i]);
779795
}
780796
}
781-
782-
if (cmdFd != FWTPM_INVALID_FD) CloseSocket(cmdFd);
783-
if (platFd != FWTPM_INVALID_FD) CloseSocket(platFd);
797+
if (platFd != FWTPM_INVALID_FD) {
798+
CloseSocket(platFd);
799+
}
784800

785801
return rc;
786802
#endif /* !WOLFTPM_FWTPM_TIS */

src/tpm2.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,11 @@ TPM_RC TPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx,
854854

855855
XMEMSET(ctx, 0, sizeof(TPM2_CTX));
856856

857+
#if defined(WOLFTPM_SWTPM)
858+
/* set before any early return so cleanup cannot act on fd 0 */
859+
ctx->tcpCtx.fd = -1;
860+
#endif
861+
857862
#ifndef WOLFTPM_NO_RETRY
858863
ctx->retries = WOLFTPM_MAX_RETRIES;
859864
#endif
@@ -864,10 +869,6 @@ TPM_RC TPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx,
864869
return rc;
865870
#endif
866871

867-
#if defined(WOLFTPM_SWTPM)
868-
ctx->tcpCtx.fd = -1;
869-
#endif
870-
871872
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || \
872873
defined(WOLFTPM_WINAPI)
873874
if (ioCb != NULL || userCtx != NULL) {
@@ -976,9 +977,8 @@ TPM_RC TPM2_Cleanup(TPM2_CTX* ctx)
976977
close(ctx->fd);
977978
#endif
978979

979-
#ifdef WOLFTPM_SWTPM_UART
980-
/* Close the persistent UART connection */
981-
TPM2_SwtpmCloseUART(ctx);
980+
#ifdef WOLFTPM_SWTPM
981+
TPM2_SwtpmClose(ctx);
982982
#endif
983983

984984
return TPM_RC_SUCCESS;

src/tpm2_cryptocb.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,13 +817,19 @@ static int wolfTPM2_HashUpdateCache(WOLFTPM2_HASHCTX* hashCtx,
817817
else if ((hashCtx->cacheSz + inSz) > hashCtx->cacheBufSz) {
818818
byte* oldIn = hashCtx->cacheBuf;
819819
word32 oldBufSz = hashCtx->cacheBufSz;
820+
word32 newSz;
820821
/* check for overflow, including the block round-up below */
821822
if (hashCtx->cacheSz + inSz < hashCtx->cacheSz ||
822823
hashCtx->cacheSz + inSz >
823824
0xFFFFFFFFU - (WOLFTPM2_HASH_BLOCK_SZ - 1)) {
824825
return BUFFER_E;
825826
}
826-
hashCtx->cacheBufSz = (hashCtx->cacheSz + inSz +
827+
newSz = hashCtx->cacheSz + inSz;
828+
/* Block alignment keeps the round-up safe after doubling. */
829+
if (oldBufSz <= 0xFFFFFFFFU / 2 && (oldBufSz * 2) > newSz) {
830+
newSz = oldBufSz * 2;
831+
}
832+
hashCtx->cacheBufSz = (newSz +
827833
WOLFTPM2_HASH_BLOCK_SZ - 1) & ~(WOLFTPM2_HASH_BLOCK_SZ - 1);
828834
hashCtx->cacheBuf = (byte*)XMALLOC(hashCtx->cacheBufSz,
829835
NULL, DYNAMIC_TYPE_TMP_BUFFER);

0 commit comments

Comments
 (0)