linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot()
@ 2025-07-22 13:11 Seyediman Seyedarab
  2025-07-22 17:58 ` Will Deacon
  0 siblings, 1 reply; 5+ messages in thread
From: Seyediman Seyedarab @ 2025-07-22 13:11 UTC (permalink / raw)
  To: dwmw2, baolu.lu, joro, will, robin.murphy
  Cc: skhan, linux-kernel-mentees, iommu, linux-kernel,
	Seyediman Seyedarab

snprintf returns the number of bytes that would have been written,
not the number actually written to the buffer. When accumulating
the byte count with the return value of snprintf, this can cause
the offset to exceed the actual buffer size if truncation occurs.

The byte count is passed to seq_puts() in latency_show_one() with-
out checking for truncation.

Replace snprintf with scnprintf, ensuring the buffer offset stays
within bound.

Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
---
 drivers/iommu/intel/perf.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel/perf.c b/drivers/iommu/intel/perf.c
index adc4de6bb..cee4821f4 100644
--- a/drivers/iommu/intel/perf.c
+++ b/drivers/iommu/intel/perf.c
@@ -122,7 +122,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
 	memset(str, 0, size);
 
 	for (i = 0; i < COUNTS_NUM; i++)
-		bytes += snprintf(str + bytes, size - bytes,
+		bytes += scnprintf(str + bytes, size - bytes,
 				  "%s", latency_counter_names[i]);
 
 	spin_lock_irqsave(&latency_lock, flags);
@@ -130,7 +130,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
 		if (!dmar_latency_enabled(iommu, i))
 			continue;
 
-		bytes += snprintf(str + bytes, size - bytes,
+		bytes += scnprintf(str + bytes, size - bytes,
 				  "\n%s", latency_type_names[i]);
 
 		for (j = 0; j < COUNTS_NUM; j++) {
@@ -156,7 +156,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
 				break;
 			}
 
-			bytes += snprintf(str + bytes, size - bytes,
+			bytes += scnprintf(str + bytes, size - bytes,
 					  "%12lld", val);
 		}
 	}
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot()
  2025-07-22 13:11 [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot() Seyediman Seyedarab
@ 2025-07-22 17:58 ` Will Deacon
  2025-07-23  8:28   ` Seyediman Seyedarab
  0 siblings, 1 reply; 5+ messages in thread
From: Will Deacon @ 2025-07-22 17:58 UTC (permalink / raw)
  To: Seyediman Seyedarab
  Cc: dwmw2, baolu.lu, joro, robin.murphy, skhan, linux-kernel-mentees,
	iommu, linux-kernel

On Tue, Jul 22, 2025 at 09:11:17AM -0400, Seyediman Seyedarab wrote:
> snprintf returns the number of bytes that would have been written,
> not the number actually written to the buffer. When accumulating
> the byte count with the return value of snprintf, this can cause
> the offset to exceed the actual buffer size if truncation occurs.
> 
> The byte count is passed to seq_puts() in latency_show_one() with-
> out checking for truncation.
> 
> Replace snprintf with scnprintf, ensuring the buffer offset stays
> within bound.
> 
> Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> ---
>  drivers/iommu/intel/perf.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iommu/intel/perf.c b/drivers/iommu/intel/perf.c
> index adc4de6bb..cee4821f4 100644
> --- a/drivers/iommu/intel/perf.c
> +++ b/drivers/iommu/intel/perf.c
> @@ -122,7 +122,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
>  	memset(str, 0, size);
>  
>  	for (i = 0; i < COUNTS_NUM; i++)
> -		bytes += snprintf(str + bytes, size - bytes,
> +		bytes += scnprintf(str + bytes, size - bytes,
>  				  "%s", latency_counter_names[i]);
>  
>  	spin_lock_irqsave(&latency_lock, flags);
> @@ -130,7 +130,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
>  		if (!dmar_latency_enabled(iommu, i))
>  			continue;
>  
> -		bytes += snprintf(str + bytes, size - bytes,
> +		bytes += scnprintf(str + bytes, size - bytes,
>  				  "\n%s", latency_type_names[i]);
>  
>  		for (j = 0; j < COUNTS_NUM; j++) {
> @@ -156,7 +156,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
>  				break;
>  			}
>  
> -			bytes += snprintf(str + bytes, size - bytes,
> +			bytes += scnprintf(str + bytes, size - bytes,
>  					  "%12lld", val);

Should the check of the return value in latency_show_one() also be
adjusted so that 'ret <= 0' is an error? I couldn't convince myself
that the string in 'debug_buf' is always null-terminated if ret == 0.

Will

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot()
  2025-07-22 17:58 ` Will Deacon
@ 2025-07-23  8:28   ` Seyediman Seyedarab
  2025-07-23 11:56     ` Will Deacon
  0 siblings, 1 reply; 5+ messages in thread
