2021-10-21 12:21:12

by Amir Mizinski

[permalink] [raw]
Subject: [PATCH v16 1/6] tpm_tis: Fix expected bit handling and send all bytes in one shot without last byte in exception

From: Amir Mizinski <[email protected]>

Detected an incorrect implementation of the send command.
Currently, the driver polls the TPM_STS.stsValid field until TRUE; then it
reads TPM_STS register again to verify only that TPM_STS.expect field is
FALSE (i.e., it ignores TPM_STS.stsValid).
Since TPM_STS.stsValid represents the TPM_STS.expect validity, a check of
only one of these fields is wrong. Fix this condition so that both fields
are checked in the same TPM_STS register read.

Modify the signature of 'wait_for_tpm_stat()', adding an additional
"result" parameter to its call.
'wait_for_tpm_stat()' is now polling the TPM_STS with a mask and waits
for the value in result. This modification adds the ability to check if
certain TPM_STS bits have been cleared.
For example, use the new parameter to check in status that TPM_STS_VALID
is set and also that TPM_STS_EXPECT is zeroed. This prevents a racy
check.

In addition, the send command was changed to comply with
TCG_DesignPrinciples_TPM2p0Driver_vp24_pubrev.pdf as follows:
- send all command bytes in one loop
- remove special handling of the last byte

Fixes: 27084efee0c3 (tpm: driver for next generation TPM chips)
Suggested-by: Benoit Houyere <[email protected]>
Signed-off-by: Amir Mizinski <[email protected]>
---
drivers/char/tpm/tpm_tis_core.c | 68 +++++++++++++++--------------------------
1 file changed, 25 insertions(+), 43 deletions(-)

diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 69579ef..0985184 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -44,9 +44,9 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
return false;
}

-static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
- unsigned long timeout, wait_queue_head_t *queue,
- bool check_cancel)
+static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, u8 result,
+ unsigned long timeout,
+ wait_queue_head_t *queue, bool check_cancel)
{
unsigned long stop;
long rc;
@@ -55,7 +55,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,

/* check current status */
status = chip->ops->status(chip);
- if ((status & mask) == mask)
+ if ((status & mask) == result)
return 0;

stop = jiffies + timeout;
@@ -83,7 +83,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
usleep_range(TPM_TIMEOUT_USECS_MIN,
TPM_TIMEOUT_USECS_MAX);
status = chip->ops->status(chip);
- if ((status & mask) == mask)
+ if ((status & mask) == result)
return 0;
} while (time_before(jiffies, stop));
}
@@ -260,9 +260,10 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)

while (size < count) {
rc = wait_for_tpm_stat(chip,
- TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- chip->timeout_c,
- &priv->read_queue, true);
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ chip->timeout_c, &priv->read_queue,
+ true);
if (rc < 0)
return rc;
burstcnt = get_burstcount(chip);
@@ -315,8 +316,9 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto out;
}

- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat(chip, TPM_STS_VALID, TPM_STS_VALID,
+ chip->timeout_c, &priv->int_queue,
+ false) < 0) {
size = -ETIME;
goto out;
}
@@ -342,61 +344,40 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc, status, burstcnt;
size_t count = 0;
- bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;

status = tpm_tis_status(chip);
if ((status & TPM_STS_COMMAND_READY) == 0) {
tpm_tis_ready(chip);
- if (wait_for_tpm_stat
- (chip, TPM_STS_COMMAND_READY, chip->timeout_b,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat(chip, TPM_STS_COMMAND_READY,
+ TPM_STS_COMMAND_READY,
+ chip->timeout_b, &priv->int_queue,
+ false) < 0) {
rc = -ETIME;
goto out_err;
}
}

- while (count < len - 1) {
+ while (count < len) {
burstcnt = get_burstcount(chip);
if (burstcnt < 0) {
dev_err(&chip->dev, "Unable to read burstcount\n");
rc = burstcnt;
goto out_err;
}
- burstcnt = min_t(int, burstcnt, len - count - 1);
+ burstcnt = min_t(int, burstcnt, len - count);
rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality),
burstcnt, buf + count);
if (rc < 0)
goto out_err;

count += burstcnt;
-
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- rc = -ETIME;
- goto out_err;
- }
- status = tpm_tis_status(chip);
- if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
- rc = -EIO;
- goto out_err;
- }
}
-
- /* write last byte */
- rc = tpm_tis_write8(priv, TPM_DATA_FIFO(priv->locality), buf[count]);
- if (rc < 0)
- goto out_err;
-
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat(chip, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
+ TPM_STS_VALID, chip->timeout_a,
+ &priv->int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
- status = tpm_tis_status(chip);
- if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) {
- rc = -EIO;
- goto out_err;
- }

return 0;

@@ -451,9 +432,10 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));

dur = tpm_calc_ordinal_duration(chip, ordinal);
- if (wait_for_tpm_stat
- (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
- &priv->read_queue, false) < 0) {
+ if (wait_for_tpm_stat(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ dur, &priv->read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
--
2.7.4


2021-10-23 00:46:11

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [PATCH v16 1/6] tpm_tis: Fix expected bit handling and send all bytes in one shot without last byte in exception

On Thu, 2021-10-21 at 15:05 +0300, [email protected] wrote:
> From: Amir Mizinski <[email protected]>
>
> Detected an incorrect implementation of the send command.

Nit: please just remove this sentence.

It tells nothing.

> Currently, the driver polls the TPM_STS.stsValid field until TRUE; then it
> reads TPM_STS register again to verify only that TPM_STS.expect field is
> FALSE (i.e., it ignores TPM_STS.stsValid).
> Since TPM_STS.stsValid represents the TPM_STS.expect validity, a check of
> only one of these fields is wrong. Fix this condition so that both fields
> are checked in the same TPM_STS register read.
>
> Modify the signature of 'wait_for_tpm_stat()', adding an additional

Remove single quotes from functions, e.g. just write
wait_form_tpm_stat().

> "result" parameter to its call.
> 'wait_for_tpm_stat()' is now polling the TPM_STS with a mask and waits
> for the value in result. This modification adds the ability to check if
> certain TPM_STS bits have been cleared.
> For example, use the new parameter to check in status that TPM_STS_VALID
> is set and also that TPM_STS_EXPECT is zeroed. This prevents a racy
> check.
>
> In addition, the send command was changed to comply with
> TCG_DesignPrinciples_TPM2p0Driver_vp24_pubrev.pdf as follows:
> - send all command bytes in one loop

What does this mean? Also, please write proper sentences with
the first letter capitalized etc. Also, I'm missing what is the
thing that this patch is complying with, and why we should care?

A bug fix should never do anything else than fix a bug.

> - remove special handling of the last byte

I have no idea what you mean by send command. Please, refer
to some thing that exists, e.g. a function or what ever.

Nit: try not to use passive form in a commit message. E.g.
"Change ... to comply with" would be better.

>
> Fixes: 27084efee0c3 (tpm: driver for next generation TPM chips)

This is incorrectly formatted, it is missing double quotes. Have you run
your patches through checkpatch.pl? Please review "Describe your
changes" section from Documentation/SubmittingPatches.

/Jarkko