diff mbox series

char: tpm: tpm-buf: Fix uninitialized return values in read helpers

Message ID 20250409205536.210202-1-purvayeshi550@gmail.com (mailing list archive)
State New
Headers show
Series char: tpm: tpm-buf: Fix uninitialized return values in read helpers | expand

Commit Message

Purva Yeshi April 9, 2025, 8:55 p.m. UTC
Fix Smatch-detected error:
drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
uninitialized symbol 'value'.
drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
uninitialized symbol 'value'.
drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
uninitialized symbol 'value'.

Call tpm_buf_read() to populate value but do not check its return
status. If the read fails, value remains uninitialized, causing
undefined behavior when returned or processed.

Initialize value to zero to ensure a defined return even if
tpm_buf_read() fails, avoiding undefined behavior from using
an uninitialized variable.

Signed-off-by: Purva Yeshi <purvayeshi550@gmail.com>
---
 drivers/char/tpm/tpm-buf.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Comments

Jarkko Sakkinen April 10, 2025, 6:14 a.m. UTC | #1
On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
> Fix Smatch-detected error:
> drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
> uninitialized symbol 'value'.
> drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
> uninitialized symbol 'value'.
> drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
> uninitialized symbol 'value'.
> 
> Call tpm_buf_read() to populate value but do not check its return
> status. If the read fails, value remains uninitialized, causing
> undefined behavior when returned or processed.
> 
> Initialize value to zero to ensure a defined return even if
> tpm_buf_read() fails, avoiding undefined behavior from using
> an uninitialized variable.

How does tpm_buf_read() fail?

