[v3] tpm/tpm_crb: Avoid unaligned reads in crb_recv()
diff mbox series

Message ID 20190205105136.3086-1-jarkko.sakkinen@linux.intel.com
State New
Headers show
Series
  • [v3] tpm/tpm_crb: Avoid unaligned reads in crb_recv()
Related show

Commit Message

Jarkko Sakkinen Feb. 5, 2019, 10:51 a.m. UTC
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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
---
v3:
* Fix typo i.e. %s/reminding/remaining/g
v2:
* There was a trailing double colon in the end of the short summary.
* Check requested and expected length against TPM_HEADER_SIZE.
* Add some explanatory comments to crb_recv().
 drivers/char/tpm/tpm_crb.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

Comments

Tomas Winkler Feb. 5, 2019, 11:07 a.m. UTC | #1
> 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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
> ---
> v3:
> * Fix typo i.e. %s/reminding/remaining/g

Why you haven't fixed all the typos I've pointed out? I think you missed that.
Tomas

> v2:
> * There was a trailing double colon in the end of the short summary.
> * Check requested and expected length against TPM_HEADER_SIZE.
> * Add some explanatory comments to crb_recv().
>  drivers/char/tpm/tpm_crb.c | 22 ++++++++++++++++------
>  1 file changed, 16 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index
> 36952ef98f90..ee4df7815912 100644
> --- a/drivers/char/tpm/tpm_crb.c
> +++ b/drivers/char/tpm/tpm_crb.c
> @@ -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)
>  		return -EIO;
> 
> +	/* If this bit is set, according to the spec, the TPM is in unrecovable
> +	 * condition.
> +	 */
>  	if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR)
>  		return -EIO;
> 
> -	memcpy_fromio(buf, priv->rsp, 6);
> -	expected = be32_to_cpup((__be32 *) &buf[2]);
> -	if (expected > count || expected < 6)
> +	/* Read 8 bytes (not just 6 bytes, which would cover the response
> length
> +	 * field) in order to make sure that the remaining memory accesses
> will
> +	 * be aligned.
> +	 */
> +	memcpy_fromio(buf, priv->rsp, 8);
> +
> +	expected = be32_to_cpup((__be32 *)&buf[2]);
> +	if (expected > count || expected < TPM_HEADER_SIZE)
>  		return -EIO;
> 
> -	memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
> +	memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
> 
>  	return expected;
>  }
> --
> 2.19.1
Jarkko Sakkinen Feb. 5, 2019, 2:35 p.m. UTC | #2
On Tue, Feb 05, 2019 at 11:07:16AM +0000, Winkler, Tomas wrote:
> > 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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
> > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> > Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
> > ---
> > v3:
> > * Fix typo i.e. %s/reminding/remaining/g
> 
> Why you haven't fixed all the typos I've pointed out? I think you missed that.

I saw only comment about remaining. Was there something else? Can fix.

/Jarkko
Tomas Winkler Feb. 5, 2019, 2:56 p.m. UTC | #3
> -----Original Message-----
> From: Jarkko Sakkinen [mailto:jarkko.sakkinen@linux.intel.com]
> Sent: Tuesday, February 05, 2019 16:36
> To: Winkler, Tomas <tomas.winkler@intel.com>
> Cc: linux-integrity@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> security-module@vger.kernel.org; stable@vger.kernel.org; James Morris
> <jmorris@namei.org>; Jerry Snitselaar <jsnitsel@redhat.com>
> Subject: Re: [PATCH v3] tpm/tpm_crb: Avoid unaligned reads in crb_recv()
> 
> On Tue, Feb 05, 2019 at 11:07:16AM +0000, Winkler, Tomas wrote:
> > > 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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
> > > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> > > Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
> > > ---
> > > v3:
> > > * Fix typo i.e. %s/reminding/remaining/g
> >
> > Why you haven't fixed all the typos I've pointed out? I think you missed that.
> 
> I saw only comment about remaining. Was there something else? Can fix.

https://www.spinics.net/lists/stable/msg283648.html

1. unrecovable -> unrecoverable
2. /* Read 8 bytes (not just 6 bytes, which would cover the tag and the response  length
> +	 * fields) in order to make sure that the remaining memory accesses */ 
                                                                             
Thanks
Tomas
Jarkko Sakkinen Feb. 5, 2019, 8:57 p.m. UTC | #4
On Tue, Feb 05, 2019 at 02:56:02PM +0000, Winkler, Tomas wrote:
> 
> 
> > -----Original Message-----
> > From: Jarkko Sakkinen [mailto:jarkko.sakkinen@linux.intel.com]
> > Sent: Tuesday, February 05, 2019 16:36
> > To: Winkler, Tomas <tomas.winkler@intel.com>
> > Cc: linux-integrity@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> > security-module@vger.kernel.org; stable@vger.kernel.org; James Morris
> > <jmorris@namei.org>; Jerry Snitselaar <jsnitsel@redhat.com>
> > Subject: Re: [PATCH v3] tpm/tpm_crb: Avoid unaligned reads in crb_recv()
> > 
> > On Tue, Feb 05, 2019 at 11:07:16AM +0000, Winkler, Tomas wrote:
> > > > 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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
> > > > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> > > > Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
> > > > ---
> > > > v3:
> > > > * Fix typo i.e. %s/reminding/remaining/g
> > >
> > > Why you haven't fixed all the typos I've pointed out? I think you missed that.
> > 
> > I saw only comment about remaining. Was there something else? Can fix.
> 
> https://www.spinics.net/lists/stable/msg283648.html
> 
> 1. unrecovable -> unrecoverable
> 2. /* Read 8 bytes (not just 6 bytes, which would cover the tag and the response  length
> > +	 * fields) in order to make sure that the remaining memory accesses */ 

