linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] perf branch: Fix heap out-of-bounds write in branch_type_count()
       [not found] <20250809093812.308027-1-yujundong@pascal-lab.net>
@ 2025-08-11  7:03 ` Anshuman Khandual
  2025-08-12  7:31   ` Yujun Dong
  0 siblings, 1 reply; 3+ messages in thread
From: Anshuman Khandual @ 2025-08-11  7:03 UTC (permalink / raw)
  To: Yujun Dong, linux-perf-users
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Ian Rogers, Adrian Hunter, Liang, Kan, linux-kernel



On 09/08/25 3:08 PM, Yujun Dong wrote:
> The branch_type_count() function writes to st->new_counts[flags->new_type]
> when flags->type is PERF_BR_EXTEND_ABI. However, while the array
> st->new_counts is sized for PERF_BR_NEW_MAX (8) entries, the field
> flags->new_type is a 4-bit unsigned value and may hold values up to 15.
> 
> This mismatch allows crafted perf data to trigger a heap out-of-bounds
> write when flags->new_type >= 8, leading to memory corruption.

Crafted ? How could flags->new_type >= 8 when PERF_BR_NEW_MAX is capped at 8.
Is this a real scenario that happened on a system ?

> 
> Add a bounds check to ensure flags->new_type is less than
> PERF_BR_NEW_MAX before accessing the new_counts array.

But it might make sense to add this check just to be on the safer side.