> 
> Signed-off-by: Purva Yeshi <purvayeshi550@gmail.com>
> ---
>  drivers/char/tpm/tpm-buf.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
> index e49a19fea3bd..dc882fc9fa9e 100644
> --- a/drivers/char/tpm/tpm-buf.c
> +++ b/drivers/char/tpm/tpm-buf.c
> @@ -201,7 +201,7 @@ static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count, void
>   */
>  u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset)
>  {
> -	u8 value;
> +	u8 value = 0;
>  
>  	tpm_buf_read(buf, offset, sizeof(value), &value);
>  
> @@ -218,7 +218,7 @@ EXPORT_SYMBOL_GPL(tpm_buf_read_u8);
>   */
>  u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset)
>  {
> -	u16 value;
> +	u16 value = 0;
>  
>  	tpm_buf_read(buf, offset, sizeof(value), &value);
>  
> @@ -235,7 +235,7 @@ EXPORT_SYMBOL_GPL(tpm_buf_read_u16);
>   */
>  u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
>  {
> -	u32 value;
> +	u32 value = 0;
>  
>  	tpm_buf_read(buf, offset, sizeof(value), &value);
>  
> -- 
> 2.34.1
> 

BR, Jarkko
Stefano Garzarella April 10, 2025, 7:51 a.m. UTC | #2
On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
>On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
>> Fix Smatch-detected error:
>> drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
>> uninitialized symbol 'value'.
>> drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
>> uninitialized symbol 'value'.
>> drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
>> uninitialized symbol 'value'.
>>
>> Call tpm_buf_read() to populate value but do not check its return
>> status. If the read fails, value remains uninitialized, causing
>> undefined behavior when returned or processed.
>>
>> Initialize value to zero to ensure a defined return even if
>> tpm_buf_read() fails, avoiding undefined behavior from using
>> an uninitialized variable.
>
>How does tpm_buf_read() fail?

If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are 
effectively returning random stack bytes to the caller.
Could this be a problem?

If it is, maybe instead of this patch, we could set `*output` to zero in 
the error path of tpm_buf_read(). Or return an error from tpm_buf_read() 
so callers can return 0 or whatever they want.

Thanks,
Stefano
Purva Yeshi April 10, 2025, 8:42 a.m. UTC | #3
On 10/04/25 13:21, Stefano Garzarella wrote:
> On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
>> On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
>>> Fix Smatch-detected error:
>>> drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
>>> uninitialized symbol 'value'.
>>> drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
>>> uninitialized symbol 'value'.
>>> drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
>>> uninitialized symbol 'value'.
>>>
>>> Call tpm_buf_read() to populate value but do not check its return
>>> status. If the read fails, value remains uninitialized, causing
>>> undefined behavior when returned or processed.
>>>
>>> Initialize value to zero to ensure a defined return even if
>>> tpm_buf_read() fails, avoiding undefined behavior from using
>>> an uninitialized variable.
>>
>> How does tpm_buf_read() fail?
> 
> If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are 
> effectively returning random stack bytes to the caller.
> Could this be a problem?
> 
> If it is, maybe instead of this patch, we could set `*output` to zero in 
> the error path of tpm_buf_read(). Or return an error from tpm_buf_read() 
> so callers can return 0 or whatever they want.
> 
> Thanks,
> Stefano
> 

Hi Jarkko, Stefano,
Thank you for the review.

I've revisited the issue and updated the implementation of 
tpm_buf_read() to zero out the *output buffer in the error paths, 
instead of initializing the return value in each caller.

static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t 
count, void *output)
{
	off_t next_offset;

	/* Return silently if overflow has already happened. */
	if (buf->flags & TPM_BUF_BOUNDARY_ERROR) {
		memset(output, 0, count);
		return;
	}

	next_offset = *offset + count;
	if (next_offset > buf->length) {
		WARN(1, "tpm_buf: read out of boundary\n");
		buf->flags |= TPM_BUF_BOUNDARY_ERROR;
		memset(output, 0, count);
		return;
	}

	memcpy(output, &buf->data[*offset], count);
	*offset = next_offset;
}

This approach ensures that output is always zeroed when the read fails, 
which avoids returning uninitialized stack values from the helper 
functions like tpm_buf_read_u8(), tpm_buf_read_u16(), and 
tpm_buf_read_u32().

Does this solution look acceptable for the next version of the patch?

Best regards,
Purva Yeshi
Jarkko Sakkinen April 10, 2025, 8:54 a.m. UTC | #4
On Thu, Apr 10, 2025 at 09:51:09AM +0200, Stefano Garzarella wrote:
> On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
> > On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
> > > Fix Smatch-detected error:

Empty line and s/error/issue/.

> > > drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
> > > uninitialized symbol 'value'.
> > > drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
> > > uninitialized symbol 'value'.
> > > drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
> > > uninitialized symbol 'value'.
> > > 
> > > Call tpm_buf_read() to populate value but do not check its return
> > > status. If the read fails, value remains uninitialized, causing
> > > undefined behavior when returned or processed.
> > > 
> > > Initialize value to zero to ensure a defined return even if
> > > tpm_buf_read() fails, avoiding undefined behavior from using
> > > an uninitialized variable.
> > 
> > How does tpm_buf_read() fail?
> 
> If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are effectively
> returning random stack bytes to the caller.
> Could this be a problem?

It should never happen, if the kernel is working correctly. The commit
message implies a legit failure scenario, which would imply that the
patch is a bug fix, which it actually is not.

"Add a sanity check for boundary overflow, and zero out the value,
if the unexpected happens" is what this patch actually does. I.e.,
code change acceptable, commit message is all wrong.

> 
> If it is, maybe instead of this patch, we could set `*output` to zero in the
> error path of tpm_buf_read(). Or return an error from tpm_buf_read() so
> callers can return 0 or whatever they want.
> 
> Thanks,
> Stefano
> 
> 

BR, Jarkko
Jarkko Sakkinen April 10, 2025, 8:55 a.m. UTC | #5
On Thu, Apr 10, 2025 at 02:12:07PM +0530, Purva Yeshi wrote:
> On 10/04/25 13:21, Stefano Garzarella wrote:
> > On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
> > > On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
> > > > Fix Smatch-detected error:
> > > > drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
> > > > uninitialized symbol 'value'.
> > > > drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
> > > > uninitialized symbol 'value'.
> > > > drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
> > > > uninitialized symbol 'value'.
> > > > 
> > > > Call tpm_buf_read() to populate value but do not check its return
> > > > status. If the read fails, value remains uninitialized, causing
> > > > undefined behavior when returned or processed.
> > > > 
> > > > Initialize value to zero to ensure a defined return even if
> > > > tpm_buf_read() fails, avoiding undefined behavior from using
> > > > an uninitialized variable.
> > > 
> > > How does tpm_buf_read() fail?
> > 
> > If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are
> > effectively returning random stack bytes to the caller.
> > Could this be a problem?
> > 
> > If it is, maybe instead of this patch, we could set `*output` to zero in
> > the error path of tpm_buf_read(). Or return an error from tpm_buf_read()
> > so callers can return 0 or whatever they want.
> > 
> > Thanks,
> > Stefano
> > 
> 
> Hi Jarkko, Stefano,
> Thank you for the review.
> 
> I've revisited the issue and updated the implementation of tpm_buf_read() to
> zero out the *output buffer in the error paths, instead of initializing the
> return value in each caller.
> 
> static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count,
> void *output)
> {
> 	off_t next_offset;
> 
> 	/* Return silently if overflow has already happened. */
> 	if (buf->flags & TPM_BUF_BOUNDARY_ERROR) {
> 		memset(output, 0, count);
> 		return;
> 	}
> 
> 	next_offset = *offset + count;
> 	if (next_offset > buf->length) {
> 		WARN(1, "tpm_buf: read out of boundary\n");
> 		buf->flags |= TPM_BUF_BOUNDARY_ERROR;
> 		memset(output, 0, count);
> 		return;
> 	}
> 
> 	memcpy(output, &buf->data[*offset], count);
> 	*offset = next_offset;
> }

