Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/perf: Fix crashes with generic_compat_pmu & BHRB

The bhrb_filter_map ("The Branch History Rolling Buffer") callback is
only defined in raw CPUs' power_pmu structs. The "architected" CPUs
use generic_compat_pmu, which does not have this callback, and crashes
occur if a user tries to enable branch stack for an event.

This add a NULL pointer check for bhrb_filter_map() which behaves as
if the callback returned an error.

This does not add the same check for config_bhrb() as the only caller
checks for cpuhw->bhrb_users which remains zero if bhrb_filter_map==0.

Fixes: be80e758d0c2 ("powerpc/perf: Add generic compat mode pmu driver")
Cc: stable@vger.kernel.org # v5.2+
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200602025612.62707-1-aik@ozlabs.ru

authored by

Alexey Kardashevskiy and committed by
Michael Ellerman
b460b512 b91eb518

+14 -5
+14 -5
arch/powerpc/perf/core-book3s.c
··· 1557 1557 ret = 0; 1558 1558 out: 1559 1559 if (has_branch_stack(event)) { 1560 - power_pmu_bhrb_enable(event); 1561 - cpuhw->bhrb_filter = ppmu->bhrb_filter_map( 1562 - event->attr.branch_sample_type); 1560 + u64 bhrb_filter = -1; 1561 + 1562 + if (ppmu->bhrb_filter_map) 1563 + bhrb_filter = ppmu->bhrb_filter_map( 1564 + event->attr.branch_sample_type); 1565 + 1566 + if (bhrb_filter != -1) { 1567 + cpuhw->bhrb_filter = bhrb_filter; 1568 + power_pmu_bhrb_enable(event); 1569 + } 1563 1570 } 1564 1571 1565 1572 perf_pmu_enable(event->pmu); ··· 1888 1881 int n; 1889 1882 int err; 1890 1883 struct cpu_hw_events *cpuhw; 1891 - u64 bhrb_filter; 1892 1884 1893 1885 if (!ppmu) 1894 1886 return -ENOENT; ··· 1993 1987 err = power_check_constraints(cpuhw, events, cflags, n + 1); 1994 1988 1995 1989 if (has_branch_stack(event)) { 1996 - bhrb_filter = ppmu->bhrb_filter_map( 1990 + u64 bhrb_filter = -1; 1991 + 1992 + if (ppmu->bhrb_filter_map) 1993 + bhrb_filter = ppmu->bhrb_filter_map( 1997 1994 event->attr.branch_sample_type); 1998 1995 1999 1996 if (bhrb_filter == -1) {