Skip to content

Commit 3d7a850

Browse files
author
Jarkko Sakkinen
committed
tpm/tpm_crb: Avoid unaligned reads in crb_recv()
The current approach to read first 6 bytes from the response and then tail of the response, can cause the 2nd memcpy_fromio() to do an unaligned read (e.g. read 32-bit word from address aligned to a 16-bits), depending on how memcpy_fromio() is implemented. If this happens, the read will fail and the memory controller will fill the read with 1's. This was triggered by 170d13c, which should be probably refined to check and react to the address alignment. Before that commit, on x86 memcpy_fromio() turned out to be memcpy(). By a luck GCC has done the right thing (from tpm_crb's perspective) for us so far, but we should not rely on that. Thus, it makes sense to fix this also in tpm_crb, not least because the fix can be then backported to stable kernels and make them more robust when compiled in differing environments. Cc: stable@vger.kernel.org Cc: James Morris <jmorris@namei.org> Cc: Tomas Winkler <tomas.winkler@intel.com> Cc: Jerry Snitselaar <jsnitsel@redhat.com> Fixes: 30fc8d1 ("tpm: TPM 2.0 CRB Interface") Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com> Acked-by: Tomas Winkler <tomas.winkler@intel.com>
1 parent 2181e08 commit 3d7a850

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

drivers/char/tpm/tpm_crb.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,19 +287,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
287287
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
288288
unsigned int expected;
289289

290-
/* sanity check */
291-
if (count < 6)
290+
/* A sanity check that the upper layer wants to get at least the header
291+
* as that is the minimum size for any TPM response.
292+
*/
293+
if (count < TPM_HEADER_SIZE)
292294
return -EIO;
293295

296+
/* If this bit is set, according to the spec, the TPM is in
297+
* unrecoverable condition.
298+
*/
294299
if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR)
295300
return -EIO;
296301

297-
memcpy_fromio(buf, priv->rsp, 6);
298-
expected = be32_to_cpup((__be32 *) &buf[2]);
299-
if (expected > count || expected < 6)
302+
/* Read the first 8 bytes in order to get the length of the response.
303+
* We read exactly a quad word in order to make sure that the remaining
304+
* reads will be aligned.
305+
*/
306+
memcpy_fromio(buf, priv->rsp, 8);
307+
308+
expected = be32_to_cpup((__be32 *)&buf[2]);
309+
if (expected > count || expected < TPM_HEADER_SIZE)
300310
return -EIO;
301311

302-
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
312+
memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
303313

304314
return expected;
305315
}

0 commit comments

Comments
 (0)