From: Seyediman Seyedarab @ 2025-07-23  8:28 UTC (permalink / raw)
  To: Will Deacon
  Cc: dwmw2, baolu.lu, joro, robin.murphy, skhan, linux-kernel-mentees,
	iommu, linux-kernel

On 25/07/22 06:58PM, Will Deacon wrote:
> On Tue, Jul 22, 2025 at 09:11:17AM -0400, Seyediman Seyedarab wrote:
> > snprintf returns the number of bytes that would have been written,
> > not the number actually written to the buffer. When accumulating
> > the byte count with the return value of snprintf, this can cause
> > the offset to exceed the actual buffer size if truncation occurs.
> > 
> > The byte count is passed to seq_puts() in latency_show_one() with-
> > out checking for truncation.
> > 
> > Replace snprintf with scnprintf, ensuring the buffer offset stays
> > within bound.
> > 
> > Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> > ---
> >  drivers/iommu/intel/perf.c | 6 +++---
> >  1 file changed, 3 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/iommu/intel/perf.c b/drivers/iommu/intel/perf.c
> > index adc4de6bb..cee4821f4 100644
> > --- a/drivers/iommu/intel/perf.c
> > +++ b/drivers/iommu/intel/perf.c
> > @@ -122,7 +122,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
> >  	memset(str, 0, size);
> >  
> >  	for (i = 0; i < COUNTS_NUM; i++)
> > -		bytes += snprintf(str + bytes, size - bytes,
> > +		bytes += scnprintf(str + bytes, size - bytes,
> >  				  "%s", latency_counter_names[i]);
> >  
> >  	spin_lock_irqsave(&latency_lock, flags);
> > @@ -130,7 +130,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
> >  		if (!dmar_latency_enabled(iommu, i))
> >  			continue;
> >  
> > -		bytes += snprintf(str + bytes, size - bytes,
> > +		bytes += scnprintf(str + bytes, size - bytes,
> >  				  "\n%s", latency_type_names[i]);
> >  
> >  		for (j = 0; j < COUNTS_NUM; j++) {
> > @@ -156,7 +156,7 @@ int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
> >  				break;
> >  			}
> >  
> > -			bytes += snprintf(str + bytes, size - bytes,
> > +			bytes += scnprintf(str + bytes, size - bytes,
> >  					  "%12lld", val);
> 
> Should the check of the return value in latency_show_one() also be
> adjusted so that 'ret <= 0' is an error? I couldn't convince myself
> that the string in 'debug_buf' is always null-terminated if ret == 0.
> 
> Will

IMO, that's not necessary. 'bytes' can't be less than zero that's
for sure (AFAIK, scnprintf() doesn't have any case where it returns
a negative number).
As for being zero, in every scnprintf() call, 'size - bytes' would
have to be == 0. (or size > INT_MAX, but still you get zero, not a
negative number as an error)

In latency_show_one(), the 'size' is DEBUG_BUFFER_SIZE, and
'bytes' in the first run is 0. So, 'size - bytes' == DEBUG_BUFFER_SIZE.
Since 'latency_counter_names' and 'latency_type_names' are arrays of
string literals, 'bytes' is guaranteed to be increased in the first
iteration, even if the rest become zero (which won't happen, since
they are smaller than DEBUG_BUFFER_SIZE).

So, the case of zero is impossible, unless you want a bulletproof
check for future implementations where the function might be rewritten.

Seyediman

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot()
  2025-07-23  8:28   ` Seyediman Seyedarab
@ 2025-07-23 11:56     ` Will Deacon
  2025-07-23 12:18       ` Seyediman Seyedarab
  0 siblings, 1 reply; 5+ messages in thread
From: Will Deacon @ 2025-07-23 11:56 UTC (permalink / raw)
  To: Seyediman Seyedarab
  Cc: dwmw2, baolu.lu, joro, robin.murphy, skhan, linux-kernel-mentees,
	iommu, linux-kernel

On Wed, Jul 23, 2025 at 04:28:54AM -0400, Seyediman Seyedarab wrote:
> On 25/07/22 06:58PM, Will Deacon wrote:
> > On Tue, Jul 22, 2025 at 09:11:17AM -0400, Seyediman Seyedarab wrote:
> > > snprintf returns the number of bytes that would have been written,
> > > not the number actually written to the buffer. When accumulating
> > > the byte count with the return value of snprintf, this can cause
> > > the offset to exceed the actual buffer size if truncation occurs.
> > > 
> > > The byte count is passed to seq_puts() in latency_show_one() with-
> > > out checking for truncation.
> > > 
> > > Replace snprintf with scnprintf, ensuring the buffer offset stays
> > > within bound.
> > > 
> > > Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> > > ---
> > >  drivers/iommu/intel/perf.c | 6 +++---
> > >  1 file changed, 3 insertions(+), 3 deletions(-)

[...]

> > Should the check of the return value in latency_show_one() also be
> > adjusted so that 'ret <= 0' is an error? I couldn't convince myself
> > that the string in 'debug_buf' is always null-terminated if ret == 0.
> > 
> IMO, that's not necessary. 'bytes' can't be less than zero that's
> for sure (AFAIK, scnprintf() doesn't have any case where it returns
> a negative number).
> As for being zero, in every scnprintf() call, 'size - bytes' would
> have to be == 0. (or size > INT_MAX, but still you get zero, not a
> negative number as an error)
> 
> In latency_show_one(), the 'size' is DEBUG_BUFFER_SIZE, and
> 'bytes' in the first run is 0. So, 'size - bytes' == DEBUG_BUFFER_SIZE.
> Since 'latency_counter_names' and 'latency_type_names' are arrays of
> string literals, 'bytes' is guaranteed to be increased in the first
> iteration, even if the rest become zero (which won't happen, since
> they are smaller than DEBUG_BUFFER_SIZE).
> 
> So, the case of zero is impossible, unless you want a bulletproof
> check for future implementations where the function might be rewritten.

Thanks, so that sounds like the error check in latency_show_one() is dead
code in which case dmar_latency_snapshot() should just have a return type
of 'void'?

Will

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot()
  2025-07-23 11:56     ` Will Deacon
@ 2025-07-23 12:18       ` Seyediman Seyedarab
  0 siblings, 0 replies; 5+ messages in thread
From: Seyediman Seyedarab @ 2025-07-23 12:18 UTC (permalink / raw)
  To: Will Deacon
  Cc: dwmw2, baolu.lu, joro, robin.murphy, skhan, linux-kernel-mentees,
	iommu, linux-kernel

On 25/07/23 12:56PM, Will Deacon wrote:
> On Wed, Jul 23, 2025 at 04:28:54AM -0400, Seyediman Seyedarab wrote:
> > On 25/07/22 06:58PM, Will Deacon wrote:
> > > On Tue, Jul 22, 2025 at 09:11:17AM -0400, Seyediman Seyedarab wrote:
> > > > snprintf returns the number of bytes that would have been written,
> > > > not the number actually written to the buffer. When accumulating
> > > > the byte count with the return value of snprintf, this can cause
> > > > the offset to exceed the actual buffer size if truncation occurs.
> > > > 
> > > > The byte count is passed to seq_puts() in latency_show_one() with-
> > > > out checking for truncation.
> > > > 
> > > > Replace snprintf with scnprintf, ensuring the buffer offset stays
> > > > within bound.
> > > > 
> > > > Signed-off-by: Seyediman Seyedarab <ImanDevel@gmail.com>
> > > > ---
> > > >  drivers/iommu/intel/perf.c | 6 +++---
> > > >  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> [...]
> 
> > > Should the check of the return value in latency_show_one() also be
> > > adjusted so that 'ret <= 0' is an error? I couldn't convince myself
> > > that the string in 'debug_buf' is always null-terminated if ret == 0.
> > > 
> > IMO, that's not necessary. 'bytes' can't be less than zero that's
> > for sure (AFAIK, scnprintf() doesn't have any case where it returns
> > a negative number).
> > As for being zero, in every scnprintf() call, 'size - bytes' would
> > have to be == 0. (or size > INT_MAX, but still you get zero, not a
> > negative number as an error)
> > 
> > In latency_show_one(), the 'size' is DEBUG_BUFFER_SIZE, and
> > 'bytes' in the first run is 0. So, 'size - bytes' == DEBUG_BUFFER_SIZE.
> > Since 'latency_counter_names' and 'latency_type_names' are arrays of
> > string literals, 'bytes' is guaranteed to be increased in the first
> > iteration, even if the rest become zero (which won't happen, since
> > they are smaller than DEBUG_BUFFER_SIZE).
> > 
> > So, the case of zero is impossible, unless you want a bulletproof
> > check for future implementations where the function might be rewritten.
> 
> Thanks, so that sounds like the error check in latency_show_one() is dead
> code in which case dmar_latency_snapshot() should just have a return type
> of 'void'?
> 
> Will

Well, there’s only one case where dmar_latency_snapshot() could go
wrong and return a negative number, and that's due to integer overflow.
It seems unlikely and probably out of reach, but increasing the number
of string literals might trigger it. So, I wouldn't say it's entirely
dead code. We can change it to 'if (unlikely(ret < 0))', or if it's
too out of reach I can send another patch to remove it and change
dmar_latency_snapshot()'s return type to void. (or a v2 including
both changes)

Seyediman

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-07-23 12:13 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-22 13:11 [PATCH] iommu/vt-d: replace snprintf with scnprintf in dmar_latency_snapshot() Seyediman Seyedarab
2025-07-22 17:58 ` Will Deacon
2025-07-23  8:28   ` Seyediman Seyedarab
2025-07-23 11:56     ` Will Deacon
2025-07-23 12:18       ` Seyediman Seyedarab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).