> 
> Fixes: 0ddea8e2a0c2 ("perf branch: Extend branch type classification")
> Signed-off-by: Yujun Dong <yujundong@pascal-lab.net>
> ---
>  tools/perf/util/branch.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c
> index 3712be067464..8ea6628c7735 100644
> --- a/tools/perf/util/branch.c
> +++ b/tools/perf/util/branch.c
> @@ -21,10 +21,12 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
>  	if (flags->type == PERF_BR_UNKNOWN || from == 0)
>  		return;
>  
> -	if (flags->type == PERF_BR_EXTEND_ABI)
> -		st->new_counts[flags->new_type]++;
> -	else
> +	if (flags->type == PERF_BR_EXTEND_ABI) {
> +		if (flags->new_type < PERF_BR_NEW_MAX)
> +			st->new_counts[flags->new_type]++;
> +	} else {
>  		st->counts[flags->type]++;
> +	}
>  
>  	if (flags->type == PERF_BR_COND) {
>  		if (to > from)



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

* Re: [PATCH] perf branch: Fix heap out-of-bounds write in branch_type_count()
  2025-08-11  7:03 ` [PATCH] perf branch: Fix heap out-of-bounds write in branch_type_count() Anshuman Khandual
@ 2025-08-12  7:31   ` Yujun Dong
  2025-08-13 14:20     ` Anshuman Khandual
  0 siblings, 1 reply; 3+ messages in thread
From: Yujun Dong @ 2025-08-12  7:31 UTC (permalink / raw)
  To: Anshuman Khandual, linux-perf-users
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Ian Rogers, Adrian Hunter, Liang, Kan, linux-kernel

On 2025/8/11 15:03, Anshuman Khandual wrote:
 > On 09/08/25 3:08 PM, Yujun Dong wrote:
 > > The branch_type_count() function writes to 
st->new_counts[flags->new_type]
 > > when flags->type is PERF_BR_EXTEND_ABI. However, while the array
 > > st->new_counts is sized for PERF_BR_NEW_MAX (8) entries, the field
 > > flags->new_type is a 4-bit unsigned value and may hold values up to 15.
 > >
 > > This mismatch allows crafted perf data to trigger a heap out-of-bounds
 > > write when flags->new_type >= 8, leading to memory corruption.
 >
 > Crafted ? How could flags->new_type >= 8 when PERF_BR_NEW_MAX is 
capped at 8.
 > Is this a real scenario that happened on a system ?
 >

Thanks for your review and for raising that question. The new_type field
in struct branch_flags is declared as a 4-bit bitfield (u64 new_type:4),
meaning it can hold values from 0 to 15, even though PERF_BR_NEW_MAX is
defined as 8. So, it's entirely possible for flags->new_type to be >= 8.

In fact, I've observed such cases when running real-world perf record/top,
where perf.data produced contains invalid new_type values, likely due to
other bugs or unexpected data corruption. Additionally, a maliciously
crafted perf.data file can also force this out-of-bounds write.

 > >
 > > Add a bounds check to ensure flags->new_type is less than
 > > PERF_BR_NEW_MAX before accessing the new_counts array.
 >
 > But it might make sense to add this check just to be on the safer side.
 >

Notably, new_type is only used in two places:
1. In branch_new_type_name(), where the bounds are already validated.
2. In branch_type_count(), where the current patch now adds the
necessary check.

Admittedly, the mismatch between the bit-field width (0-15) and
PERF_BR_NEW_MAX (8) is the root cause. While adjusting the bit-field
to match PERF_BR_NEW_MAX would also resolve the mismatch, that risks
breaking existing compatibility. Therefore, adding a bounds check at
the use site is the least disruptive correction.

 > >
 > > Fixes: 0ddea8e2a0c2 ("perf branch: Extend branch type classification")
 > > Signed-off-by: Yujun Dong <yujundong@pascal-lab.net>
 > > ---
 > >  tools/perf/util/branch.c | 8 +++++---
 > >  1 file changed, 5 insertions(+), 3 deletions(-)
 > >
 > > diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c
 > > index 3712be067464..8ea6628c7735 100644
 > > --- a/tools/perf/util/branch.c
 > > +++ b/tools/perf/util/branch.c
 > > @@ -21,10 +21,12 @@ void branch_type_count(struct branch_type_stat 
*st, struct branch_flags *flags,
 > >      if (flags->type == PERF_BR_UNKNOWN || from == 0)
 > >          return;
 > >
 > > -    if (flags->type == PERF_BR_EXTEND_ABI)
 > > -        st->new_counts[flags->new_type]++;
 > > -    else
 > > +    if (flags->type == PERF_BR_EXTEND_ABI) {
 > > +        if (flags->new_type < PERF_BR_NEW_MAX)
 > > +            st->new_counts[flags->new_type]++;
 > > +    } else {
 > >          st->counts[flags->type]++;
 > > +    }
 > >
 > >      if (flags->type == PERF_BR_COND) {
 > >          if (to > from)
 >

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

* Re: [PATCH] perf branch: Fix heap out-of-bounds write in branch_type_count()
  2025-08-12  7:31   ` Yujun Dong
@ 2025-08-13 14:20     ` Anshuman Khandual
  0 siblings, 0 replies; 3+ messages in thread
From: Anshuman Khandual @ 2025-08-13 14:20 UTC (permalink / raw)
  To: Yujun Dong, linux-perf-users
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Ian Rogers, Adrian Hunter, Liang, Kan, linux-kernel



On 12/08/25 1:01 PM, Yujun Dong wrote:
> On 2025/8/11 15:03, Anshuman Khandual wrote:
>> On 09/08/25 3:08 PM, Yujun Dong wrote:
>> > The branch_type_count() function writes to st->new_counts[flags->new_type]
>> > when flags->type is PERF_BR_EXTEND_ABI. However, while the array
>> > st->new_counts is sized for PERF_BR_NEW_MAX (8) entries, the field
>> > flags->new_type is a 4-bit unsigned value and may hold values up to 15.
>> >
>> > This mismatch allows crafted perf data to trigger a heap out-of-bounds
>> > write when flags->new_type >= 8, leading to memory corruption.
>>
>> Crafted ? How could flags->new_type >= 8 when PERF_BR_NEW_MAX is capped at 8.
>> Is this a real scenario that happened on a system ?
>>
> 
> Thanks for your review and for raising that question. The new_type field
> in struct branch_flags is declared as a 4-bit bitfield (u64 new_type:4),
> meaning it can hold values from 0 to 15, even though PERF_BR_NEW_MAX is
> defined as 8. So, it's entirely possible for flags->new_type to be >= 8.

Sure it is possible but not probable I guess as new_type itself would be
first guarded by PERF_BR_NEW_MAX.

> 
> In fact, I've observed such cases when running real-world perf record/top,
> where perf.data produced contains invalid new_type values, likely due to
> other bugs or unexpected data corruption. Additionally, a maliciously
> crafted perf.data file can also force this out-of-bounds write.

Agreed. 

> 
>> >
>> > Add a bounds check to ensure flags->new_type is less than
>> > PERF_BR_NEW_MAX before accessing the new_counts array.
>>
>> But it might make sense to add this check just to be on the safer side.
>>
> 
> Notably, new_type is only used in two places:
> 1. In branch_new_type_name(), where the bounds are already validated.
> 2. In branch_type_count(), where the current patch now adds the
> necessary check.

Agreed - this change will ensure consistency across both the functions.

> 
> Admittedly, the mismatch between the bit-field width (0-15) and
> PERF_BR_NEW_MAX (8) is the root cause. While adjusting the bit-field
> to match PERF_BR_NEW_MAX would also resolve the mismatch, that risks
> breaking existing compatibility. Therefore, adding a bounds check at
> the use site is the least disruptive correction.

Right, increasing PERF_BR_NEW_MAX to 15 will not be desirable.

> 
>> >
>> > Fixes: 0ddea8e2a0c2 ("perf branch: Extend branch type classification")
>> > Signed-off-by: Yujun Dong <yujundong@pascal-lab.net>
>> > ---
>> >  tools/perf/util/branch.c | 8 +++++---
>> >  1 file changed, 5 insertions(+), 3 deletions(-)
>> >
>> > diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c
>> > index 3712be067464..8ea6628c7735 100644
>> > --- a/tools/perf/util/branch.c
>> > +++ b/tools/perf/util/branch.c
>> > @@ -21,10 +21,12 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
>> >      if (flags->type == PERF_BR_UNKNOWN || from == 0)
>> >          return;
>> >
>> > -    if (flags->type == PERF_BR_EXTEND_ABI)
>> > -        st->new_counts[flags->new_type]++;
>> > -    else
>> > +    if (flags->type == PERF_BR_EXTEND_ABI) {
>> > +        if (flags->new_type < PERF_BR_NEW_MAX)
>> > +            st->new_counts[flags->new_type]++;
>> > +    } else {
>> >          st->counts[flags->type]++;
>> > +    }
>> >
>> >      if (flags->type == PERF_BR_COND) {
>> >          if (to > from)
>> >Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>

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

end of thread, other threads:[~2025-08-13 14:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20250809093812.308027-1-yujundong@pascal-lab.net>
2025-08-11  7:03 ` [PATCH] perf branch: Fix heap out-of-bounds write in branch_type_count() Anshuman Khandual
2025-08-12  7:31   ` Yujun Dong
2025-08-13 14:20     ` Anshuman Khandual

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).