Please don't touch this.

> 
> This approach ensures that output is always zeroed when the read fails,
> which avoids returning uninitialized stack values from the helper functions
> like tpm_buf_read_u8(), tpm_buf_read_u16(), and tpm_buf_read_u32().
> 
> Does this solution look acceptable for the next version of the patch?
> 
> Best regards,
> Purva Yeshi

BR, Jarkko
Jarkko Sakkinen April 10, 2025, 8:57 a.m. UTC | #6
On Thu, Apr 10, 2025 at 11:55:22AM +0300, Jarkko Sakkinen wrote:
> On Thu, Apr 10, 2025 at 02:12:07PM +0530, Purva Yeshi wrote:
> > On 10/04/25 13:21, Stefano Garzarella wrote:
> > > On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
> > > > On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
> > > > > Fix Smatch-detected error:
> > > > > drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
> > > > > uninitialized symbol 'value'.
> > > > > drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
> > > > > uninitialized symbol 'value'.
> > > > > drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
> > > > > uninitialized symbol 'value'.
> > > > > 
> > > > > Call tpm_buf_read() to populate value but do not check its return
> > > > > status. If the read fails, value remains uninitialized, causing
> > > > > undefined behavior when returned or processed.
> > > > > 
> > > > > Initialize value to zero to ensure a defined return even if
> > > > > tpm_buf_read() fails, avoiding undefined behavior from using
> > > > > an uninitialized variable.
> > > > 
> > > > How does tpm_buf_read() fail?
> > > 
> > > If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are
> > > effectively returning random stack bytes to the caller.
> > > Could this be a problem?
> > > 
> > > If it is, maybe instead of this patch, we could set `*output` to zero in
> > > the error path of tpm_buf_read(). Or return an error from tpm_buf_read()
> > > so callers can return 0 or whatever they want.
> > > 
> > > Thanks,
> > > Stefano
> > > 
> > 
> > Hi Jarkko, Stefano,
> > Thank you for the review.
> > 
> > I've revisited the issue and updated the implementation of tpm_buf_read() to
> > zero out the *output buffer in the error paths, instead of initializing the
> > return value in each caller.
> > 
> > static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count,
> > void *output)
> > {
> > 	off_t next_offset;
> > 
> > 	/* Return silently if overflow has already happened. */
> > 	if (buf->flags & TPM_BUF_BOUNDARY_ERROR) {
> > 		memset(output, 0, count);
> > 		return;
> > 	}
> > 
> > 	next_offset = *offset + count;
> > 	if (next_offset > buf->length) {
> > 		WARN(1, "tpm_buf: read out of boundary\n");
> > 		buf->flags |= TPM_BUF_BOUNDARY_ERROR;
> > 		memset(output, 0, count);
> > 		return;
> > 	}
> > 
> > 	memcpy(output, &buf->data[*offset], count);
> > 	*offset = next_offset;
> > }
> 
> Please don't touch this.

If you want to do anything, check the call sites for raw tpm_buf_read()
instead, which is not very common.

BR, Jarkko
Purva Yeshi April 10, 2025, 9:44 a.m. UTC | #7
On 10/04/25 14:24, Jarkko Sakkinen wrote:
> On Thu, Apr 10, 2025 at 09:51:09AM +0200, Stefano Garzarella wrote:
>> On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
>>> On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
>>>> Fix Smatch-detected error:
> 
> Empty line and s/error/issue/.
> 
>>>> drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
>>>> uninitialized symbol 'value'.
>>>> drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
>>>> uninitialized symbol 'value'.
>>>> drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
>>>> uninitialized symbol 'value'.
>>>>
>>>> Call tpm_buf_read() to populate value but do not check its return
>>>> status. If the read fails, value remains uninitialized, causing
>>>> undefined behavior when returned or processed.
>>>>
>>>> Initialize value to zero to ensure a defined return even if
>>>> tpm_buf_read() fails, avoiding undefined behavior from using
>>>> an uninitialized variable.
>>>
>>> How does tpm_buf_read() fail?
>>
>> If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are effectively
>> returning random stack bytes to the caller.
>> Could this be a problem?
> 
> It should never happen, if the kernel is working correctly. The commit
> message implies a legit failure scenario, which would imply that the
> patch is a bug fix, which it actually is not.
> 
> "Add a sanity check for boundary overflow, and zero out the value,
> if the unexpected happens" is what this patch actually does. I.e.,
> code change acceptable, commit message is all wrong.