Thanks and apologies for missing these.

/Jarkko
Jarkko Sakkinen Feb. 6, 2019, 12:43 p.m. UTC | #5
On Tue, Feb 05, 2019 at 10:57:19PM +0200, Jarkko Sakkinen wrote:
> On Tue, Feb 05, 2019 at 02:56:02PM +0000, Winkler, Tomas wrote:
> > 
> > 
> > > -----Original Message-----
> > > From: Jarkko Sakkinen [mailto:jarkko.sakkinen@linux.intel.com]
> > > Sent: Tuesday, February 05, 2019 16:36
> > > To: Winkler, Tomas <tomas.winkler@intel.com>
> > > Cc: linux-integrity@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> > > security-module@vger.kernel.org; stable@vger.kernel.org; James Morris
> > > <jmorris@namei.org>; Jerry Snitselaar <jsnitsel@redhat.com>
> > > Subject: Re: [PATCH v3] tpm/tpm_crb: Avoid unaligned reads in crb_recv()
> > > 
> > > On Tue, Feb 05, 2019 at 11:07:16AM +0000, Winkler, Tomas wrote:
> > > > > 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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
> > > > > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> > > > > Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
> > > > > ---
> > > > > v3:
> > > > > * Fix typo i.e. %s/reminding/remaining/g
> > > >
> > > > Why you haven't fixed all the typos I've pointed out? I think you missed that.
> > > 
> > > I saw only comment about remaining. Was there something else? Can fix.
> > 
> > https://www.spinics.net/lists/stable/msg283648.html
> > 
> > 1. unrecovable -> unrecoverable
> > 2. /* Read 8 bytes (not just 6 bytes, which would cover the tag and the response  length
> > > +	 * fields) in order to make sure that the remaining memory accesses */ 
> 
> Thanks and apologies for missing these.

Fixed comments and applied the patch, thank you. Do I amend your
acked-by?

/Jarkko
Tomas Winkler Feb. 6, 2019, 12:55 p.m. UTC | #6
()
> 
> On Tue, Feb 05, 2019 at 10:57:19PM +0200, Jarkko Sakkinen wrote:
> > On Tue, Feb 05, 2019 at 02:56:02PM +0000, Winkler, Tomas wrote:
> > >
> > >
> > > > -----Original Message-----
> > > > From: Jarkko Sakkinen [mailto:jarkko.sakkinen@linux.intel.com]
> > > > Sent: Tuesday, February 05, 2019 16:36
> > > > To: Winkler, Tomas <tomas.winkler@intel.com>
> > > > Cc: linux-integrity@vger.kernel.org; linux-kernel@vger.kernel.org;
> > > > linux- security-module@vger.kernel.org; stable@vger.kernel.org;
> > > > James Morris <jmorris@namei.org>; Jerry Snitselaar
> > > > <jsnitsel@redhat.com>
> > > > Subject: Re: [PATCH v3] tpm/tpm_crb: Avoid unaligned reads in
> > > > crb_recv()
> > > >
> > > > On Tue, Feb 05, 2019 at 11:07:16AM +0000, Winkler, Tomas wrote:
> > > > > > 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 170d13ca3a2f, 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: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
> > > > > > Signed-off-by: Jarkko Sakkinen
> > > > > > <jarkko.sakkinen@linux.intel.com>
> > > > > > Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
> > > > > > ---
> > > > > > v3:
> > > > > > * Fix typo i.e. %s/reminding/remaining/g
> > > > >
> > > > > Why you haven't fixed all the typos I've pointed out? I think you missed
> that.
> > > >
> > > > I saw only comment about remaining. Was there something else? Can fix.
> > >
> > > https://www.spinics.net/lists/stable/msg283648.html
> > >
> > > 1. unrecovable -> unrecoverable
> > > 2. /* Read 8 bytes (not just 6 bytes, which would cover the tag and
> > > the response  length
> > > > +	 * fields) in order to make sure that the remaining memory
> > > > +accesses */
> >
> > Thanks and apologies for missing these.
> 
> Fixed comments and applied the patch, thank you. Do I amend your acked-by?

Please, do.
Thanks
Tomas
Jarkko Sakkinen Feb. 6, 2019, 1:20 p.m. UTC | #7
On Wed, Feb 06, 2019 at 12:55:55PM +0000, Winkler, Tomas wrote:
> > Fixed comments and applied the patch, thank you. Do I amend your acked-by?
> 
> Please, do.
> Thanks
> Tomas

Great, thank you.

/Jarkko

Patch
diff mbox series

diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 36952ef98f90..ee4df7815912 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -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)
 		return -EIO;
 
+	/* If this bit is set, according to the spec, the TPM is in unrecovable
+	 * condition.
+	 */
 	if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR)
 		return -EIO;
 
-	memcpy_fromio(buf, priv->rsp, 6);
-	expected = be32_to_cpup((__be32 *) &buf[2]);
-	if (expected > count || expected < 6)
+	/* Read 8 bytes (not just 6 bytes, which would cover the response length
+	 * field) in order to make sure that the remaining memory accesses will
+	 * be aligned.
+	 */
+	memcpy_fromio(buf, priv->rsp, 8);
+
+	expected = be32_to_cpup((__be32 *)&buf[2]);
+	if (expected > count || expected < TPM_HEADER_SIZE)
 		return -EIO;
 
-	memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
+	memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
 
 	return expected;
 }