Patch "tpm: fix Atmel TPM crash caused by too frequent queries" has been added to the 5.14-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    tpm: fix Atmel TPM crash caused by too frequent queries

to the 5.14-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     tpm-fix-atmel-tpm-crash-caused-by-too-frequent-queri.patch
and it can be found in the queue-5.14 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 25421b34e18caf5ca599811a678ffecd0bb2375f
Author: Hao Wu <hao.wu@xxxxxxxxxx>
Date:   Wed Sep 8 02:26:06 2021 -0700

    tpm: fix Atmel TPM crash caused by too frequent queries
    
    [ Upstream commit 79ca6f74dae067681a779fd573c2eb59649989bc ]
    
    The Atmel TPM 1.2 chips crash with error
    `tpm_try_transmit: send(): error -62` since kernel 4.14.
    It is observed from the kernel log after running `tpm_sealdata -z`.
    The error thrown from the command is as follows
    ```
    $ tpm_sealdata -z
    Tspi_Key_LoadKey failed: 0x00001087 - layer=tddl,
    code=0087 (135), I/O error
    ```
    
    The issue was reproduced with the following Atmel TPM chip:
    ```
    $ tpm_version
    T0  TPM 1.2 Version Info:
      Chip Version:        1.2.66.1
      Spec Level:          2
      Errata Revision:     3
      TPM Vendor ID:       ATML
      TPM Version:         01010000
      Manufacturer Info:   41544d4c
    ```
    
    The root cause of the issue is due to the TPM calls to msleep()
    were replaced with usleep_range() [1], which reduces
    the actual timeout. Via experiments, it is observed that
    the original msleep(5) actually sleeps for 15ms.
    Because of a known timeout issue in Atmel TPM 1.2 chip,
    the shorter timeout than 15ms can cause the error described above.
    
    A few further changes in kernel 4.16 [2] and 4.18 [3, 4] further
    reduced the timeout to less than 1ms. With experiments,
    the problematic timeout in the latest kernel is the one
    for `wait_for_tpm_stat`.
    
    To fix it, the patch reverts the timeout of `wait_for_tpm_stat`
    to 15ms for all Atmel TPM 1.2 chips, but leave it untouched
    for Ateml TPM 2.0 chip, and chips from other vendors.
    As explained above, the chosen 15ms timeout is
    the actual timeout before this issue introduced,
    thus the old value is used here.
    Particularly, TPM_ATML_TIMEOUT_WAIT_STAT_MIN is set to 14700us,
    TPM_ATML_TIMEOUT_WAIT_STAT_MIN is set to 15000us according to
    the existing TPM_TIMEOUT_RANGE_US (300us).
    The fixed has been tested in the system with the affected Atmel chip
    with no issues observed after boot up.
    
    References:
    [1] 9f3fc7bcddcb tpm: replace msleep() with usleep_range() in TPM
    1.2/2.0 generic drivers
    [2] cf151a9a44d5 tpm: reduce tpm polling delay in tpm_tis_core
    [3] 59f5a6b07f64 tpm: reduce poll sleep time in tpm_transmit()
    [4] 424eaf910c32 tpm: reduce polling time to usecs for even finer
    granularity
    
    Fixes: 9f3fc7bcddcb ("tpm: replace msleep() with usleep_range() in TPM 1.2/2.0 generic drivers")
    Link: https://patchwork.kernel.org/project/linux-integrity/patch/20200926223150.109645-1-hao.wu@xxxxxxxxxx/
    Signed-off-by: Hao Wu <hao.wu@xxxxxxxxxx>
    Reviewed-by: Jarkko Sakkinen <jarkko@xxxxxxxxxx>
    Signed-off-by: Jarkko Sakkinen <jarkko@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 69579efb247b3..b2659a4c40168 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -48,6 +48,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
 		unsigned long timeout, wait_queue_head_t *queue,
 		bool check_cancel)
 {
+	struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
 	unsigned long stop;
 	long rc;
 	u8 status;
@@ -80,8 +81,8 @@ again:
 		}
 	} else {
 		do {
-			usleep_range(TPM_TIMEOUT_USECS_MIN,
-				     TPM_TIMEOUT_USECS_MAX);
+			usleep_range(priv->timeout_min,
+				     priv->timeout_max);
 			status = chip->ops->status(chip);
 			if ((status & mask) == mask)
 				return 0;
@@ -945,7 +946,22 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
 	chip->timeout_b = msecs_to_jiffies(TIS_TIMEOUT_B_MAX);
 	chip->timeout_c = msecs_to_jiffies(TIS_TIMEOUT_C_MAX);
 	chip->timeout_d = msecs_to_jiffies(TIS_TIMEOUT_D_MAX);
+	priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
+	priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
 	priv->phy_ops = phy_ops;
+
+	rc = tpm_tis_read32(priv, TPM_DID_VID(0), &vendor);
+	if (rc < 0)
+		goto out_err;
+
+	priv->manufacturer_id = vendor;
+
+	if (priv->manufacturer_id == TPM_VID_ATML &&
+		!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+		priv->timeout_min = TIS_TIMEOUT_MIN_ATML;
+		priv->timeout_max = TIS_TIMEOUT_MAX_ATML;
+	}
+
 	dev_set_drvdata(&chip->dev, priv);
 
 	if (is_bsw()) {
@@ -988,12 +1004,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
 	if (rc)
 		goto out_err;
 
-	rc = tpm_tis_read32(priv, TPM_DID_VID(0), &vendor);
-	if (rc < 0)
-		goto out_err;
-
-	priv->manufacturer_id = vendor;
-
 	rc = tpm_tis_read8(priv, TPM_RID(0), &rid);
 	if (rc < 0)
 		goto out_err;
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index b2a3c6c72882d..3be24f221e32a 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -54,6 +54,8 @@ enum tis_defaults {
 	TIS_MEM_LEN = 0x5000,
 	TIS_SHORT_TIMEOUT = 750,	/* ms */
 	TIS_LONG_TIMEOUT = 2000,	/* 2 sec */
+	TIS_TIMEOUT_MIN_ATML = 14700,	/* usecs */
+	TIS_TIMEOUT_MAX_ATML = 15000,	/* usecs */
 };
 
 /* Some timeout values are needed before it is known whether the chip is
@@ -98,6 +100,8 @@ struct tpm_tis_data {
 	wait_queue_head_t read_queue;
 	const struct tpm_tis_phy_ops *phy_ops;
 	unsigned short rng_quality;
+	unsigned int timeout_min; /* usecs */
+	unsigned int timeout_max; /* usecs */
 };
 
 struct tpm_tis_phy_ops {
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index aa11fe323c56b..12d827734686d 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -269,6 +269,7 @@ enum tpm2_cc_attrs {
 #define TPM_VID_INTEL    0x8086
 #define TPM_VID_WINBOND  0x1050
 #define TPM_VID_STM      0x104A
+#define TPM_VID_ATML     0x1114
 
 enum tpm_chip_flags {
 	TPM_CHIP_FLAG_TPM2		= BIT(1),



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux