1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 36952ef98f90..763fc7e6c005 100644
@@ -287,19 +287,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
unsigned int expected;
- /* sanity check */
- if (count < 6)
+ /* A sanity check that the upper layer wants to get at least the header
+ * as that is the minimum size for any TPM response.
+ if (count < TPM_HEADER_SIZE)
+ /* If this bit is set, according to the spec, the TPM is in
+ * unrecoverable condition.
if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR)
- memcpy_fromio(buf, priv->rsp, 6);
- expected = be32_to_cpup((__be32 *) &buf);
- if (expected > count || expected < 6)
+ /* Read the first 8 bytes in order to get the length of the response.
+ * We read exactly a quad word in order to make sure that the remaining
+ * reads will be aligned.
+ memcpy_fromio(buf, priv->rsp, 8);
+ expected = be32_to_cpup((__be32 *)&buf);
+ if (expected > count || expected < TPM_HEADER_SIZE)
- memcpy_fromio(&buf, &priv->rsp, expected - 6);
+ memcpy_fromio(&buf, &priv->rsp, expected - 8);