Understood now. I’ll update the commit message to clearly state this is 
a sanity check for unexpected boundary overflows. Thanks for the 
clarification!

> 
>>
>> If it is, maybe instead of this patch, we could set `*output` to zero in the
>> error path of tpm_buf_read(). Or return an error from tpm_buf_read() so
>> callers can return 0 or whatever they want.
>>
>> Thanks,
>> Stefano
>>
>>
> 
> BR, Jarkko
Purva Yeshi April 10, 2025, 9:46 a.m. UTC | #8
On 10/04/25 14:25, Jarkko Sakkinen wrote:
> On Thu, Apr 10, 2025 at 02:12:07PM +0530, Purva Yeshi wrote:
>> On 10/04/25 13:21, Stefano Garzarella wrote:
>>> On Thu, Apr 10, 2025 at 09:14:58AM +0300, Jarkko Sakkinen wrote:
>>>> On Thu, Apr 10, 2025 at 02:25:36AM +0530, Purva Yeshi wrote:
>>>>> Fix Smatch-detected error:
>>>>> drivers/char/tpm/tpm-buf.c:208 tpm_buf_read_u8() error:
>>>>> uninitialized symbol 'value'.
>>>>> drivers/char/tpm/tpm-buf.c:225 tpm_buf_read_u16() error:
>>>>> uninitialized symbol 'value'.
>>>>> drivers/char/tpm/tpm-buf.c:242 tpm_buf_read_u32() error:
>>>>> uninitialized symbol 'value'.
>>>>>
>>>>> Call tpm_buf_read() to populate value but do not check its return
>>>>> status. If the read fails, value remains uninitialized, causing
>>>>> undefined behavior when returned or processed.
>>>>>
>>>>> Initialize value to zero to ensure a defined return even if
>>>>> tpm_buf_read() fails, avoiding undefined behavior from using
>>>>> an uninitialized variable.
>>>>
>>>> How does tpm_buf_read() fail?
>>>
>>> If TPM_BUF_BOUNDARY_ERROR is set (or we are setting it), we are
>>> effectively returning random stack bytes to the caller.
>>> Could this be a problem?
>>>
>>> If it is, maybe instead of this patch, we could set `*output` to zero in
>>> the error path of tpm_buf_read(). Or return an error from tpm_buf_read()
>>> so callers can return 0 or whatever they want.
>>>
>>> Thanks,
>>> Stefano
>>>
>>
>> Hi Jarkko, Stefano,
>> Thank you for the review.
>>
>> I've revisited the issue and updated the implementation of tpm_buf_read() to
>> zero out the *output buffer in the error paths, instead of initializing the
>> return value in each caller.
>>
>> static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count,
>> void *output)
>> {
>> 	off_t next_offset;
>>
>> 	/* Return silently if overflow has already happened. */
>> 	if (buf->flags & TPM_BUF_BOUNDARY_ERROR) {
>> 		memset(output, 0, count);
>> 		return;
>> 	}
>>
>> 	next_offset = *offset + count;
>> 	if (next_offset > buf->length) {
>> 		WARN(1, "tpm_buf: read out of boundary\n");
>> 		buf->flags |= TPM_BUF_BOUNDARY_ERROR;
>> 		memset(output, 0, count);
>> 		return;
>> 	}
>>
>> 	memcpy(output, &buf->data[*offset], count);
>> 	*offset = next_offset;
>> }
> 
> Please don't touch this.

Got it, thanks!

> 
>>
>> This approach ensures that output is always zeroed when the read fails,
>> which avoids returning uninitialized stack values from the helper functions
>> like tpm_buf_read_u8(), tpm_buf_read_u16(), and tpm_buf_read_u32().
>>
>> Does this solution look acceptable for the next version of the patch?
>>
>> Best regards,
>> Purva Yeshi
> 
> BR, Jarkko
diff mbox series

Patch

diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index e49a19fea3bd..dc882fc9fa9e 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -201,7 +201,7 @@  static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count, void
  */
 u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset)
 {
-	u8 value;
+	u8 value = 0;
 
 	tpm_buf_read(buf, offset, sizeof(value), &value);
 
@@ -218,7 +218,7 @@  EXPORT_SYMBOL_GPL(tpm_buf_read_u8);
  */
 u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset)
 {
-	u16 value;
+	u16 value = 0;
 
 	tpm_buf_read(buf, offset, sizeof(value), &value);
 
@@ -235,7 +235,7 @@  EXPORT_SYMBOL_GPL(tpm_buf_read_u16);
  */
 u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
 {
-	u32 value;
+	u32 value = 0;
 
 	tpm_buf_read(buf, offset, sizeof(value), &value);